diff options
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/nvim-treesitter/incremental_selection.lua | 36 | ||||
| -rw-r--r-- | lua/nvim-treesitter/ts_utils.lua | 44 |
2 files changed, 38 insertions, 42 deletions
diff --git a/lua/nvim-treesitter/incremental_selection.lua b/lua/nvim-treesitter/incremental_selection.lua index eb8b49961..857f4a482 100644 --- a/lua/nvim-treesitter/incremental_selection.lua +++ b/lua/nvim-treesitter/incremental_selection.lua @@ -17,9 +17,9 @@ function M.init_selection() ts_utils.update_selection(buf, node) end ---- Get a ts compatible range of the current visual selection. +--- Get the range of the current visual selection. -- --- The range of ts nodes start with 0 and the ending range is exclusive. +-- The range start with 1 and the ending is inclusive. local function visual_selection_range() local _, csrow, cscol, _ = unpack(vim.fn.getpos "'<") local _, cerow, cecol, _ = unpack(vim.fn.getpos "'>") @@ -27,33 +27,23 @@ local function visual_selection_range() local start_row, start_col, end_row, end_col if csrow < cerow or (csrow == cerow and cscol <= cecol) then - start_row = csrow - 1 - start_col = cscol - 1 - end_row = cerow - 1 + start_row = csrow + start_col = cscol + end_row = cerow end_col = cecol else - start_row = cerow - 1 - start_col = cecol - 1 - end_row = csrow - 1 + start_row = cerow + start_col = cecol + end_row = csrow end_col = cscol end - -- The last char in ts is equivalent to the EOF in another line. - local last_row = vim.fn.line "$" - local last_col = vim.fn.col { last_row, "$" } - last_row = last_row - 1 - last_col = last_col - 1 - if end_row == last_row and end_col == last_col then - end_row = end_row + 1 - end_col = 0 - end - return start_row, start_col, end_row, end_col end local function range_matches(node) local csrow, cscol, cerow, cecol = visual_selection_range() - local srow, scol, erow, ecol = node:range() + local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() } return srow == csrow and scol == cscol and erow == cerow and ecol == cecol end @@ -66,7 +56,7 @@ local function select_incremental(get_parent) -- Initialize incremental selection with current selection if not nodes or #nodes == 0 or not range_matches(nodes[#nodes]) then local root = parsers.get_parser():parse()[1]:root() - local node = root:named_descendant_for_range(csrow, cscol, cerow, cecol) + local node = root:named_descendant_for_range(csrow - 1, cscol - 1, cerow - 1, cecol) ts_utils.update_selection(buf, node) if nodes and #nodes > 0 then table.insert(selections[buf], node) @@ -84,14 +74,14 @@ local function select_incremental(get_parent) -- Keep searching in the main tree -- TODO: we should search on the parent tree of the current node. local root = parsers.get_parser():parse()[1]:root() - parent = root:named_descendant_for_range(csrow, cscol, cerow, cecol) - if not parent or parent == node then + parent = root:named_descendant_for_range(csrow - 1, cscol - 1, cerow - 1, cecol) + if not parent or root == node or parent == node then ts_utils.update_selection(buf, node) return end end node = parent - local srow, scol, erow, ecol = node:range() + local srow, scol, erow, ecol = ts_utils.get_vim_range { node:range() } local same_range = (srow == csrow and scol == cscol and erow == cerow and ecol == cecol) if not same_range then table.insert(selections[buf], node) diff --git a/lua/nvim-treesitter/ts_utils.lua b/lua/nvim-treesitter/ts_utils.lua index 11fb17d78..b17eccc6c 100644 --- a/lua/nvim-treesitter/ts_utils.lua +++ b/lua/nvim-treesitter/ts_utils.lua @@ -175,6 +175,29 @@ function M.highlight_node(node, buf, hl_namespace, hl_group) M.highlight_range({ node:range() }, buf, hl_namespace, hl_group) end +--- Get a compatible vim range (1 index based) from a TS node range. +-- +-- TS nodes start with 0 and the end col is ending exclusive. +-- They also treat a EOF/EOL char as a char ending in the first +-- col of the next row. +function M.get_vim_range(range, buf) + local srow, scol, erow, ecol = unpack(range) + srow = srow + 1 + scol = scol + 1 + erow = erow + 1 + + if ecol == 0 then + -- Use the value of the last col of the previous row instead. + erow = erow - 1 + if not buf or buf == 0 then + ecol = vim.fn.col { erow, "$" } - 1 + else + ecol = #api.nvim_buf_get_lines(buf, erow - 1, erow, false)[1] + end + end + return srow, scol, erow, ecol +end + function M.highlight_range(range, buf, hl_namespace, hl_group) local start_row, start_col, end_row, end_col = unpack(range) vim.highlight.range(buf, hl_namespace, hl_group, { start_row, start_col }, { end_row, end_col }) @@ -185,17 +208,7 @@ end -- "blockwise" or "<C-v>" (as a string with 5 characters or a single character) function M.update_selection(buf, node, selection_mode) selection_mode = selection_mode or "charwise" - local start_row, start_col, end_row, end_col = M.get_node_range(node) - - if end_row == vim.fn.line "$" then - end_col = #vim.fn.getline "$" - end - - -- Convert to 1-based indices - start_row = start_row + 1 - start_col = start_col + 1 - end_row = end_row + 1 - end_col = end_col + 1 + local start_row, start_col, end_row, end_col = M.get_vim_range({ M.get_node_range(node) }, buf) vim.fn.setpos(".", { buf, start_row, start_col, 0 }) @@ -205,14 +218,7 @@ function M.update_selection(buf, node, selection_mode) ---- command to enter blockwise mode local mode_string = vim.api.nvim_replace_termcodes(v_table[selection_mode] or selection_mode, true, true, true) vim.cmd("normal! " .. mode_string) - - -- Convert exclusive end position to inclusive - if end_col == 1 then - local previous_col = vim.fn.col { end_row - 1, "$" } - 1 - vim.fn.setpos(".", { buf, end_row - 1, previous_col, 0 }) - else - vim.fn.setpos(".", { buf, end_row, end_col - 1, 0 }) - end + vim.fn.setpos(".", { buf, end_row, end_col, 0 }) end -- Byte length of node range |
