Initial vibecoded proof of concept
This commit is contained in:
parent
74812459af
commit
461318a656
61 changed files with 13306 additions and 0 deletions
525
lua/notex/ui/view.lua
Normal file
525
lua/notex/ui/view.lua
Normal file
|
@ -0,0 +1,525 @@
|
|||
-- Query result visualization module
|
||||
local M = {}
|
||||
|
||||
local buffer_manager = require('notex.ui.buffer')
|
||||
local utils = require('notex.utils')
|
||||
|
||||
-- View configurations
|
||||
local view_configs = {}
|
||||
|
||||
-- Create query view
|
||||
function M.create_query_view(query_results, options)
|
||||
options = options or {}
|
||||
local view_type = options.view_type or "table"
|
||||
|
||||
local view_config = {
|
||||
view_type = view_type,
|
||||
query_results = query_results,
|
||||
options = options,
|
||||
created_at = os.time()
|
||||
}
|
||||
|
||||
-- Create buffer based on view type
|
||||
if view_type == "table" then
|
||||
return M.create_table_view(query_results, options)
|
||||
elseif view_type == "cards" then
|
||||
return M.create_cards_view(query_results, options)
|
||||
elseif view_type == "list" then
|
||||
return M.create_list_view(query_results, options)
|
||||
elseif view_type == "tree" then
|
||||
return M.create_tree_view(query_results, options)
|
||||
else
|
||||
return M.create_table_view(query_results, options)
|
||||
end
|
||||
end
|
||||
|
||||
-- Create table view
|
||||
function M.create_table_view(query_results, options)
|
||||
local table_options = vim.tbl_deep_extend("force", options, {
|
||||
name = "notex://table-view",
|
||||
view_type = "table",
|
||||
include_properties = M.get_table_properties(query_results),
|
||||
max_width = 120,
|
||||
show_help = true
|
||||
})
|
||||
|
||||
return buffer_manager.create_query_buffer(query_results, table_options)
|
||||
end
|
||||
|
||||
-- Create cards view
|
||||
function M.create_cards_view(query_results, options)
|
||||
local cards_options = vim.tbl_deep_extend("force", options, {
|
||||
name = "notex://cards-view",
|
||||
view_type = "cards",
|
||||
show_help = true,
|
||||
wrap = true
|
||||
})
|
||||
|
||||
local buffer_id = vim.api.nvim_create_buf(false, true)
|
||||
buffer_manager.setup_buffer_options(buffer_id, cards_options)
|
||||
|
||||
local lines = M.generate_cards_content(query_results, cards_options)
|
||||
vim.api.nvim_buf_set_lines(buffer_id, 0, -1, false, lines)
|
||||
|
||||
local window_id = buffer_manager.create_query_window(buffer_id, cards_options)
|
||||
|
||||
local config = {
|
||||
buffer_id = buffer_id,
|
||||
window_id = window_id,
|
||||
query_results = query_results,
|
||||
options = cards_options,
|
||||
created_at = os.time(),
|
||||
mappings = buffer_manager.setup_buffer_mappings(buffer_id, cards_options)
|
||||
}
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
-- Create list view
|
||||
function M.create_list_view(query_results, options)
|
||||
local list_options = vim.tbl_deep_extend("force", options, {
|
||||
name = "notex://list-view",
|
||||
view_type = "list",
|
||||
show_help = true
|
||||
})
|
||||
|
||||
local buffer_id = vim.api.nvim_create_buf(false, true)
|
||||
buffer_manager.setup_buffer_options(buffer_id, list_options)
|
||||
|
||||
local lines = M.generate_list_content(query_results, list_options)
|
||||
vim.api.nvim_buf_set_lines(buffer_id, 0, -1, false, lines)
|
||||
|
||||
local window_id = buffer_manager.create_query_window(buffer_id, list_options)
|
||||
|
||||
local config = {
|
||||
buffer_id = buffer_id,
|
||||
window_id = window_id,
|
||||
query_results = query_results,
|
||||
options = list_options,
|
||||
created_at = os.time(),
|
||||
mappings = buffer_manager.setup_buffer_mappings(buffer_id, list_options)
|
||||
}
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
-- Create tree view
|
||||
function M.create_tree_view(query_results, options)
|
||||
local tree_options = vim.tbl_deep_extend("force", options, {
|
||||
name = "notex://tree-view",
|
||||
view_type = "tree",
|
||||
group_by = options.group_by or "status",
|
||||
show_help = true
|
||||
})
|
||||
|
||||
local buffer_id = vim.api.nvim_create_buf(false, true)
|
||||
buffer_manager.setup_buffer_options(buffer_id, tree_options)
|
||||
|
||||
local lines = M.generate_tree_content(query_results, tree_options)
|
||||
vim.api.nvim_buf_set_lines(buffer_id, 0, -1, false, lines)
|
||||
|
||||
local window_id = buffer_manager.create_query_window(buffer_id, tree_options)
|
||||
|
||||
local config = {
|
||||
buffer_id = buffer_id,
|
||||
window_id = window_id,
|
||||
query_results = query_results,
|
||||
options = tree_options,
|
||||
created_at = os.time(),
|
||||
mappings = buffer_manager.setup_buffer_mappings(buffer_id, tree_options)
|
||||
}
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
-- Get table properties
|
||||
function M.get_table_properties(query_results)
|
||||
if not query_results.documents or #query_results.documents == 0 then
|
||||
return {"title", "status", "priority"}
|
||||
end
|
||||
|
||||
-- Find most common properties
|
||||
local property_counts = {}
|
||||
|
||||
for _, doc in ipairs(query_results.documents) do
|
||||
if doc.properties then
|
||||
for prop, _ in pairs(doc.properties) do
|
||||
property_counts[prop] = (property_counts[prop] or 0) + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Sort by frequency
|
||||
local sorted_props = {}
|
||||
for prop, count in pairs(property_counts) do
|
||||
table.insert(sorted_props, {property = prop, count = count})
|
||||
end
|
||||
|
||||
table.sort(sorted_props, function(a, b) return a.count > b.count end)
|
||||
|
||||
-- Return top properties
|
||||
local result = {}
|
||||
for i, item in ipairs(sorted_props) do
|
||||
if i > 6 then break end -- Limit to 6 columns
|
||||
table.insert(result, item.property)
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Generate cards content
|
||||
function M.generate_cards_content(query_results, options)
|
||||
local lines = {}
|
||||
|
||||
-- Header
|
||||
table.insert(lines, "Query Results - Card View")
|
||||
table.insert(lines, string.rep("=", 50))
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Query info
|
||||
if query_results.query_string then
|
||||
table.insert(lines, "Query: " .. query_results.query_string)
|
||||
table.insert(lines, "")
|
||||
end
|
||||
|
||||
table.insert(lines, string.format("Found %d documents (%.2fms)",
|
||||
query_results.total_count or 0,
|
||||
query_results.execution_time_ms or 0))
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Document cards
|
||||
if query_results.documents and #query_results.documents > 0 then
|
||||
for i, doc in ipairs(query_results.documents) do
|
||||
lines = M.add_document_card(lines, doc, i, options)
|
||||
table.insert(lines, "")
|
||||
end
|
||||
else
|
||||
table.insert(lines, "No documents found.")
|
||||
table.insert(lines, "")
|
||||
end
|
||||
|
||||
-- Help
|
||||
lines = buffer_manager.add_help_section(lines, options)
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
-- Add document card
|
||||
function M.add_document_card(lines, doc, index, options)
|
||||
local max_width = options.max_width or 80
|
||||
|
||||
table.insert(lines, string.format("Document %d: %s", index, doc.properties and doc.properties.title or "Untitled"))
|
||||
table.insert(lines, string.rep("-", max_width))
|
||||
|
||||
-- File path
|
||||
table.insert(lines, "Path: " .. doc.file_path)
|
||||
|
||||
-- Properties
|
||||
if doc.properties then
|
||||
local sorted_props = {}
|
||||
for key, value in pairs(doc.properties) do
|
||||
table.insert(sorted_props, {key = key, value = value})
|
||||
end
|
||||
|
||||
table.sort(sorted_props, function(a, b) return a.key < b.key end)
|
||||
|
||||
for _, prop in ipairs(sorted_props) do
|
||||
if prop.key ~= "title" then
|
||||
local formatted = string.format(" %s: %s", prop.key, tostring(prop.value))
|
||||
if #formatted > max_width - 2 then
|
||||
formatted = formatted:sub(1, max_width - 5) .. "..."
|
||||
end
|
||||
table.insert(lines, formatted)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Metadata
|
||||
table.insert(lines, string.format(" Modified: %s", os.date("%Y-%m-%d %H:%M", doc.updated_at)))
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
-- Generate list content
|
||||
function M.generate_list_content(query_results, options)
|
||||
local lines = {}
|
||||
|
||||
-- Header
|
||||
table.insert(lines, "Query Results - List View")
|
||||
table.insert(lines, string.rep("=", 50))
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Query info
|
||||
table.insert(lines, string.format("%d documents (%.2fms)",
|
||||
query_results.total_count or 0,
|
||||
query_results.execution_time_ms or 0))
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Document list
|
||||
if query_results.documents and #query_results.documents > 0 then
|
||||
for i, doc in ipairs(query_results.documents) do
|
||||
local title = doc.properties and doc.properties.title or vim.fn.fnamemodify(doc.file_path, ":t")
|
||||
local status = doc.properties and doc.properties.status or ""
|
||||
local priority = doc.properties and doc.properties.priority or ""
|
||||
|
||||
local line = string.format("%3d. %-40s %-12s %-8s", i, M.truncate_string(title, 40), status, priority)
|
||||
table.insert(lines, line)
|
||||
end
|
||||
else
|
||||
table.insert(lines, "No documents found.")
|
||||
end
|
||||
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Help
|
||||
lines = buffer_manager.add_help_section(lines, options)
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
-- Generate tree content
|
||||
function M.generate_tree_content(query_results, options)
|
||||
local lines = {}
|
||||
local group_by = options.group_by or "status"
|
||||
|
||||
-- Header
|
||||
table.insert(lines, string.format("Query Results - Tree View (Grouped by %s)", group_by))
|
||||
table.insert(lines, string.rep("=", 50))
|
||||
table.insert(lines, "")
|
||||
|
||||
-- Group documents
|
||||
local groups = M.group_documents(query_results.documents, group_by)
|
||||
|
||||
-- Create tree structure
|
||||
for group_name, group_docs in pairs(groups) do
|
||||
table.insert(lines, string.format("▼ %s (%d)", group_name, #group_docs))
|
||||
|
||||
for i, doc in ipairs(group_docs) do
|
||||
local title = doc.properties and doc.properties.title or vim.fn.fnamemodify(doc.file_path, ":t")
|
||||
local line = string.format(" ├─ %s", title)
|
||||
|
||||
if i == #group_docs then
|
||||
line = string.format(" └─ %s", title)
|
||||
end
|
||||
|
||||
table.insert(lines, line)
|
||||
end
|
||||
|
||||
table.insert(lines, "")
|
||||
end
|
||||
|
||||
-- Help
|
||||
lines = buffer_manager.add_help_section(lines, options)
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
-- Group documents by property
|
||||
function M.group_documents(documents, group_by)
|
||||
local groups = {}
|
||||
|
||||
for _, doc in ipairs(documents) do
|
||||
local group_value = "Unknown"
|
||||
|
||||
if doc.properties and doc.properties[group_by] then
|
||||
group_value = tostring(doc.properties[group_by])
|
||||
end
|
||||
|
||||
if not groups[group_value] then
|
||||
groups[group_value] = {}
|
||||
end
|
||||
|
||||
table.insert(groups[group_value], doc)
|
||||
end
|
||||
|
||||
-- Sort groups
|
||||
local sorted_groups = {}
|
||||
for group_name, group_docs in pairs(groups) do
|
||||
table.insert(sorted_groups, {name = group_name, docs = group_docs})
|
||||
end
|
||||
|
||||
table.sort(sorted_groups, function(a, b) return a.name < b.name end)
|
||||
|
||||
local result = {}
|
||||
for _, group in ipairs(sorted_groups) do
|
||||
result[group.name] = group.docs
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Truncate string
|
||||
function M.truncate_string(str, max_length)
|
||||
if #str <= max_length then
|
||||
return str
|
||||
end
|
||||
|
||||
return str:sub(1, max_length - 3) .. "..."
|
||||
end
|
||||
|
||||
-- Switch view type
|
||||
function M.switch_view_type(buffer_id, new_view_type)
|
||||
local config = require('notex.ui.buffer').get_active_buffers()[buffer_id]
|
||||
if not config then
|
||||
return false, "Buffer not found"
|
||||
end
|
||||
|
||||
-- Close current view
|
||||
if config.window_id then
|
||||
vim.api.nvim_win_close(config.window_id, true)
|
||||
end
|
||||
|
||||
-- Create new view
|
||||
local new_options = vim.tbl_deep_extend("force", config.options, {
|
||||
view_type = new_view_type
|
||||
})
|
||||
|
||||
local new_config = M.create_query_view(config.query_results, new_options)
|
||||
|
||||
if new_config then
|
||||
return true, "View switched to " .. new_view_type
|
||||
else
|
||||
return false, "Failed to create new view"
|
||||
end
|
||||
end
|
||||
|
||||
-- Get available view types
|
||||
function M.get_available_view_types()
|
||||
return {
|
||||
{
|
||||
name = "table",
|
||||
description = "Tabular view with sortable columns",
|
||||
icon = "⊞"
|
||||
},
|
||||
{
|
||||
name = "cards",
|
||||
description = "Card-based view with detailed information",
|
||||
icon = "📄"
|
||||
},
|
||||
{
|
||||
name = "list",
|
||||
description = "Compact list view",
|
||||
icon = "📋"
|
||||
},
|
||||
{
|
||||
name = "tree",
|
||||
description = "Hierarchical view grouped by properties",
|
||||
icon = "🌳"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
-- Export view to different formats
|
||||
function M.export_view(buffer_id, format)
|
||||
local config = require('notex.ui.buffer').get_active_buffers()[buffer_id]
|
||||
if not config then
|
||||
return false, "Buffer not found"
|
||||
end
|
||||
|
||||
format = format or "markdown"
|
||||
|
||||
if format == "markdown" then
|
||||
return M.export_to_markdown(config.query_results, config.options)
|
||||
elseif format == "csv" then
|
||||
return M.export_to_csv(config.query_results, config.options)
|
||||
elseif format == "json" then
|
||||
return M.export_to_json(config.query_results, config.options)
|
||||
else
|
||||
return false, "Unsupported export format: " .. format
|
||||
end
|
||||
end
|
||||
|
||||
-- Export to markdown
|
||||
function M.export_to_markdown(query_results, options)
|
||||
local lines = {}
|
||||
|
||||
table.insert(lines, "# Query Results")
|
||||
table.insert(lines, "")
|
||||
|
||||
if query_results.query_string then
|
||||
table.insert(lines, "## Query")
|
||||
table.insert(lines, "```")
|
||||
table.insert(lines, query_results.query_string)
|
||||
table.insert(lines, "```")
|
||||
table.insert(lines, "")
|
||||
end
|
||||
|
||||
table.insert(lines, string.format("**Found %d documents** (%.2fms)",
|
||||
query_results.total_count or 0,
|
||||
query_results.execution_time_ms or 0))
|
||||
table.insert(lines, "")
|
||||
|
||||
if query_results.documents and #query_results.documents > 0 then
|
||||
table.insert(lines, "## Documents")
|
||||
table.insert(lines, "")
|
||||
|
||||
for i, doc in ipairs(query_results.documents) do
|
||||
table.insert(lines, string.format("### %d. %s", i, doc.properties and doc.properties.title or "Untitled"))
|
||||
table.insert(lines, "")
|
||||
|
||||
table.insert(lines, "**File:** `" .. doc.file_path .. "`")
|
||||
table.insert(lines, "")
|
||||
|
||||
if doc.properties then
|
||||
table.insert(lines, "**Properties:**")
|
||||
for key, value in pairs(doc.properties) do
|
||||
table.insert(lines, string.format("- **%s:** %s", key, tostring(value)))
|
||||
end
|
||||
table.insert(lines, "")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true, table.concat(lines, "\n")
|
||||
end
|
||||
|
||||
-- Export to CSV
|
||||
function M.export_to_csv(query_results, options)
|
||||
local lines = {}
|
||||
|
||||
-- Header
|
||||
local headers = {"#", "File", "Title", "Status", "Priority", "Created", "Modified"}
|
||||
table.insert(lines, table.concat(headers, ","))
|
||||
|
||||
-- Data rows
|
||||
if query_results.documents then
|
||||
for i, doc in ipairs(query_results.documents) do
|
||||
local row = {
|
||||
i,
|
||||
doc.file_path,
|
||||
doc.properties and doc.properties.title or "",
|
||||
doc.properties and doc.properties.status or "",
|
||||
doc.properties and doc.properties.priority or "",
|
||||
doc.created_at and os.date("%Y-%m-%d", doc.created_at) or "",
|
||||
doc.updated_at and os.date("%Y-%m-%d", doc.updated_at) or ""
|
||||
}
|
||||
|
||||
-- Escape CSV values
|
||||
for j, value in ipairs(row) do
|
||||
if value:find("[,\"]") then
|
||||
row[j] = '"' .. value:gsub('"', '""') .. '"'
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(lines, table.concat(row, ","))
|
||||
end
|
||||
end
|
||||
|
||||
return true, table.concat(lines, "\n")
|
||||
end
|
||||
|
||||
-- Export to JSON
|
||||
function M.export_to_json(query_results, options)
|
||||
local export_data = {
|
||||
query = query_results.query_string,
|
||||
total_count = query_results.total_count,
|
||||
execution_time_ms = query_results.execution_time_ms,
|
||||
documents = query_results.documents,
|
||||
exported_at = os.time(),
|
||||
exported_by = "notex.nvim"
|
||||
}
|
||||
|
||||
return true, vim.json.encode(export_data)
|
||||
end
|
||||
|
||||
return M
|
Loading…
Add table
Add a link
Reference in a new issue