227 lines
6.4 KiB
Lua
227 lines
6.4 KiB
Lua
-- Attribute block toggle - Interactive expand/collapse of {...} blocks
|
|
local M = {}
|
|
|
|
-- Store expanded content per buffer
|
|
-- Format: { [bufnr] = { [line_num] = { collapsed = "...", expanded = "actual content", is_collapsed = boolean } } }
|
|
local buffer_attr_state = {}
|
|
|
|
-- Find attribute block under cursor
|
|
-- Returns: start_col, end_col, content (or nil if not found)
|
|
function M.find_attr_block_under_cursor()
|
|
local line = vim.api.nvim_get_current_line()
|
|
local col = vim.api.nvim_win_get_cursor(0)[2] + 1 -- 1-indexed
|
|
|
|
-- Find all {...} blocks in the line
|
|
local pos = 1
|
|
while pos <= #line do
|
|
local start_pos, end_pos = line:find("{(.-)}", pos)
|
|
if not start_pos then
|
|
break
|
|
end
|
|
|
|
-- Check if cursor is within this block (including braces)
|
|
if col >= start_pos and col <= end_pos then
|
|
local content = line:sub(start_pos + 1, end_pos - 1)
|
|
return start_pos, end_pos, content
|
|
end
|
|
|
|
pos = end_pos + 1
|
|
end
|
|
|
|
return nil, nil, nil
|
|
end
|
|
|
|
-- Toggle the attribute block under cursor
|
|
function M.toggle_attr_block()
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local line_num = vim.api.nvim_win_get_cursor(0)[1]
|
|
local line = vim.api.nvim_get_current_line()
|
|
|
|
local start_col, end_col, content = M.find_attr_block_under_cursor()
|
|
if not start_col then
|
|
vim.notify("No attribute block found under cursor", vim.log.levels.WARN)
|
|
return
|
|
end
|
|
|
|
-- Initialize buffer state if needed
|
|
if not buffer_attr_state[bufnr] then
|
|
buffer_attr_state[bufnr] = {}
|
|
end
|
|
|
|
local state_key = line_num .. "_" .. start_col
|
|
local state = buffer_attr_state[bufnr][state_key]
|
|
|
|
-- Check if this is currently collapsed
|
|
local is_collapsed = content == "..."
|
|
|
|
if is_collapsed then
|
|
-- Expand: restore original content
|
|
if state and state.expanded then
|
|
local new_line = line:sub(1, start_col) .. state.expanded .. line:sub(end_col)
|
|
vim.api.nvim_set_current_line(new_line)
|
|
buffer_attr_state[bufnr][state_key].is_collapsed = false
|
|
vim.notify("Attribute block expanded", vim.log.levels.INFO)
|
|
else
|
|
vim.notify("Cannot expand: original content not stored", vim.log.levels.WARN)
|
|
end
|
|
else
|
|
-- Collapse: store original and show {...}
|
|
local new_line = line:sub(1, start_col) .. "..." .. line:sub(end_col)
|
|
vim.api.nvim_set_current_line(new_line)
|
|
buffer_attr_state[bufnr][state_key] = {
|
|
collapsed = "...",
|
|
expanded = content,
|
|
is_collapsed = true,
|
|
line_num = line_num,
|
|
start_col = start_col,
|
|
}
|
|
vim.notify("Attribute block collapsed", vim.log.levels.INFO)
|
|
end
|
|
end
|
|
|
|
-- Expand all collapsed blocks in current buffer
|
|
function M.expand_all_attr_blocks(opts)
|
|
opts = opts or {}
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
|
local count = 0
|
|
|
|
if not buffer_attr_state[bufnr] then
|
|
if not opts.silent then
|
|
vim.notify("No collapsed blocks to expand", vim.log.levels.INFO)
|
|
end
|
|
return
|
|
end
|
|
|
|
for state_key, state in pairs(buffer_attr_state[bufnr]) do
|
|
if state.is_collapsed then
|
|
local line = lines[state.line_num]
|
|
|
|
if line then
|
|
local new_line = line:sub(1, state.start_col) .. state.expanded .. line:sub(state.start_col + 4)
|
|
lines[state.line_num] = new_line
|
|
state.is_collapsed = false
|
|
count = count + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
|
if not opts.silent and count > 0 then
|
|
vim.notify("Expanded " .. count .. " attribute block(s)", vim.log.levels.INFO)
|
|
end
|
|
end
|
|
|
|
-- Find the last line of the declaration section based on filetype
|
|
local function get_declaration_end(lines, ft)
|
|
if ft == "udt" then
|
|
return #lines
|
|
end
|
|
for i, line in ipairs(lines) do
|
|
if line:match("^%s*BEGIN%s*$") then
|
|
return i - 1
|
|
end
|
|
end
|
|
return #lines
|
|
end
|
|
|
|
-- Collapse all {...} blocks in the declaration section of current buffer
|
|
function M.collapse_all_attr_blocks()
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local ft = vim.bo[bufnr].filetype
|
|
local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
|
local count = 0
|
|
|
|
local decl_end = get_declaration_end(lines, ft)
|
|
|
|
if not buffer_attr_state[bufnr] then
|
|
buffer_attr_state[bufnr] = {}
|
|
end
|
|
|
|
for line_idx = 1, decl_end do
|
|
local line = lines[line_idx]
|
|
local pos = 1
|
|
while pos <= #line do
|
|
local start_pos, end_pos = line:find("{(.-)}", pos)
|
|
if not start_pos then
|
|
break
|
|
end
|
|
|
|
local content = line:sub(start_pos + 1, end_pos - 1)
|
|
|
|
if content ~= "..." then
|
|
local state_key = line_idx .. "_" .. start_pos
|
|
buffer_attr_state[bufnr][state_key] = {
|
|
collapsed = "...",
|
|
expanded = content,
|
|
is_collapsed = true,
|
|
line_num = line_idx,
|
|
start_col = start_pos,
|
|
}
|
|
|
|
line = line:sub(1, start_pos) .. "..." .. line:sub(end_pos)
|
|
count = count + 1
|
|
pos = start_pos + 4
|
|
else
|
|
pos = end_pos + 1
|
|
end
|
|
end
|
|
lines[line_idx] = line
|
|
end
|
|
|
|
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
|
|
vim.notify("Collapsed " .. count .. " attribute block(s)", vim.log.levels.INFO)
|
|
end
|
|
|
|
-- Clear state when buffer is unloaded
|
|
function M.clear_buffer_state(bufnr)
|
|
buffer_attr_state[bufnr] = nil
|
|
end
|
|
|
|
-- Setup autocmd to clear state on buffer unload
|
|
function M.setup()
|
|
local augroup = vim.api.nvim_create_augroup("SCLAttrToggle", { clear = true })
|
|
|
|
vim.api.nvim_create_autocmd("BufWritePre", {
|
|
group = augroup,
|
|
pattern = { "*.scl", "*.udt", "*.db" },
|
|
callback = function(args)
|
|
if buffer_attr_state[args.buf] then
|
|
local has_collapsed = false
|
|
for _, state in pairs(buffer_attr_state[args.buf]) do
|
|
if state.is_collapsed then
|
|
has_collapsed = true
|
|
break
|
|
end
|
|
end
|
|
if has_collapsed then
|
|
M.expand_all_attr_blocks({ silent = true })
|
|
end
|
|
end
|
|
end,
|
|
})
|
|
|
|
vim.api.nvim_create_autocmd("BufUnload", {
|
|
group = augroup,
|
|
pattern = { "*.scl", "*.udt", "*.db" },
|
|
callback = function(args)
|
|
M.clear_buffer_state(args.buf)
|
|
end,
|
|
})
|
|
|
|
-- Create commands
|
|
vim.api.nvim_create_user_command("SCLToggleAttrBlock", function()
|
|
M.toggle_attr_block()
|
|
end, {})
|
|
|
|
vim.api.nvim_create_user_command("SCLExpandAllAttrBlocks", function()
|
|
M.expand_all_attr_blocks()
|
|
end, {})
|
|
|
|
vim.api.nvim_create_user_command("SCLCollapseAllAttrBlocks", function()
|
|
M.collapse_all_attr_blocks()
|
|
end, {})
|
|
end
|
|
|
|
return M
|