mirror of
https://github.com/neovim/neovim.git
synced 2026-06-15 16:23:48 +00:00
feat(pos): pos:to_offset(), pos.offset() (#39639)
Problem:
For a given position, it is not easy to compare which of several other positions is closest to it.
Solution:
Add support for converting `vim.Pos` to a buffer byte offset.
This allows for sorting, e.g:
```lua
table.sort(positions, function(pos1, pos2)
return pos1:to_offset() < pos2:to_offset()
end
```
Or a binary search, e.g:
```lua
vim.list.bisect(positions, pos, { key = function(pos) return pos:to_offset() end })
```
Co-authored-by: Yi Ming <ofseed@foxmail.com>
This commit is contained in:
@@ -4324,6 +4324,16 @@ lsp({buf}, {pos}, {position_encoding}) *vim.pos.lsp()*
|
||||
• {pos} (`lsp.Position`)
|
||||
• {position_encoding} (`lsp.PositionEncodingKind`)
|
||||
|
||||
offset({buf}, {offset}) *vim.pos.offset()*
|
||||
Creates a new |vim.Pos| from buffer offset.
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer`)
|
||||
• {offset} (`integer`)
|
||||
|
||||
Return: ~
|
||||
(`vim.Pos`) See |vim.Pos|.
|
||||
|
||||
to_cursor({pos}) *vim.pos.to_cursor()*
|
||||
Converts |vim.Pos| to cursor position (see |api-indexing|).
|
||||
|
||||
@@ -4358,6 +4368,15 @@ to_lsp({pos}, {position_encoding}) *vim.pos.to_lsp()*
|
||||
• {pos} (`vim.Pos`) See |vim.Pos|.
|
||||
• {position_encoding} (`lsp.PositionEncodingKind`)
|
||||
|
||||
to_offset({pos}) *vim.pos.to_offset()*
|
||||
Converts |vim.Pos| to buffer offset.
|
||||
|
||||
Parameters: ~
|
||||
• {pos} (`vim.Pos`) See |vim.Pos|.
|
||||
|
||||
Return: ~
|
||||
(`integer`)
|
||||
|
||||
|
||||
==============================================================================
|
||||
Lua module: vim.range *vim.range*
|
||||
|
||||
@@ -309,8 +309,8 @@ LUA
|
||||
• |vim.filetype.inspect()| returns a copy of the internal tables used for
|
||||
filetype detection.
|
||||
• Added `__eq` metamethod to |vim.VersionRange|. 2 distinct but representing
|
||||
the same range instances now compare equal.
|
||||
|
||||
the same range instances now compare equal.
|
||||
• |vim.pos| can now convert between positions and buffer offsets.
|
||||
|
||||
OPTIONS
|
||||
|
||||
|
||||
@@ -225,6 +225,33 @@ function M.extmark(buf, row, col)
|
||||
return M.new(buf, row, col)
|
||||
end
|
||||
|
||||
--- Converts |vim.Pos| to buffer offset.
|
||||
---@param pos vim.Pos
|
||||
---@return integer
|
||||
function M.to_offset(pos)
|
||||
return api.nvim_buf_get_offset(pos.buf, pos[1]) + pos[2]
|
||||
end
|
||||
|
||||
--- Creates a new |vim.Pos| from buffer offset.
|
||||
---@param buf integer
|
||||
---@param offset integer
|
||||
---@return vim.Pos
|
||||
function M.offset(buf, offset)
|
||||
local lnum = vim.list.bisect(
|
||||
setmetatable({}, {
|
||||
__index = function(_, lnum)
|
||||
return api.nvim_buf_get_offset(buf, lnum - 1)
|
||||
end,
|
||||
}),
|
||||
offset,
|
||||
{ lo = 1, hi = api.nvim_buf_line_count(buf) + 2, bound = 'upper' }
|
||||
) - 1
|
||||
|
||||
local row = lnum - 1
|
||||
local col = offset - api.nvim_buf_get_offset(buf, row)
|
||||
return M.new(buf, row, col)
|
||||
end
|
||||
|
||||
-- Overload `Range.new` to allow calling this module as a function.
|
||||
setmetatable(M, {
|
||||
__call = function(_, ...)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
local t = require('test.testutil')
|
||||
local n = require('test.functional.testnvim')()
|
||||
local eq = t.eq
|
||||
local dedent = t.dedent
|
||||
|
||||
local clear = n.clear
|
||||
local exec_lua = n.exec_lua
|
||||
@@ -120,4 +121,40 @@ describe('vim.pos', function()
|
||||
end)
|
||||
eq({ 0, 9, buf }, pos2)
|
||||
end)
|
||||
|
||||
it('converts between vim.Pos and buffer offset', function()
|
||||
local buf = exec_lua(function()
|
||||
return vim.api.nvim_get_current_buf()
|
||||
end)
|
||||
insert(dedent [[
|
||||
first
|
||||
second
|
||||
third
|
||||
]])
|
||||
|
||||
local offsets = exec_lua(function()
|
||||
return {
|
||||
vim.pos(buf, 0, 0):to_offset(),
|
||||
vim.pos(buf, 0, 3):to_offset(),
|
||||
vim.pos(buf, 1, 0):to_offset(),
|
||||
vim.pos(buf, 3, 0):to_offset(),
|
||||
}
|
||||
end)
|
||||
eq({ 0, 3, 6, 19 }, offsets)
|
||||
|
||||
local positions = exec_lua(function()
|
||||
return {
|
||||
vim.pos.offset(buf, 0),
|
||||
vim.pos.offset(buf, 3),
|
||||
vim.pos.offset(buf, 6),
|
||||
vim.pos.offset(buf, 19),
|
||||
}
|
||||
end)
|
||||
eq({
|
||||
{ 0, 0, buf },
|
||||
{ 0, 3, buf },
|
||||
{ 1, 0, buf },
|
||||
{ 3, 0, buf },
|
||||
}, positions)
|
||||
end)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user