2024-04-22 01:11:56 +00:00
|
|
|
--
|
|
|
|
-- Cursor
|
|
|
|
--
|
2024-04-22 00:20:57 +00:00
|
|
|
|
2024-04-25 03:02:10 +00:00
|
|
|
local Cursor = {}
|
2024-04-22 00:20:57 +00:00
|
|
|
|
2024-04-22 01:11:56 +00:00
|
|
|
function Cursor.new(row, col)
|
|
|
|
local cursor = {row = row, col = col}
|
2024-04-22 00:20:57 +00:00
|
|
|
return setmetatable(cursor, {__index = Cursor})
|
|
|
|
end
|
|
|
|
|
2024-04-22 04:57:41 +00:00
|
|
|
function Cursor:is_valid()
|
|
|
|
return self.row > 0 and self.col > 0
|
|
|
|
end
|
|
|
|
|
|
|
|
function Cursor:is_string()
|
2024-04-25 02:58:01 +00:00
|
|
|
assert(self:is_valid())
|
2024-04-22 01:11:56 +00:00
|
|
|
local syn_id = vim.fn.synID(self.row, self.col, false)
|
|
|
|
local syn_attr = vim.fn.synIDattr(syn_id, 'name')
|
|
|
|
return syn_attr:find('String$')
|
|
|
|
end
|
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
function Cursor.get_current()
|
|
|
|
local _, row, col, _ = unpack(vim.fn.getpos('.'))
|
|
|
|
return Cursor.new(row, col)
|
|
|
|
end
|
|
|
|
|
|
|
|
function Cursor:set_current()
|
|
|
|
assert(self:is_valid())
|
|
|
|
vim.fn.secursorcharpos({self.row, self.col})
|
|
|
|
end
|
|
|
|
|
2024-04-22 01:11:56 +00:00
|
|
|
--
|
|
|
|
-- BracePair
|
|
|
|
--
|
|
|
|
|
2024-04-25 03:02:10 +00:00
|
|
|
local BracePair = {}
|
2024-04-22 00:20:57 +00:00
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
function BracePair.new(open, close)
|
|
|
|
local brace_pair = {open = open, close = close}
|
2024-04-22 01:11:56 +00:00
|
|
|
return setmetatable(brace_pair, {__index = BracePair})
|
|
|
|
end
|
|
|
|
|
|
|
|
function BracePair.from_brace(brace)
|
2024-04-25 02:58:01 +00:00
|
|
|
local brace_pairs = {
|
|
|
|
{'(', ')'},
|
|
|
|
{'[', ']'},
|
|
|
|
{'{', '}'},
|
|
|
|
{'<', '>'},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, brace_pair in ipairs(brace_pairs) do
|
2024-04-23 05:36:25 +00:00
|
|
|
if brace_pair[1] == brace or brace_pair[2] == brace then
|
|
|
|
return BracePair.new(brace_pair[1], brace_pair[2])
|
2024-04-22 01:11:56 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function BracePair:escaped()
|
2024-04-25 02:58:01 +00:00
|
|
|
local escape_func = function(brace_raw)
|
2024-04-22 00:20:57 +00:00
|
|
|
if brace_raw == '[' or brace_raw == ']' then
|
|
|
|
return '\\' .. brace_raw
|
|
|
|
else
|
|
|
|
return brace_raw
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
return BracePair.new(
|
|
|
|
escape_func(self.open),
|
|
|
|
escape_func(self.close)
|
|
|
|
)
|
2024-04-22 01:11:56 +00:00
|
|
|
end
|
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
function BracePair:find_closest(backward, cursor)
|
|
|
|
if not cursor then
|
|
|
|
cursor = Cursor.get_current()
|
|
|
|
end
|
|
|
|
|
2024-04-22 01:11:56 +00:00
|
|
|
-- See flags: https://neovim.io/doc/user/builtin.html#search()
|
|
|
|
local flags = 'Wcn'
|
|
|
|
if backward then
|
|
|
|
flags = 'Wbn'
|
|
|
|
end
|
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
local ignore_func = function()
|
|
|
|
return cursor:is_string()
|
|
|
|
end
|
|
|
|
|
2024-04-22 01:11:56 +00:00
|
|
|
local escaped_pair = self:escaped()
|
|
|
|
local position = vim.fn.searchpairpos(
|
|
|
|
escaped_pair.open,
|
|
|
|
'',
|
|
|
|
escaped_pair.close,
|
|
|
|
flags,
|
2024-04-25 02:58:01 +00:00
|
|
|
ignore_func
|
2024-04-22 01:11:56 +00:00
|
|
|
)
|
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
local brace_cursor = Cursor.new(unpack(position))
|
|
|
|
if brace_cursor:is_valid() then
|
|
|
|
return brace_cursor
|
2024-04-22 00:20:57 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-04-23 05:36:25 +00:00
|
|
|
--
|
|
|
|
-- BraceStack
|
|
|
|
--
|
|
|
|
|
2024-04-25 03:02:10 +00:00
|
|
|
local BraceStack = {}
|
2024-04-23 05:36:25 +00:00
|
|
|
|
|
|
|
function BraceStack.new()
|
|
|
|
local stack = {stack = {}}
|
|
|
|
return setmetatable(stack, {__index = BraceStack})
|
|
|
|
end
|
|
|
|
|
|
|
|
function BraceStack:update(brace)
|
2024-04-25 02:39:09 +00:00
|
|
|
local brace_pair = BracePair.from_brace(brace)
|
2024-04-23 05:36:25 +00:00
|
|
|
if brace_pair then
|
|
|
|
if brace == brace_pair.close and self:top() == brace_pair.open then
|
|
|
|
self:pop()
|
|
|
|
else
|
|
|
|
self:push(brace)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function BraceStack:push(brace)
|
|
|
|
table.insert(self.stack, brace)
|
|
|
|
end
|
|
|
|
|
|
|
|
function BraceStack:pop()
|
|
|
|
assert(not self:empty())
|
|
|
|
return table.remove(self.stack, #self.stack)
|
|
|
|
end
|
|
|
|
|
|
|
|
function BraceStack:empty()
|
|
|
|
return #self.stack == 0
|
|
|
|
end
|
|
|
|
|
|
|
|
function BraceStack:top()
|
|
|
|
return #self.stack[#self.stack]
|
|
|
|
end
|
|
|
|
|
2024-04-22 01:11:56 +00:00
|
|
|
--
|
|
|
|
-- BraceRange
|
|
|
|
--
|
|
|
|
|
2024-04-25 03:02:10 +00:00
|
|
|
local BraceRange = {}
|
2024-04-22 00:20:57 +00:00
|
|
|
|
|
|
|
function BraceRange.new(start_cursor, stop_cursor, brace_pair, brace_params)
|
|
|
|
local brace_range = {
|
|
|
|
start_cursor = start_cursor,
|
|
|
|
stop_cursor = stop_cursor,
|
|
|
|
brace_pair = brace_pair,
|
2024-04-22 01:11:56 +00:00
|
|
|
brace_params = brace_params,
|
2024-04-22 00:20:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return setmetatable(brace_range, {__index = BraceRange})
|
|
|
|
end
|
2024-04-22 01:11:56 +00:00
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
function BraceRange.find_closest(brace_pair)
|
|
|
|
local stop_cursor = brace_pair:find_closest(false)
|
2024-04-25 02:39:09 +00:00
|
|
|
if stop_cursor then
|
2024-04-25 02:58:01 +00:00
|
|
|
local start_cursor = brace_pair:find_closest(true)
|
2024-04-25 02:39:09 +00:00
|
|
|
if start_cursor then
|
2024-04-22 01:11:56 +00:00
|
|
|
return BraceRange.new(start_cursor, stop_cursor, brace_pair, {})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2024-04-22 04:57:41 +00:00
|
|
|
|
2024-04-25 02:58:01 +00:00
|
|
|
function BraceRange.find_closest_any()
|
2024-04-22 04:57:41 +00:00
|
|
|
local brace_range_compare = function(brace_range_1, brace_range_2)
|
2024-04-25 02:58:01 +00:00
|
|
|
local cursor = Cursor:get_current()
|
2024-04-22 04:57:41 +00:00
|
|
|
|
|
|
|
local row_diff1 = cursor.row - brace_range_1.start_cursor.row
|
|
|
|
local row_diff2 = cursor.row - brace_range_2.start_cursor.row
|
|
|
|
if row_diff1 < row_diff2 then
|
|
|
|
return -1
|
|
|
|
elseif row_diff1 > row_diff2 then
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
|
|
|
|
local col_diff1 = cursor.col - brace_range_1.start_cursor.col
|
|
|
|
local col_diff2 = cursor.col - brace_range_2.start_cursor.col
|
|
|
|
if col_diff1 < col_diff2 then
|
|
|
|
return -1
|
|
|
|
elseif col_diff1 > col_diff2 then
|
|
|
|
return 1
|
|
|
|
end
|
|
|
|
|
|
|
|
return 0
|
|
|
|
end
|
|
|
|
|
|
|
|
local brace_ranges = {}
|
|
|
|
for _, brace in ipairs({'(', '[', '{', '<'}) do
|
|
|
|
local brace_pair = BracePair.from_brace(brace)
|
2024-04-25 02:58:01 +00:00
|
|
|
local brace_range = BraceRange.find_closest(brace_pair)
|
2024-04-22 04:57:41 +00:00
|
|
|
if brace_range then
|
|
|
|
table.insert(brace_ranges, brace_range)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-04-22 05:07:24 +00:00
|
|
|
if #brace_ranges > 0 then
|
2024-04-25 02:39:09 +00:00
|
|
|
vim.fn.sort(brace_ranges, brace_range_compare)
|
|
|
|
return brace_ranges[1]
|
2024-04-22 05:07:24 +00:00
|
|
|
end
|
2024-04-22 04:57:41 +00:00
|
|
|
end
|
2024-04-24 02:04:14 +00:00
|
|
|
|
2024-04-24 04:43:26 +00:00
|
|
|
function BraceRange:is_wrapped()
|
2024-04-25 02:39:09 +00:00
|
|
|
return self.start_cursor.row < self.stop_cursor.row
|
2024-04-24 04:43:26 +00:00
|
|
|
end
|
2024-04-24 02:04:14 +00:00
|
|
|
|
|
|
|
--
|
|
|
|
-- Arg
|
|
|
|
--
|
|
|
|
|
2024-04-25 03:02:10 +00:00
|
|
|
local Arg = {}
|
2024-04-24 02:04:14 +00:00
|
|
|
|
|
|
|
function Arg.new(text, brace_pair)
|
|
|
|
local arg = {
|
|
|
|
text = text,
|
|
|
|
brace_pair = brace_pair,
|
|
|
|
}
|
|
|
|
|
|
|
|
return setmetatable(arg, {__index = Arg})
|
|
|
|
end
|
|
|
|
|
|
|
|
function Arg:append(char)
|
|
|
|
self.text = self.text .. char
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- ArgList
|
|
|
|
--
|
|
|
|
|
2024-04-25 03:02:10 +00:00
|
|
|
local ArgList = {}
|
2024-04-24 02:04:14 +00:00
|
|
|
|
|
|
|
function ArgList.new()
|
|
|
|
local arg_list = {
|
|
|
|
indent = '',
|
|
|
|
prefix = '',
|
|
|
|
suffix = '',
|
|
|
|
arg = nil,
|
|
|
|
args = {},
|
|
|
|
}
|
|
|
|
|
|
|
|
return setmetatable(arg_list, {__index = ArgList})
|
|
|
|
end
|
|
|
|
|
|
|
|
function ArgList:flush()
|
|
|
|
if self.arg then
|
|
|
|
table.insert(self.args, self.arg)
|
|
|
|
self.arg = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function ArgList:update(char, brace_stack, brace_range, cursor)
|
|
|
|
if not cursor:is_string() then
|
|
|
|
brace_stack:update(char)
|
|
|
|
if brace_stack:empty() and char == ',' then
|
|
|
|
self:flush()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if self.arg then
|
2024-04-25 02:39:09 +00:00
|
|
|
self.arg:append(char)
|
2024-04-24 02:04:14 +00:00
|
|
|
else
|
|
|
|
self.arg = Arg.new(char, brace_range)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function ArgList:parse(brace_range)
|
|
|
|
local brace_stack = BraceStack:new()
|
|
|
|
|
|
|
|
local first_line = vim.fn.getline(brace_range.start_cursor.row)
|
|
|
|
self.indent = first_line:match('^(%s*)')
|
2024-04-25 02:39:09 +00:00
|
|
|
self.prefix = first_line:sub(#self.indent + 1, brace_range.start_cursor.col)
|
2024-04-24 02:04:14 +00:00
|
|
|
|
|
|
|
local last_line = vim.fn.getline(brace_range.stop_cursor.row)
|
|
|
|
self.suffix = last_line:sub(brace_range.stop_cursor.col)
|
|
|
|
|
|
|
|
for row = brace_range.start_cursor.row, brace_range.stop_cursor.row do
|
|
|
|
local line = vim.fn.getline(row)
|
|
|
|
|
|
|
|
local start_col = 1
|
|
|
|
if row == brace_range.start_cursor.row then
|
|
|
|
start_col = brace_range.start_cursor.col + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
local stop_col = #line
|
|
|
|
if row == brace_range.stop_cursor.row then
|
|
|
|
stop_col = brace_range.stop_cursor.col - 1
|
|
|
|
end
|
|
|
|
|
|
|
|
for col = start_col, stop_col do
|
|
|
|
local char = line:sub(col, col)
|
|
|
|
self:update(char, brace_stack, brace_range, Cursor.new(row, col))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-04-24 03:38:56 +00:00
|
|
|
self:flush()
|
2024-04-24 02:04:14 +00:00
|
|
|
end
|
2024-04-24 04:43:26 +00:00
|
|
|
|
2024-04-25 02:39:09 +00:00
|
|
|
return {
|
2024-04-25 03:02:10 +00:00
|
|
|
BraceRange = BraceRange,
|
|
|
|
ArgList = ArgList,
|
2024-04-25 02:39:09 +00:00
|
|
|
}
|