1
argonaut.nvim/lua/argonaut.lua

310 lines
9.1 KiB
Lua
Raw Normal View History

2024-04-20 16:29:45 +00:00
local config = require('config')
2022-12-30 23:10:22 +00:00
2023-02-20 21:01:31 +00:00
local function setup(opts, filetypes)
2024-04-20 16:29:45 +00:00
config.set_filetype_opts(opts, filetypes)
2022-12-30 23:10:22 +00:00
end
2023-01-29 06:43:56 +00:00
local function get_cursor_pos()
local _, row, col, _ = unpack(vim.fn.getpos('.'))
return {row = row, col = col}
end
2023-02-20 20:35:38 +00:00
local function get_brace_alt(brace)
2023-02-08 02:10:12 +00:00
local brace_pairs = {{'(', ')'}, {'[', ']'}, {'{', '}'}, {'<', '>'}}
for _, brace_pair in ipairs(brace_pairs) do
if brace_pair[1] == brace then
return brace_pair[2], true
elseif brace_pair[2] == brace then
return brace_pair[1], false
end
end
end
2023-02-20 20:35:38 +00:00
local function is_string_literal(pos)
if not pos then
pos = get_cursor_pos()
end
2023-02-20 22:21:29 +00:00
local syn_id = vim.fn.synID(pos.row, pos.col, false)
2023-02-20 20:35:38 +00:00
local syn_attr = vim.fn.synIDattr(syn_id, 'name')
return syn_attr:find('String$')
end
2023-02-08 02:10:12 +00:00
local function find_brace_range(brace)
2023-02-20 20:35:38 +00:00
local brace_alt, _ = get_brace_alt(brace)
2023-02-08 02:10:12 +00:00
assert(brace_alt)
2023-02-20 20:31:38 +00:00
local escape_brace = function(brace_raw)
if brace_raw == '[' or brace_raw == ']' then
return '\\' .. brace_raw
else
return brace_raw
end
end
2023-02-20 05:11:47 +00:00
local row1, col1 = unpack(vim.fn.searchpairpos(escape_brace(brace), '', escape_brace(brace_alt), 'Wnb', is_string_literal))
2023-01-29 03:20:14 +00:00
if row1 > 0 and col1 > 0 then
2023-02-08 02:10:12 +00:00
local row2, col2 = unpack(vim.fn.searchpairpos(escape_brace(brace), '', escape_brace(brace_alt), 'Wcn', is_string_literal))
2023-01-29 03:20:14 +00:00
if row2 > 0 and col2 > 0 then
return {
2023-02-08 02:10:12 +00:00
brace = brace,
2023-01-29 03:20:14 +00:00
row1 = row1,
col1 = col1,
row2 = row2,
col2 = col2
}
end
end
2022-12-30 23:10:22 +00:00
end
2023-02-08 02:10:12 +00:00
local function find_all_brace_ranges(braces)
local brace_ranges = {}
for _, brace in ipairs(braces) do
local brace_range = find_brace_range(brace)
if brace_range then
table.insert(brace_ranges, brace_range)
2023-01-29 03:20:14 +00:00
end
end
2023-02-08 02:10:12 +00:00
if #brace_ranges > 0 then
return brace_ranges
2023-01-29 03:20:14 +00:00
end
end
2023-02-08 02:10:12 +00:00
local function find_closest_brace_range(braces)
local cursor_pos = get_cursor_pos()
local compare_brace_ranges = function(brace_range_1, brace_range_2)
local row_diff1 = cursor_pos.row - brace_range_1.row1
local row_diff2 = cursor_pos.row - brace_range_2.row1
2023-02-07 06:36:11 +00:00
if row_diff1 < row_diff2 then
return -1
elseif row_diff1 > row_diff2 then
return 1
end
2023-01-29 03:20:14 +00:00
2023-02-08 02:10:12 +00:00
local col_diff1 = cursor_pos.col - brace_range_1.col1
local col_diff2 = cursor_pos.col - brace_range_2.col1
2023-02-07 06:36:11 +00:00
if col_diff1 < col_diff2 then
return -1
elseif col_diff1 > col_diff2 then
return 1
end
2023-01-29 03:20:14 +00:00
2023-02-07 06:36:11 +00:00
return 0
end
2022-12-30 23:10:22 +00:00
2023-02-08 02:10:12 +00:00
local brace_ranges = find_all_brace_ranges(braces)
if brace_ranges then
return vim.fn.sort(brace_ranges, compare_brace_ranges)[1]
2023-01-29 03:20:14 +00:00
end
2022-12-30 23:10:22 +00:00
end
2023-03-12 18:52:29 +00:00
local function parse_brace_range_params(brace_range)
2023-02-20 01:53:06 +00:00
brace_range.params = {}
2023-02-20 02:40:34 +00:00
local first_line = vim.fn.getline(brace_range.row1)
2023-02-20 23:37:49 +00:00
brace_range.indent = first_line:match('^(%s*)')
brace_range.prefix = first_line:sub(#brace_range.indent + 1, brace_range.col1)
2023-02-20 02:40:34 +00:00
local last_line = vim.fn.getline(brace_range.row2)
2023-02-20 23:37:49 +00:00
brace_range.suffix = last_line:sub(brace_range.col2)
2023-02-20 01:53:06 +00:00
2023-02-20 23:54:19 +00:00
local brace_range_param = nil
2023-02-08 02:10:12 +00:00
local flush_brace_range_param = function()
2023-02-20 23:54:19 +00:00
if brace_range_param then
2024-01-22 02:03:52 +00:00
brace_range_param.col_raw_1 = brace_range_param.col
brace_range_param.col_raw_2 = brace_range_param.col + #brace_range_param.text
2023-02-21 03:47:22 +00:00
local left_pad_start, left_pad_end = brace_range_param.text:find('^%s+')
if left_pad_start and left_pad_end then
local pad_length = left_pad_end - left_pad_start + 1
2023-02-21 03:39:57 +00:00
brace_range_param.col = brace_range_param.col + pad_length
brace_range_param.text = brace_range_param.text:sub(pad_length + 1)
end
2023-02-21 03:47:22 +00:00
local right_pad_start, right_pad_end = brace_range_param.text:find('%s+$')
if right_pad_start and right_pad_end then
local pad_length = right_pad_end - right_pad_start + 1
2023-02-21 03:39:57 +00:00
brace_range_param.text = brace_range_param.text:sub(1, #brace_range_param.text - pad_length)
end
2023-02-21 03:47:22 +00:00
if #brace_range_param.text > 0 then
table.insert(brace_range.params, brace_range_param)
end
2023-02-20 23:54:19 +00:00
brace_range_param = nil
end
end
local update_brace_range_param = function(element)
if brace_range_param then
brace_range_param.text = brace_range_param.text .. element.char
else
2023-03-12 18:52:29 +00:00
brace_range_param = {
text = element.char,
row = element.row,
col = element.col,
brace = element.brace
}
2023-02-08 02:10:12 +00:00
end
end
local brace_stack = {}
local update_brace_stack = function(c)
local brace_stack_size = #brace_stack
2023-02-20 20:35:38 +00:00
local brace_alt, brace_open = get_brace_alt(c)
2023-02-08 02:10:12 +00:00
if brace_stack_size > 0 and brace_alt == brace_stack[brace_stack_size] and not brace_open then
table.remove(brace_stack, brace_stack_size)
elseif brace_alt then
table.insert(brace_stack, c)
end
end
local brace_range_elements = {}
for row = brace_range.row1, brace_range.row2 do
2023-02-07 06:36:11 +00:00
local line = vim.fn.getline(row)
2023-02-20 20:23:29 +00:00
local col1 = 1
2023-02-08 02:10:12 +00:00
if row == brace_range.row1 then
col1 = brace_range.col1 + 1
2023-02-07 06:36:11 +00:00
end
local col2 = #line
2023-02-08 02:10:12 +00:00
if row == brace_range.row2 then
col2 = brace_range.col2 - 1
2023-02-07 06:36:11 +00:00
end
2023-02-20 20:23:29 +00:00
for col = col1, col2 do
2023-02-20 23:54:19 +00:00
local char = line:sub(col, col)
assert(#char > 0)
2023-02-21 04:37:36 +00:00
table.insert(brace_range_elements, {
row = row,
col = col,
char = char,
brace = brace_range.brace,
literal = is_string_literal({row = row, col = col}),
})
2023-02-07 06:36:11 +00:00
end
end
2023-03-12 18:52:29 +00:00
for _, brace_range_element in ipairs(brace_range_elements) do
2024-01-22 04:10:40 +00:00
local append = true
if not brace_range_element.literal then
2023-03-12 18:52:29 +00:00
update_brace_stack(brace_range_element.char)
if #brace_stack == 0 and brace_range_element.char == ',' then
flush_brace_range_param()
append = false
2023-02-07 06:36:11 +00:00
end
2023-03-12 18:52:29 +00:00
end
2023-02-07 06:36:11 +00:00
2023-03-12 18:52:29 +00:00
if append then
update_brace_range_param(brace_range_element)
2023-02-07 06:36:11 +00:00
end
2023-03-12 18:52:29 +00:00
end
flush_brace_range_param()
if #brace_range.params > 0 then
local cursor_pos = get_cursor_pos()
2023-02-07 06:36:11 +00:00
2024-04-20 16:29:45 +00:00
for _, param in ipairs(brace_range.params) do
2023-03-12 18:52:29 +00:00
local contains_row =
cursor_pos.row == param.row
local contains_col =
2024-01-22 02:03:52 +00:00
cursor_pos.col >= param.col_raw_1 and
cursor_pos.col <= param.col_raw_2
2023-03-12 18:52:29 +00:00
if contains_row and contains_col then
2024-01-22 01:35:26 +00:00
param.offset = cursor_pos.col - param.col
2023-03-12 18:52:29 +00:00
break
end
end
2023-02-07 06:36:11 +00:00
end
2023-02-20 01:53:06 +00:00
end
local function wrap_brace_range(brace_range)
2024-04-20 16:29:45 +00:00
local opts = config.get_filetype_opts()
2023-02-20 22:21:29 +00:00
2023-02-20 05:11:47 +00:00
vim.fn.setline(brace_range.row1, brace_range.indent .. brace_range.prefix)
2023-02-20 04:45:40 +00:00
2024-01-22 01:35:26 +00:00
local cursor_pos = nil
2023-02-20 04:45:40 +00:00
local row = brace_range.row1
for i, param in ipairs(brace_range.params) do
2023-02-20 22:21:29 +00:00
local on_last_row = i == #brace_range.params
2023-02-20 04:45:40 +00:00
2023-02-20 23:54:19 +00:00
local line = brace_range.indent .. param.text
2024-04-20 16:29:45 +00:00
if opts.tail_comma or not on_last_row then
2023-02-20 04:45:40 +00:00
line = line .. ','
end
2024-04-20 16:29:45 +00:00
if on_last_row and not opts.wrap_closing_brace then
2023-02-20 22:21:29 +00:00
line = line .. brace_range.suffix
end
2023-02-20 04:45:40 +00:00
vim.fn.append(row, line)
vim.fn.execute(string.format('%d>', row + 1))
2024-01-22 01:35:26 +00:00
if param.offset then
cursor_pos = get_cursor_pos()
cursor_pos.col = cursor_pos.col + param.offset
cursor_pos.row = row + 1
end
2023-02-20 04:45:40 +00:00
row = row + 1
end
2024-04-20 16:29:45 +00:00
if opts.wrap_closing_brace then
2023-02-20 22:21:29 +00:00
vim.fn.append(row, brace_range.indent .. brace_range.suffix)
end
2024-01-22 01:35:26 +00:00
if cursor_pos then
vim.fn.setcursorcharpos({cursor_pos.row, cursor_pos.col})
end
2023-02-20 01:53:06 +00:00
end
local function unwrap_brace_range(brace_range)
2024-01-22 01:35:26 +00:00
local cursor_pos = nil
2023-02-20 05:11:47 +00:00
local line = brace_range.indent .. brace_range.prefix
2023-02-20 02:40:34 +00:00
for i, param in ipairs(brace_range.params) do
2024-01-22 01:35:26 +00:00
if param.offset then
cursor_pos = {
row = brace_range.row1,
col = #line + param.offset + 1
}
end
2023-02-20 23:54:19 +00:00
line = line .. param.text
2023-02-20 02:40:34 +00:00
if i < #brace_range.params then
line = line .. ', '
end
end
line = line .. brace_range.suffix
2023-02-07 06:36:11 +00:00
2023-02-20 02:40:34 +00:00
vim.fn.setline(brace_range.row1, line)
2023-02-20 23:09:22 +00:00
vim.fn.execute(string.format('%d,%dd_', brace_range.row1 + 1, brace_range.row2))
2024-01-22 01:35:26 +00:00
if cursor_pos then
vim.fn.setcursorcharpos({cursor_pos.row, cursor_pos.col})
end
2023-02-07 06:36:11 +00:00
end
2023-01-29 03:20:14 +00:00
local function reflow()
2023-02-20 22:21:29 +00:00
local brace_range = find_closest_brace_range({'(', '[', '{', '<'})
2023-02-08 02:10:12 +00:00
if brace_range then
2023-03-12 18:52:29 +00:00
parse_brace_range_params(brace_range)
2023-02-20 01:53:06 +00:00
if brace_range.row1 == brace_range.row2 then
wrap_brace_range(brace_range)
else
2023-02-20 02:40:34 +00:00
unwrap_brace_range(brace_range)
2023-02-20 01:53:06 +00:00
end
2023-01-29 03:20:14 +00:00
end
2022-12-30 18:40:23 +00:00
end
return {
2023-01-29 03:20:14 +00:00
reflow = reflow,
2023-02-20 21:01:31 +00:00
setup = setup,
2022-12-30 18:40:23 +00:00
}