diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index cacc0fa169..4364f098f1 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -7,6 +7,7 @@ local lsp = vim.lsp local validate = vim.validate local util = require('vim.lsp.util') local npcall = vim.npcall +local Range = require('vim.treesitter._range') local M = {} @@ -1432,22 +1433,13 @@ local selection_ranges = nil ---@param range lsp.Range local function select_range(range) - local start_line = range.start.line + 1 - local end_line = range['end'].line + 1 + local start_line = range.start.line + local end_line = range['end'].line local start_col = range.start.character local end_col = range['end'].character - -- If the selection ends at column 0, adjust the position to the end of the previous line. - if end_col == 0 then - end_line = end_line - 1 - local end_line_text = api.nvim_buf_get_lines(0, end_line - 1, end_line, true)[1] - end_col = #end_line_text - end - - vim.fn.setpos("'<", { 0, start_line, start_col + 1, 0 }) - vim.fn.setpos("'>", { 0, end_line, end_col, 0 }) - vim.cmd.normal({ 'gv', bang = true }) + Range.visual_select({ start_line, start_col, end_line, end_col }) end ---@param range lsp.Range diff --git a/runtime/lua/vim/treesitter/_range.lua b/runtime/lua/vim/treesitter/_range.lua index b37135efc7..e6ee89d19e 100644 --- a/runtime/lua/vim/treesitter/_range.lua +++ b/runtime/lua/vim/treesitter/_range.lua @@ -172,4 +172,40 @@ function M.add_bytes(source, range) return { start_row, start_col, start_byte, end_row, end_col, end_byte } end +---@param range Range +function M.visual_select(range) + local start_row, start_col, end_row, end_col = M.unpack4(range) + + -- If the selection ends at column 0, adjust the position to the end of the previous line. + if end_col == 0 then + end_row = end_row - 1 + end_col = #vim.fn.getline(end_row + 1) + 1 + end + + if vim.fn.visualmode() ~= 'v' then + -- Reset visualmode() to 'v' + vim.cmd.normal({ 'v\27', bang = true }) + end + + local cursor_other_end_of_selection = false + local visual_col, visual_row = vim.fn.col('v'), vim.fn.line('v') + local cursor_col, cursor_row = vim.fn.col('.'), vim.fn.line('.') + if M.cmp_pos.gt(visual_row, visual_col, cursor_row, cursor_col) then + cursor_other_end_of_selection = true + end + + if vim.o.selection == 'exclusive' then + end_col = end_col + 1 + end + + vim.fn.setpos("'<", { 0, start_row + 1, start_col + 1, 0 }) + vim.fn.setpos("'>", { 0, end_row + 1, end_col, 0 }) + + if cursor_other_end_of_selection then + vim.cmd.normal({ 'gvo', bang = true }) + else + vim.cmd.normal({ 'gv', bang = true }) + end +end + return M diff --git a/runtime/lua/vim/treesitter/_select.lua b/runtime/lua/vim/treesitter/_select.lua index 2fb5fc1561..e77e51a0c5 100644 --- a/runtime/lua/vim/treesitter/_select.lua +++ b/runtime/lua/vim/treesitter/_select.lua @@ -348,36 +348,6 @@ local function node_normalize_down(node) return node end -local function visual_select(range) - assert(type(range) == 'table') - local srow, scol, erow, ecol = Range.unpack4(range) - local cursor_other_end_of_visual = false - - local vcol, vrow = vim.fn.col('v'), vim.fn.line('v') - local ccol, cline = vim.fn.col('.'), vim.fn.line('.') - if vrow > cline or (vrow == cline and vcol > ccol) then - cursor_other_end_of_visual = true - end - - if ecol == 0 then - erow = erow - 1 - ecol = #vim.fn.getline(erow + 1) + 1 - end - - if vim.fn.visualmode() ~= 'v' then - -- reset visualmode() to 'v' - vim.cmd.normal({ 'v\27', bang = true }) - end - - vim.fn.setpos("'<", { 0, srow + 1, scol + 1, 0 }) - vim.fn.setpos("'>", { 0, erow + 1, ecol, 0 }) - if cursor_other_end_of_visual then - vim.cmd.normal({ 'gvo', bang = true }) - else - vim.cmd.normal({ 'gv', bang = true }) - end -end - --- @return Range4 local function get_selection() local pos1 = vim.fn.getpos('v') @@ -387,6 +357,10 @@ local function get_selection() pos1, pos2 = pos2, pos1 end + if vim.o.selection == 'exclusive' then + pos2[3] = pos2[3] - 1 + end + if pos2[3] == #vim.fn.getline(pos2[2]) + 1 then pos2[2] = pos2[2] + 1 pos2[3] = 0 @@ -596,7 +570,7 @@ local function repeate_apply_range(count, fn) end if range and count ~= 0 then - visual_select(range) + Range.visual_select(range) end end diff --git a/test/functional/plugin/lsp/selection_range_spec.lua b/test/functional/plugin/lsp/selection_range_spec.lua index 04a354ce56..e9989aaa24 100644 --- a/test/functional/plugin/lsp/selection_range_spec.lua +++ b/test/functional/plugin/lsp/selection_range_spec.lua @@ -48,7 +48,7 @@ describe('vim.lsp.selection_range', function() parent = { range = { start = { line = 0, character = 0 }, - ['end'] = { line = 5, character = 5 }, + ['end'] = { line = 4, character = 5 }, }, parent = nil, },