mirror of
https://github.com/nvim-treesitter/nvim-treesitter.git
synced 2026-07-02 11:36:54 -04:00
First draft of node swapping
This commit is contained in:
parent
eb13e5c2d7
commit
9dcb96b439
2 changed files with 77 additions and 88 deletions
|
|
@ -16,41 +16,15 @@ M.current_node = {}
|
|||
local function node_start_to_vim(node)
|
||||
if not node then return end
|
||||
|
||||
|
||||
local row, col = node:start()
|
||||
|
||||
local mode = api.nvim_get_mode().mode
|
||||
print(vim.inspect(mode))
|
||||
--if mode == 'v' then
|
||||
--local _, current_line, current_col, _ = unpack(vim.fn.getpos("."))
|
||||
--local _, sel_start_line, sel_start_col, _ = unpack(vim.fn.getpos("'<"))
|
||||
--local _, sel_end_line, sel_end_col, _ = unpack(vim.fn.getpos("'>"))
|
||||
|
||||
--if current_line == sel_start_line and current_col == sel_start_col then
|
||||
--sel_start_line = row + 1
|
||||
--sel_start_col = col + 1
|
||||
--vim.fn.setpos("'<", {row + 1, col + 1})
|
||||
--end
|
||||
--if current_line == sel_end_line and current_col == sel_end_col then
|
||||
--row, col = node:end_()
|
||||
--sel_end_line = row + 1
|
||||
--sel_end_col = col
|
||||
--vim.fn.setpos("'>", {row + 1, col + 1})
|
||||
--end
|
||||
--local exec_command = string.format(select_range,
|
||||
--sel_start_line, sel_start_col,
|
||||
--sel_end_line, sel_end_col)
|
||||
|
||||
--api.nvim_exec(exec_command, false)
|
||||
--else
|
||||
api.nvim_exec('normal gv', false)
|
||||
api.nvim_exec('normal o', false)
|
||||
api.nvim_win_set_cursor(0, {row + 1, col})
|
||||
--end
|
||||
local exec_command = string.format('call cursor(%d, %d)', row+1, col+1)
|
||||
api.nvim_exec(exec_command, false)
|
||||
end
|
||||
|
||||
M.do_node_movement = function(kind, move_node)
|
||||
local line, col = unpack(api.nvim_win_get_cursor(0))
|
||||
local buf = api.nvim_win_get_buf(0)
|
||||
local _, line, col = unpack(vim.fn.getpos("."))
|
||||
local buf = api.nvim_get_current_buf()
|
||||
|
||||
local current_node = M.current_node[buf]
|
||||
|
||||
|
|
@ -95,14 +69,10 @@ M.do_node_movement = function(kind, move_node)
|
|||
node_start_to_vim(destination_node)
|
||||
if move_node then
|
||||
if kind ~= M.NodeMovementKind.down then
|
||||
local _, new_destination_range = utils.swap_nodes(buf, current_node, destination_node)
|
||||
|
||||
local new_destination_range = utils.swap_nodes(buf, current_node, destination_node)
|
||||
local root = parsers.get_parser():parse():root()
|
||||
if new_destination_range then
|
||||
local new_destination_node = root:named_descendant_for_range(new_destination_range[0],
|
||||
new_destination_range[1],
|
||||
new_destination_range[2],
|
||||
new_destination_range[3])
|
||||
local new_destination_node = utils.node_from_lsp_range(root, new_destination_range)
|
||||
M.current_node[buf] = new_destination_node or current_node
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -80,77 +80,96 @@ function M.string_to_lines(str)
|
|||
return t, line_breaks
|
||||
end
|
||||
|
||||
function M.node_to_lsp_range(node)
|
||||
local start_line, start_col, end_line, end_col = node:range()
|
||||
local rtn = {}
|
||||
rtn.start = { line = start_line, character = start_col }
|
||||
rtn['end'] = { line = end_line, character = end_col }
|
||||
return rtn
|
||||
end
|
||||
|
||||
function M.node_to_start_pos(node)
|
||||
local line, col = unpack(node:start())
|
||||
return { line = line, character = col }
|
||||
end
|
||||
|
||||
function M.node_to_end_pos(node)
|
||||
local line, col = unpack(node:end_())
|
||||
return { line = line, character = col }
|
||||
end
|
||||
|
||||
function M.replace_node(buf, source, destination)
|
||||
local replacement_lines = M.get_node_text(source)
|
||||
return M.replace_node_text(buf, destination, replacement_lines)
|
||||
end
|
||||
|
||||
function M.replace_node_text(buf, node_or_range, replacement_lines)
|
||||
local start_row, start_col, end_row, end_col
|
||||
if type(node_or_range) == 'table' then
|
||||
start_row, start_col, end_row, end_col = unpack(node_or_range)
|
||||
else
|
||||
start_row, start_col, end_row, end_col = node_or_range:range()
|
||||
function M.range_lines(lsp_range)
|
||||
return lsp_range['end'].line - lsp_range['start'].line
|
||||
end
|
||||
|
||||
--- Replace node text and return new range (LSP range)
|
||||
-- @param buf buffer number
|
||||
-- @param node node to replace
|
||||
-- @param new lines new lines to use
|
||||
function M.replace_node_text(buf, node, replacement_lines)
|
||||
-- apply_text_edits splits at '\n'
|
||||
local new_text = table.concat(replacement_lines, '\n')
|
||||
|
||||
local text_edit = { range = M.node_to_lsp_range(node), newText = new_text }
|
||||
vim.lsp.util.apply_text_edits({text_edit}, buf)
|
||||
|
||||
local range = text_edit.range
|
||||
|
||||
local end_char = #replacement_lines[#replacement_lines]
|
||||
if #replacement_lines == 1 then
|
||||
end_char = end_char + range.start.character
|
||||
end
|
||||
|
||||
local original_lines = api.nvim_buf_get_lines(buf, start_row, end_row + 1, false)
|
||||
-- original_lines[1]..'' <- Empty string is necessary! Bug in vim string to lua string conversion??
|
||||
local new_text = string.sub(original_lines[1]..'', 1, start_col)..table.concat(replacement_lines, '')..string.sub(original_lines[#original_lines], end_col + 1)
|
||||
|
||||
local new_lines, line_count = M.string_to_lines(new_text)
|
||||
|
||||
api.nvim_buf_set_lines(buf, start_row, end_row + 1, false, new_lines)
|
||||
|
||||
return {start_row,
|
||||
start_col,
|
||||
start_row + line_count,
|
||||
(line_count == 0 and start_col or 0) + #replacement_lines[#replacement_lines]}
|
||||
range['end'] = { line = range.start.line + #replacement_lines - 1,
|
||||
character = end_char }
|
||||
end
|
||||
|
||||
function M.node_lenght(node)
|
||||
local start_row, _, end_row, end_col = node:range()
|
||||
return end_row - start_row, end_col
|
||||
end
|
||||
|
||||
function M.range_difference(node1, node2)
|
||||
local rows1, cols1 = M.node_lenght(node1)
|
||||
local rows2, cols2 = M.node_lenght(node2)
|
||||
|
||||
return rows1 - rows2, (node2:end_() == node1:end_() and cols1 - cols2 or 0)
|
||||
end
|
||||
|
||||
--- Swaps the contents of two nodes returning new range of destination (LSP range)
|
||||
-- @param buf buffer number
|
||||
-- @param source first node
|
||||
-- @param destination second node
|
||||
function M.swap_nodes(buf, source, destination)
|
||||
local dst_start_row, dst_start_col, dst_start = destination:start()
|
||||
local dst_end_row, dst_end_col, dst_end = destination:end_()
|
||||
local src_start_row, src_start_col, src_start = source:start()
|
||||
local src_end_row, src_end_col, src_end = source:end_()
|
||||
local _, _, dst_start = destination:start()
|
||||
local _, _, dst_end = destination:end_()
|
||||
local _, _, src_start = source:start()
|
||||
local _, _, src_end = source:end_()
|
||||
|
||||
if dst_start <= src_start and dst_end >= src_end then
|
||||
local src_range = M.replace_node(buf, source, destination)
|
||||
return src_range, nil
|
||||
return src_range
|
||||
end
|
||||
|
||||
local source_text = M.get_node_text(source)
|
||||
local destination_text = M.get_node_text(destination)
|
||||
|
||||
if dst_end < src_start then
|
||||
local diff_rows, diff_cols = M.range_difference(source, destination)
|
||||
local dst_range = M.replace_node(buf, source, destination)
|
||||
--local src_range = M.replace_node_text(buf, {src_start_row + diff_rows,
|
||||
--src_start_col + (source:start() == destination:end_() and diff_cols or 0),
|
||||
--src_end_row + diff_rows,
|
||||
--(source:end_() == destination:end_() and diff_cols or 0)}, destination_text)
|
||||
return src_range, dst_range
|
||||
elseif src_end < dst_start then
|
||||
local diff_rows, diff_cols = M.range_difference(destination, source)
|
||||
local src_range = M.replace_node(buf, destination, source)
|
||||
--local dst_range = M.replace_node_text(buf, {dst_start_row + diff_rows,
|
||||
--dst_start_col + (destination:start() == source:end_() and diff_cols or 0),
|
||||
--dst_end_row + diff_rows,
|
||||
--(destination:end_() == source:end_() and diff_cols or 0)}, source_text)
|
||||
return src_range, dst_range
|
||||
end
|
||||
local dst_range
|
||||
|
||||
if dst_end <= src_start then
|
||||
M.replace_node_text(buf, source, destination_text)
|
||||
dst_range = M.replace_node_text(buf, destination, source_text)
|
||||
return
|
||||
elseif src_end <= dst_start then
|
||||
dst_range = M.replace_node_text(buf, destination, source_text)
|
||||
M.replace_node_text(buf, source, destination_text)
|
||||
end
|
||||
return dst_range
|
||||
end
|
||||
|
||||
|
||||
--- Get tree sitter node in LSP range
|
||||
-- root Root of parsed tree
|
||||
-- lsp_range A LSP range
|
||||
function M.node_from_lsp_range(root, lsp_range)
|
||||
return root:named_descendant_for_range(lsp_range.start.line,
|
||||
lsp_range.start.character,
|
||||
lsp_range['end'].line,
|
||||
lsp_range['end'].character)
|
||||
end
|
||||
|
||||
function M.setup_commands(mod, commands)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue