WIP
This commit is contained in:
parent
23fd61dab8
commit
588e8781d5
@ -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,
|
||||
}
|
||||
|
@ -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)
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user