From 588e8781d5677c09ac1eae7d2342d30f6a4fe939 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Wed, 24 Apr 2024 19:39:09 -0700 Subject: [PATCH] WIP --- lua/argonaut/init.lua | 301 +---------------------------------------- lua/argonaut/types.lua | 43 +++--- 2 files changed, 25 insertions(+), 319 deletions(-) diff --git a/lua/argonaut/init.lua b/lua/argonaut/init.lua index 2de56ea..9f47a99 100644 --- a/lua/argonaut/init.lua +++ b/lua/argonaut/init.lua @@ -5,306 +5,7 @@ local function setup(opts, filetypes) config.set(opts, filetypes) end -local function get_cursor_pos() - local _, row, col, _ = unpack(vim.fn.getpos('.')) - return {row = row, col = col} -end - -local function get_brace_alt(brace) - 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 - -local function is_string_literal(pos) - if not pos then - pos = get_cursor_pos() - end - - local syn_id = vim.fn.synID(pos.row, pos.col, false) - local syn_attr = vim.fn.synIDattr(syn_id, 'name') - - return syn_attr:find('String$') -end - -local function find_brace_range(brace) - local brace_alt, _ = get_brace_alt(brace) - assert(brace_alt) - - local escape_brace = function(brace_raw) - if brace_raw == '[' or brace_raw == ']' then - return '\\' .. brace_raw - else - return brace_raw - end - end - - local row1, col1 = unpack(vim.fn.searchpairpos(escape_brace(brace), '', escape_brace(brace_alt), 'Wnb', is_string_literal)) - if row1 > 0 and col1 > 0 then - local row2, col2 = unpack(vim.fn.searchpairpos(escape_brace(brace), '', escape_brace(brace_alt), 'Wcn', is_string_literal)) - if row2 > 0 and col2 > 0 then - return { - brace = brace, - row1 = row1, - col1 = col1, - row2 = row2, - col2 = col2 - } - end - end -end - -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) - end - end - - if #brace_ranges > 0 then - return brace_ranges - end -end - -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 - if row_diff1 < row_diff2 then - return -1 - elseif row_diff1 > row_diff2 then - return 1 - end - - local col_diff1 = cursor_pos.col - brace_range_1.col1 - local col_diff2 = cursor_pos.col - brace_range_2.col1 - if col_diff1 < col_diff2 then - return -1 - elseif col_diff1 > col_diff2 then - return 1 - end - - return 0 - end - - local brace_ranges = find_all_brace_ranges(braces) - if brace_ranges then - return vim.fn.sort(brace_ranges, compare_brace_ranges)[1] - end -end - -local function parse_brace_range_params(brace_range) - brace_range.params = {} - - local first_line = vim.fn.getline(brace_range.row1) - brace_range.indent = first_line:match('^(%s*)') - brace_range.prefix = first_line:sub(#brace_range.indent + 1, brace_range.col1) - - local last_line = vim.fn.getline(brace_range.row2) - brace_range.suffix = last_line:sub(brace_range.col2) - - local brace_range_param = nil - local flush_brace_range_param = function() - if brace_range_param then - brace_range_param.col_raw_1 = brace_range_param.col - brace_range_param.col_raw_2 = brace_range_param.col + #brace_range_param.text - - 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 - brace_range_param.col = brace_range_param.col + pad_length - brace_range_param.text = brace_range_param.text:sub(pad_length + 1) - end - - 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 - brace_range_param.text = brace_range_param.text:sub(1, #brace_range_param.text - pad_length) - end - - if #brace_range_param.text > 0 then - table.insert(brace_range.params, brace_range_param) - end - - 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 - brace_range_param = { - text = element.char, - row = element.row, - col = element.col, - brace = element.brace - } - end - end - - local brace_stack = {} - local update_brace_stack = function(c) - local brace_stack_size = #brace_stack - local brace_alt, brace_open = get_brace_alt(c) - 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 - local line = vim.fn.getline(row) - - local col1 = 1 - if row == brace_range.row1 then - col1 = brace_range.col1 + 1 - end - - local col2 = #line - if row == brace_range.row2 then - col2 = brace_range.col2 - 1 - end - - for col = col1, col2 do - local char = line:sub(col, col) - assert(#char > 0) - table.insert(brace_range_elements, { - row = row, - col = col, - char = char, - brace = brace_range.brace, - literal = is_string_literal({row = row, col = col}), - }) - end - end - - for _, brace_range_element in ipairs(brace_range_elements) do - local append = true - if not brace_range_element.literal then - update_brace_stack(brace_range_element.char) - if #brace_stack == 0 and brace_range_element.char == ',' then - flush_brace_range_param() - append = false - end - end - - if append then - update_brace_range_param(brace_range_element) - end - end - - flush_brace_range_param() - - if #brace_range.params > 0 then - local cursor_pos = get_cursor_pos() - - for _, param in ipairs(brace_range.params) do - local contains_row = - cursor_pos.row == param.row - - local contains_col = - cursor_pos.col >= param.col_raw_1 and - cursor_pos.col <= param.col_raw_2 - - if contains_row and contains_col then - param.offset = cursor_pos.col - param.col - break - end - end - end -end - -local function wrap_brace_range(brace_range) - local opts = config.get() - - vim.fn.setline(brace_range.row1, brace_range.indent .. brace_range.prefix) - - local cursor_pos = nil - local row = brace_range.row1 - for i, param in ipairs(brace_range.params) do - local on_last_row = i == #brace_range.params - - local line = brace_range.indent .. param.text - if opts.tail_comma or not on_last_row then - line = line .. ',' - end - - if on_last_row and not opts.wrap_closing_brace then - line = line .. brace_range.suffix - end - - vim.fn.append(row, line) - vim.fn.execute(string.format('%d>', row + 1)) - - if param.offset then - cursor_pos = get_cursor_pos() - cursor_pos.col = cursor_pos.col + param.offset - cursor_pos.row = row + 1 - end - - row = row + 1 - end - - if opts.wrap_closing_brace then - vim.fn.append(row, brace_range.indent .. brace_range.suffix) - end - - if cursor_pos then - vim.fn.setcursorcharpos({cursor_pos.row, cursor_pos.col}) - end -end - -local function unwrap_brace_range(brace_range) - local cursor_pos = nil - local line = brace_range.indent .. brace_range.prefix - for i, param in ipairs(brace_range.params) do - if param.offset then - cursor_pos = { - row = brace_range.row1, - col = #line + param.offset + 1 - } - end - - line = line .. param.text - if i < #brace_range.params then - line = line .. ', ' - end - end - line = line .. brace_range.suffix - - vim.fn.setline(brace_range.row1, line) - vim.fn.execute(string.format('%d,%dd_', brace_range.row1 + 1, brace_range.row2)) - - if cursor_pos then - vim.fn.setcursorcharpos({cursor_pos.row, cursor_pos.col}) - end -end - -local function reflow() - local brace_range = find_closest_brace_range({'(', '[', '{', '<'}) - if brace_range then - parse_brace_range_params(brace_range) - if brace_range.row1 == brace_range.row2 then - wrap_brace_range(brace_range) - else - unwrap_brace_range(brace_range) - end - end -end - return { - reflow = reflow, + reflow = types.reflow, setup = setup, } diff --git a/lua/argonaut/types.lua b/lua/argonaut/types.lua index 3c6ed1e..3858d5d 100644 --- a/lua/argonaut/types.lua +++ b/lua/argonaut/types.lua @@ -96,7 +96,7 @@ function BraceStack.new() end function BraceStack:update(brace) - local brace_pair = BracePair.new(brace) + local brace_pair = BracePair.from_brace(brace) if brace_pair then if brace == brace_pair.close and self:top() == brace_pair.open then self:pop() @@ -141,10 +141,10 @@ function BraceRange.new(start_cursor, stop_cursor, brace_pair, brace_params) end function BraceRange.find(brace_pair) - local start_cursor = brace_pair:find(false) - if start_cursor then - local stop_cursor = brace_pair:find(true) - if stop_cursor then + local stop_cursor = brace_pair:find(false) + if stop_cursor then + local start_cursor = brace_pair:find(true) + if start_cursor then return BraceRange.new(start_cursor, stop_cursor, brace_pair, {}) end end @@ -183,12 +183,13 @@ function BraceRange.find_closest() end if #brace_ranges > 0 then - return vim.fn.sort(brace_ranges, brace_range_compare)[1] + vim.fn.sort(brace_ranges, brace_range_compare) + return brace_ranges[1] end end function BraceRange:is_wrapped() - return self.start_cursor.row ~= self.stop_cursor.row + return self.start_cursor.row < self.stop_cursor.row end -- @@ -245,7 +246,7 @@ function ArgList:update(char, brace_stack, brace_range, cursor) end if self.arg then - self.arg.append(char) + self.arg:append(char) else self.arg = Arg.new(char, brace_range) end @@ -256,7 +257,7 @@ function ArgList:parse(brace_range) local first_line = vim.fn.getline(brace_range.start_cursor.row) self.indent = first_line:match('^(%s*)') - self.prefix = first_line:sub(#brace_range.indent + 1, brace_range.start_cursor.col) + self.prefix = first_line:sub(#self.indent + 1, brace_range.start_cursor.col) local last_line = vim.fn.getline(brace_range.stop_cursor.row) self.suffix = last_line:sub(brace_range.stop_cursor.col) @@ -291,9 +292,9 @@ local function wrap_brace_range(brace_range, arg_list) for _, arg in ipairs(arg_list.args) do -- local on_last_row = i == #brace_range.params - local line = brace_range.indent .. arg.text + local line = arg_list.indent .. arg.text -- if opts.tail_comma or not on_last_row then - -- line = line .. ',' + line = line .. ',' -- end -- if on_last_row and not opts.wrap_closing_brace then @@ -324,29 +325,33 @@ local function wrap_brace_range(brace_range, arg_list) end local function unwrap_brace_range(brace_range, arg_list) - local line = brace_range.indent .. brace_range.prefix - for i, param in ipairs(brace_range.params) do - line = line .. param.text - if i < #brace_range.params then + local line = arg_list.indent .. arg_list.prefix + for i, arg in ipairs(arg_list.args) do + line = line .. arg.text + if i < #arg_list.args then line = line .. ', ' end end - line = line .. brace_range.suffix + line = line .. arg_list.suffix vim.fn.setline(brace_range.start_cursor.row, line) - vim.fn.execute(string.format('%d,%dd_', brace_range.start_cursor.row + 1, brace_range.stop_cursor.rowrow2)) + vim.fn.execute(string.format('%d,%dd_', brace_range.start_cursor.row + 1, brace_range.stop_cursor.row)) end local function reflow() local brace_range = BraceRange.find_closest() if brace_range then local arg_list = ArgList.new() - arg_list.parse(brace_range) + arg_list:parse(brace_range) - if brace_range.is_wrapped() then + if brace_range:is_wrapped() then unwrap_brace_range(brace_range, arg_list) else wrap_brace_range(brace_range, arg_list) end end end + +return { + reflow = reflow +}