From d40875a2f844d0005441aa0db47599e2f6b63be1 Mon Sep 17 00:00:00 2001 From: Yi Ming Date: Tue, 28 Apr 2026 01:43:46 +0800 Subject: [PATCH] perf(vim.pos): use numeric index internally #39447 --- runtime/lua/vim/pos.lua | 17 +++++----- runtime/lua/vim/range.lua | 71 ++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 51 deletions(-) diff --git a/runtime/lua/vim/pos.lua b/runtime/lua/vim/pos.lua index df5bd67f3a..a4c0f2d536 100644 --- a/runtime/lua/vim/pos.lua +++ b/runtime/lua/vim/pos.lua @@ -86,15 +86,15 @@ end --- 0: a == b --- -1: a < b local function cmp_pos(p1, p2) - if p1.row == p2.row then - if p1.col > p2.col then + if p1[1] == p2[1] then + if p1[2] > p2[2] then return 1 - elseif p1.col < p2.col then + elseif p1[2] < p2[2] then return -1 else return 0 end - elseif p1.row > p2.row then + elseif p1[1] > p2[1] then return 1 end @@ -138,7 +138,7 @@ function M.to_lsp(pos, position_encoding) validate('pos', pos, 'table') validate('position_encoding', position_encoding, 'string') - local buf, row, col = pos.buf, pos.row, pos.col + local buf, row, col = pos.buf, pos[1], pos[2] -- When on the first character, -- we can ignore the difference between byte and character. if col > 0 then @@ -188,7 +188,7 @@ end ---@param pos vim.Pos ---@return integer, integer function M.to_cursor(pos) - return pos.row + 1, pos.col + return pos[1] + 1, pos[2] end --- Creates a new |vim.Pos| from cursor position (see |api-indexing|). @@ -204,9 +204,8 @@ end function M.to_extmark(pos) local line_count = api.nvim_buf_line_count(pos.buf) - local row = pos.row - local col = pos.col - if pos.col == 0 and pos.row == line_count then + local row, col = pos[1], pos[2] + if col == 0 and row == line_count then row = row - 1 col = #get_line(pos.buf, row) end diff --git a/runtime/lua/vim/range.lua b/runtime/lua/vim/range.lua index a19259577c..9a8f1169a4 100644 --- a/runtime/lua/vim/range.lua +++ b/runtime/lua/vim/range.lua @@ -85,8 +85,7 @@ function M.new(...) if start.buf ~= end_.buf then error('start and end positions must belong to the same buffer') end - start_row, start_col, end_row, end_col, buf = - start.row, start.col, end_.row, end_.col, start.buf + start_row, start_col, end_row, end_col, buf = start[1], start[2], end_[1], end_[2], start.buf elseif nargs == 5 then ---@type integer, integer, integer, integer, integer buf, start_row, start_col, end_row, end_col = ... @@ -165,26 +164,23 @@ end ---@param r1 vim.Range ---@param r2 vim.Range function M.__lt(r1, r2) - local r1_inclusive_end_row, r1_inclusive_end_col = - to_inclusive_pos(r1.buf, r1.end_row, r1.end_col) - return cmp_pos(r1_inclusive_end_row, r1_inclusive_end_col, r2.start_row, r2.start_col) == -1 + local r1_inclusive_end_row, r1_inclusive_end_col = to_inclusive_pos(r1.buf, r1[3], r1[4]) + return cmp_pos(r1_inclusive_end_row, r1_inclusive_end_col, r2[1], r2[2]) == -1 end ---@private ---@param r1 vim.Range ---@param r2 vim.Range function M.__le(r1, r2) - local r1_inclusive_end_row, r1_inclusive_end_col = - to_inclusive_pos(r1.buf, r1.end_row, r1.end_col) - return cmp_pos(r1_inclusive_end_row, r1_inclusive_end_col, r2.start_row, r2.start_col) ~= 1 + local r1_inclusive_end_row, r1_inclusive_end_col = to_inclusive_pos(r1.buf, r1[3], r1[4]) + return cmp_pos(r1_inclusive_end_row, r1_inclusive_end_col, r2[1], r2[2]) ~= 1 end ---@private ---@param r1 vim.Range ---@param r2 vim.Range function M.__eq(r1, r2) - return cmp_pos(r1.start_row, r1.start_col, r2.start_row, r2.start_col) == 0 - and cmp_pos(r1.end_row, r1.end_col, r2.end_row, r2.end_col) == 0 + return cmp_pos(r1[1], r1[2], r2[1], r2[2]) == 0 and cmp_pos(r1[3], r1[4], r2[3], r2[4]) == 0 end --- Checks whether the given range is empty; i.e., start >= end. @@ -192,10 +188,9 @@ end ---@param range vim.Range ---@return boolean `true` if the given range is empty. function M.is_empty(range) - local inclusive_end_row, inclusive_end_col = - to_inclusive_pos(range.buf, range.end_row, range.end_col) + local inclusive_end_row, inclusive_end_col = to_inclusive_pos(range.buf, range[3], range[4]) - return cmp_pos(range.start_row, range.start_col, inclusive_end_row, inclusive_end_col) ~= -1 + return cmp_pos(range[1], range[2], inclusive_end_row, inclusive_end_col) ~= -1 end --- Checks whether {outer} range contains {inner} range or position. @@ -206,28 +201,22 @@ end function M.has(outer, inner) if getmetatable(inner) == vim.pos then ---@cast inner -vim.Range - return cmp_pos(outer.start_row, outer.start_col, inner.row, inner.col) ~= 1 - and cmp_pos(outer.end_row, outer.end_col, inner.row, inner.col) ~= -1 + return cmp_pos(outer[1], outer[2], inner[1], inner[2]) ~= 1 + and cmp_pos(outer[3], outer[4], inner[1], inner[2]) ~= -1 end ---@cast inner -vim.Pos local outer_inclusive_end_row, outer_inclusive_end_col = - to_inclusive_pos(outer.buf, outer.end_row, outer.end_col) + to_inclusive_pos(outer.buf, outer[3], outer[4]) local inner_inclusive_end_row, inner_inclusive_end_col = - to_inclusive_pos(inner.buf, inner.end_row, inner.end_col) + to_inclusive_pos(inner.buf, inner[3], inner[4]) - return cmp_pos(outer.start_row, outer.start_col, inner.start_row, inner.start_col) ~= 1 - and cmp_pos(outer.end_row, outer.end_col, inner.end_row, inner.end_col) ~= -1 + return cmp_pos(outer[1], outer[2], inner[1], inner[2]) ~= 1 + and cmp_pos(outer[3], outer[4], inner[3], inner[4]) ~= -1 -- accounts for empty ranges at the start/end of `outer` that per Neovim API and LSP logic -- insert the text outside `outer` - and cmp_pos(outer.start_row, outer.start_col, inner_inclusive_end_row, inner_inclusive_end_col) == -1 - and cmp_pos( - outer_inclusive_end_row, - outer_inclusive_end_col, - inner.start_row, - inner.start_col - ) - == 1 + and cmp_pos(outer[1], outer[2], inner_inclusive_end_row, inner_inclusive_end_col) == -1 + and cmp_pos(outer_inclusive_end_row, outer_inclusive_end_col, inner[1], inner[2]) == 1 end --- Computes the common range shared by the given ranges. @@ -241,21 +230,19 @@ function M.intersect(r1, r2) return nil end - local r1_inclusive_end_row, r1_inclusive_end_col = - to_inclusive_pos(r1.buf, r1.end_row, r1.end_col) - local r2_inclusive_end_row, r2_inclusive_end_col = - to_inclusive_pos(r2.buf, r2.end_row, r2.end_col) + local r1_inclusive_end_row, r1_inclusive_end_col = to_inclusive_pos(r1.buf, r1[3], r1[4]) + local r2_inclusive_end_row, r2_inclusive_end_col = to_inclusive_pos(r2.buf, r2[3], r2[4]) if - cmp_pos(r1_inclusive_end_row, r1_inclusive_end_col, r2.start_row, r2.start_col) ~= 1 - or cmp_pos(r1.start_row, r1.start_col, r2_inclusive_end_row, r2_inclusive_end_col) ~= -1 + cmp_pos(r1_inclusive_end_row, r1_inclusive_end_col, r2[1], r2[2]) ~= 1 + or cmp_pos(r1[1], r1[2], r2_inclusive_end_row, r2_inclusive_end_col) ~= -1 then return nil end - local rs = cmp_pos(r1.start_row, r1.start_col, r2.start_row, r2.start_col) ~= 1 and r2 or r1 - local re = cmp_pos(r1.end_row, r1.end_col, r2.end_row, r2.end_col) ~= -1 and r2 or r1 - return M.new(r1.buf, rs.start_row, rs.start_col, re.end_row, re.end_col) + local rs = cmp_pos(r1[1], r1[2], r2[1], r2[2]) ~= 1 and r2 or r1 + local re = cmp_pos(r1[3], r1[4], r2[3], r2[4]) ~= -1 and r2 or r1 + return M.new(r1.buf, rs[1], rs[2], re[3], re[4]) end --- Converts |vim.Range| to `lsp.Range`. @@ -276,8 +263,8 @@ function M.to_lsp(range, position_encoding) ---@type lsp.Range return { - ['start'] = vim.pos(range.buf, range.start_row, range.start_col):to_lsp(position_encoding), - ['end'] = vim.pos(range.buf, range.end_row, range.end_col):to_lsp(position_encoding), + ['start'] = vim.pos(range.buf, range[1], range[2]):to_lsp(position_encoding), + ['end'] = vim.pos(range.buf, range[3], range[4]):to_lsp(position_encoding), } end @@ -325,8 +312,8 @@ end function M.to_extmark(range) validate('range', range, 'table') - local srow, scol = vim.pos(range.buf, range.start_row, range.start_col):to_extmark() - local erow, ecol = vim.pos(range.buf, range.end_row, range.end_col):to_extmark() + local srow, scol = vim.pos(range.buf, range[1], range[2]):to_extmark() + local erow, ecol = vim.pos(range.buf, range[3], range[4]):to_extmark() return srow, scol, erow, ecol end @@ -371,8 +358,8 @@ end function M.to_cursor(range) validate('range', range, 'table') - local srow, scol = vim.pos(range.buf, range.start_row, range.start_col):to_cursor() - local erow, ecol = vim.pos(range.buf, range.end_row, range.end_col):to_cursor() + local srow, scol = vim.pos(range.buf, range[1], range[2]):to_cursor() + local erow, ecol = vim.pos(range.buf, range[3], range[4]):to_cursor() return srow, scol, erow, ecol end