refactor(pos): move get_lines from lsp.util to pos

This commit is contained in:
Yi Ming
2026-05-15 19:16:10 +08:00
parent 6f5ba9ebf6
commit 1c687c76b0
2 changed files with 99 additions and 96 deletions

View File

@@ -133,98 +133,9 @@ local function sort_by_key(fn)
end
end
--- Gets the zero-indexed lines from the given buffer.
--- Works on unloaded buffers by reading the file using libuv to bypass buf reading events.
--- Falls back to loading the buffer and nvim_buf_get_lines for buffers with non-file URI.
---
---@param bufnr integer bufnr to get the lines from
---@param rows integer[] zero-indexed line numbers
---@return table<integer, string> # a table mapping rows to lines
local function get_lines(bufnr, rows)
--- @type integer[]
rows = type(rows) == 'table' and rows or { rows }
local get_lines = vim.pos._get_lines
-- This is needed for bufload and bufloaded
bufnr = vim._resolve_bufnr(bufnr)
local function buf_lines()
local lines = {} --- @type table<integer,string>
for _, row in ipairs(rows) do
lines[row] = (api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
end
return lines
end
-- use loaded buffers if available
if vim.fn.bufloaded(bufnr) == 1 then
return buf_lines()
end
local uri = vim.uri_from_bufnr(bufnr)
-- load the buffer if this is not a file uri
-- Custom language server protocol extensions can result in servers sending URIs with custom schemes. Plugins are able to load these via `BufReadCmd` autocmds.
if uri:sub(1, 4) ~= 'file' then
vim.fn.bufload(bufnr)
return buf_lines()
end
local filename = api.nvim_buf_get_name(bufnr)
if vim.fn.isdirectory(filename) ~= 0 then
return {}
end
-- get the data from the file
local fd = uv.fs_open(filename, 'r', 438)
if not fd then
return {}
end
local stat = assert(uv.fs_fstat(fd))
local data = assert(uv.fs_read(fd, stat.size, 0))
uv.fs_close(fd)
local lines = {} --- @type table<integer,true|string> rows we need to retrieve
local need = 0 -- keep track of how many unique rows we need
for _, row in pairs(rows) do
if not lines[row] then
need = need + 1
end
lines[row] = true
end
local found = 0
local lnum = 0
for line in string.gmatch(data, '([^\n]*)\n?') do
if lines[lnum] == true then
lines[lnum] = line
found = found + 1
if found == need then
break
end
end
lnum = lnum + 1
end
-- change any lines we didn't find to the empty string
for i, line in pairs(lines) do
if line == true then
lines[i] = ''
end
end
return lines --[[@as table<integer,string>]]
end
--- Gets the zero-indexed line from the given buffer.
--- Works on unloaded buffers by reading the file using libuv to bypass buf reading events.
--- Falls back to loading the buffer and nvim_buf_get_lines for buffers with non-file URI.
---
---@param bufnr integer
---@param row integer zero-indexed line number
---@return string the line at row in filename
local function get_line(bufnr, row)
return get_lines(bufnr, { row })[row]
end
local get_line = vim.pos._get_line
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
---@param position lsp.Position