mirror of
https://github.com/neovim/neovim.git
synced 2026-05-24 05:40:08 +00:00
Merge #39822 from ofseed/pos-mark
feat(pos,range): pos:to_mark(), pos.mark(), range:to_mark(), range.mark()
This commit is contained in:
@@ -38,6 +38,10 @@ LUA
|
||||
• vim.F.npcall() Renamed to |vim.npcall()|
|
||||
• vim.F.nil_wrap() Use |vim.npcall()| instead
|
||||
|
||||
LSP
|
||||
|
||||
• vim.lsp.util.character_offset() Use to |vim.str_utfindex()| instead
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
DEPRECATED IN 0.12 *deprecated-0.12*
|
||||
|
||||
|
||||
@@ -2941,20 +2941,6 @@ buf_highlight_references({bufnr}, {references}, {position_encoding})
|
||||
See also: ~
|
||||
• https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
|
||||
|
||||
*vim.lsp.util.character_offset()*
|
||||
character_offset({buf}, {row}, {col}, {position_encoding})
|
||||
Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer.
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer`) buffer number (0 for current)
|
||||
• {row} (`integer`) 0-indexed line
|
||||
• {col} (`integer`) 0-indexed byte offset in line
|
||||
• {position_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
|
||||
|
||||
Return: ~
|
||||
(`integer`) `position_encoding` index of the character in line {row}
|
||||
column {col} in buffer {buf}
|
||||
|
||||
*vim.lsp.util.convert_input_to_markdown_lines()*
|
||||
convert_input_to_markdown_lines({input}, {contents})
|
||||
Converts any of `MarkedString` | `MarkedString[]` | `MarkupContent` into a
|
||||
|
||||
@@ -4539,6 +4539,14 @@ lsp({buf}, {pos}, {position_encoding}) *vim.pos.lsp()*
|
||||
• {pos} (`lsp.Position`)
|
||||
• {position_encoding} (`lsp.PositionEncodingKind`)
|
||||
|
||||
mark({buf}, {row}, {col}) *vim.pos.mark()*
|
||||
Creates a new |vim.Pos| from mark position (see |api-indexing|).
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer`)
|
||||
• {row} (`integer`)
|
||||
• {col} (`integer`)
|
||||
|
||||
offset({buf}, {offset}) *vim.pos.offset()*
|
||||
Creates a new |vim.Pos| from buffer offset.
|
||||
|
||||
@@ -4583,6 +4591,16 @@ to_lsp({pos}, {position_encoding}) *vim.pos.to_lsp()*
|
||||
• {pos} (`vim.Pos`) See |vim.Pos|.
|
||||
• {position_encoding} (`lsp.PositionEncodingKind`)
|
||||
|
||||
to_mark({pos}) *vim.pos.to_mark()*
|
||||
Converts |vim.Pos| to mark position (see |api-indexing|).
|
||||
|
||||
Parameters: ~
|
||||
• {pos} (`vim.Pos`) See |vim.Pos|.
|
||||
|
||||
Return (multiple): ~
|
||||
(`integer`)
|
||||
(`integer`)
|
||||
|
||||
to_offset({pos}) *vim.pos.to_offset()*
|
||||
Converts |vim.Pos| to buffer offset.
|
||||
|
||||
@@ -4719,6 +4737,26 @@ lsp({buf}, {range}, {position_encoding}) *vim.range.lsp()*
|
||||
• {range} (`lsp.Range`)
|
||||
• {position_encoding} (`lsp.PositionEncodingKind`)
|
||||
|
||||
*vim.range.mark()*
|
||||
mark({buf}, {start_row}, {start_col}, {end_row}, {end_col})
|
||||
Creates a new |vim.Range| from "mark-indexed" range (see |api-indexing|).
|
||||
|
||||
Example: >lua
|
||||
-- A range represented by marks may be end-inclusive (decided by 'selection' option).
|
||||
local start_row, start_col = unpack(api.nvim_buf_get_mark(bufnr, '<'))
|
||||
local end_row, end_col = unpack(api.nvim_buf_get_mark(bufnr, '>'))
|
||||
|
||||
-- Create an end-exclusive range.
|
||||
local range = vim.range.mark(0, start_row, start_col, end_row, end_col)
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {buf} (`integer`)
|
||||
• {start_row} (`integer`)
|
||||
• {start_col} (`integer`)
|
||||
• {end_row} (`integer`)
|
||||
• {end_col} (`integer`)
|
||||
|
||||
to_cursor({range}) *vim.range.to_cursor()*
|
||||
Converts |vim.Range| to mark-like range (see |api-indexing|).
|
||||
|
||||
@@ -4762,6 +4800,25 @@ to_lsp({range}, {position_encoding}) *vim.range.to_lsp()*
|
||||
Return: ~
|
||||
(`lsp.Range`)
|
||||
|
||||
to_mark({range}) *vim.range.to_mark()*
|
||||
Converts |vim.Range| to extmark range (see |api-indexing|).
|
||||
|
||||
Example: >lua
|
||||
local range = vim.range(0, 3, 5, 4, 0)
|
||||
|
||||
-- Convert to mark range, you can call it in a method style.
|
||||
local start_row, start_col, end_row, end_col = range:to_mark()
|
||||
<
|
||||
|
||||
Parameters: ~
|
||||
• {range} (`vim.Range`) See |vim.Range|.
|
||||
|
||||
Return (multiple): ~
|
||||
(`integer`)
|
||||
(`integer`)
|
||||
(`integer`)
|
||||
(`integer`)
|
||||
|
||||
|
||||
==============================================================================
|
||||
Lua module: vim.re *vim.re*
|
||||
|
||||
@@ -203,6 +203,7 @@ LUA
|
||||
• |vim.log| for easily creating loggers.
|
||||
• |vim.pack.get()| output includes revision of a pending update.
|
||||
• |vim.pack.get()| can fetch new updates before computing the output.
|
||||
• |vim.pos| and |vim.range| can now convert between mark positions.
|
||||
|
||||
OPTIONS
|
||||
|
||||
|
||||
@@ -1856,32 +1856,11 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, position_encoding)
|
||||
validate('position_encoding', position_encoding, 'string')
|
||||
|
||||
bufnr = vim._resolve_bufnr(bufnr)
|
||||
--- @type [integer, integer]
|
||||
local A = { unpack(start_pos or api.nvim_buf_get_mark(bufnr, '<')) }
|
||||
--- @type [integer, integer]
|
||||
local B = { unpack(end_pos or api.nvim_buf_get_mark(bufnr, '>')) }
|
||||
-- convert to 0-index
|
||||
A[1] = A[1] - 1
|
||||
B[1] = B[1] - 1
|
||||
-- account for position_encoding.
|
||||
if A[2] > 0 then
|
||||
A[2] = M.character_offset(bufnr, A[1], A[2], position_encoding)
|
||||
end
|
||||
if B[2] > 0 then
|
||||
B[2] = M.character_offset(bufnr, B[1], B[2], position_encoding)
|
||||
end
|
||||
-- we need to offset the end character position otherwise we loose the last
|
||||
-- character of the selection, as LSP end position is exclusive
|
||||
-- see https://microsoft.github.io/language-server-protocol/specification#range
|
||||
if vim.o.selection ~= 'exclusive' then
|
||||
B[2] = B[2] + 1
|
||||
end
|
||||
local start_row, start_col = unpack(start_pos or api.nvim_buf_get_mark(bufnr, '<'))
|
||||
local end_row, end_col = unpack(end_pos or api.nvim_buf_get_mark(bufnr, '>'))
|
||||
return {
|
||||
textDocument = M.make_text_document_params(bufnr),
|
||||
range = {
|
||||
start = { line = A[1], character = A[2] },
|
||||
['end'] = { line = B[1], character = B[2] },
|
||||
},
|
||||
range = vim.range.mark(bufnr, start_row, start_col, end_row, end_col):to_lsp(position_encoding),
|
||||
}
|
||||
end
|
||||
|
||||
@@ -1933,12 +1912,14 @@ end
|
||||
|
||||
--- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer.
|
||||
---
|
||||
---@deprecated
|
||||
---@param buf integer buffer number (0 for current)
|
||||
---@param row integer 0-indexed line
|
||||
---@param col integer 0-indexed byte offset in line
|
||||
---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
|
||||
---@return integer `position_encoding` index of the character in line {row} column {col} in buffer {buf}
|
||||
function M.character_offset(buf, row, col, position_encoding)
|
||||
vim.deprecate('vim.lsp.util.character_offset', 'vim.str_utfindex', '0.14')
|
||||
vim.validate('position_encoding', position_encoding, 'string')
|
||||
|
||||
local line = get_line(buf, row)
|
||||
|
||||
@@ -291,6 +291,25 @@ function M.cursor(buf, pos)
|
||||
return M.new(buf, pos[1] - 1, pos[2])
|
||||
end
|
||||
|
||||
--- Converts |vim.Pos| to mark position (see |api-indexing|).
|
||||
---@param pos vim.Pos
|
||||
---@return integer, integer
|
||||
function M.to_mark(pos)
|
||||
return pos[1] + 1, pos[2]
|
||||
end
|
||||
|
||||
--- Creates a new |vim.Pos| from mark position (see |api-indexing|).
|
||||
---@param buf integer
|
||||
---@param row integer
|
||||
---@param col integer
|
||||
function M.mark(buf, row, col)
|
||||
if buf == 0 then
|
||||
buf = api.nvim_get_current_buf()
|
||||
end
|
||||
|
||||
return M.new(buf, row - 1, col)
|
||||
end
|
||||
|
||||
--- Converts |vim.Pos| to extmark position (see |api-indexing|).
|
||||
---@param pos vim.Pos
|
||||
---@return integer, integer
|
||||
|
||||
@@ -150,11 +150,28 @@ end
|
||||
---@param buf integer
|
||||
---@return integer, integer
|
||||
local function to_inclusive_pos(buf, row, col)
|
||||
local line = get_line(buf, row)
|
||||
if col > 0 then
|
||||
col = col - 1
|
||||
col = col + vim.str_utf_start(line, col) - 1
|
||||
elseif col == 0 and row > 0 then
|
||||
row = row - 1
|
||||
col = #get_line(buf, row)
|
||||
col = #line > 0 and #line + vim.str_utf_start(line, #line) - 1 or 0
|
||||
end
|
||||
|
||||
return row, col
|
||||
end
|
||||
|
||||
---@param row integer
|
||||
---@param col integer
|
||||
---@param buf integer
|
||||
---@return integer, integer
|
||||
local function to_exclusive_pos(buf, row, col)
|
||||
local line = get_line(buf, row)
|
||||
if col >= #line then
|
||||
row = row + 1
|
||||
col = 0
|
||||
else
|
||||
col = col + vim.str_utf_end(line, col + 1) + 1
|
||||
end
|
||||
|
||||
return row, col
|
||||
@@ -164,7 +181,7 @@ end
|
||||
---@param r1 vim.Range
|
||||
---@param r2 vim.Range
|
||||
function M.__lt(r1, r2)
|
||||
if r1:is_empty() then
|
||||
if r1:is_empty() or r2:is_empty() then
|
||||
return cmp_pos(r1[3], r1[4], r2[1], r2[2]) ~= 1
|
||||
end
|
||||
|
||||
@@ -176,7 +193,7 @@ end
|
||||
---@param r1 vim.Range
|
||||
---@param r2 vim.Range
|
||||
function M.__le(r1, r2)
|
||||
if r1:is_empty() then
|
||||
if r1:is_empty() or r2:is_empty() then
|
||||
return cmp_pos(r1[3], r1[4], r2[1], r2[2]) ~= 1
|
||||
end
|
||||
|
||||
@@ -314,6 +331,67 @@ function M.lsp(buf, range, position_encoding)
|
||||
return M.new(start, end_)
|
||||
end
|
||||
|
||||
--- Converts |vim.Range| to extmark range (see |api-indexing|).
|
||||
---
|
||||
--- Example:
|
||||
--- ```lua
|
||||
--- local range = vim.range(0, 3, 5, 4, 0)
|
||||
---
|
||||
--- -- Convert to mark range, you can call it in a method style.
|
||||
--- local start_row, start_col, end_row, end_col = range:to_mark()
|
||||
--- ```
|
||||
---@param range vim.Range
|
||||
---@return integer, integer, integer, integer
|
||||
function M.to_mark(range)
|
||||
validate('range', range, 'table')
|
||||
|
||||
local buf = range.buf
|
||||
local start_row, start_col, end_row, end_col = range[1], range[2], range[3], range[4]
|
||||
if vim.o.selection ~= 'exclusive' then
|
||||
end_row, end_col = to_inclusive_pos(buf, end_row, end_col)
|
||||
end
|
||||
|
||||
start_row, start_col = vim.pos(buf, start_row, start_col):to_mark()
|
||||
end_row, end_col = vim.pos(buf, end_row, end_col):to_mark()
|
||||
return start_row, start_col, end_row, end_col
|
||||
end
|
||||
|
||||
--- Creates a new |vim.Range| from "mark-indexed" range (see |api-indexing|).
|
||||
---
|
||||
--- Example:
|
||||
--- ```lua
|
||||
--- -- A range represented by marks may be end-inclusive (decided by 'selection' option).
|
||||
--- local start_row, start_col = unpack(api.nvim_buf_get_mark(bufnr, '<'))
|
||||
--- local end_row, end_col = unpack(api.nvim_buf_get_mark(bufnr, '>'))
|
||||
---
|
||||
--- -- Create an end-exclusive range.
|
||||
--- local range = vim.range.mark(0, start_row, start_col, end_row, end_col)
|
||||
--- ```
|
||||
---@param buf integer
|
||||
---@param start_row integer
|
||||
---@param start_col integer
|
||||
---@param end_row integer
|
||||
---@param end_col integer
|
||||
function M.mark(buf, start_row, start_col, end_row, end_col)
|
||||
validate('buf', buf, 'number')
|
||||
validate('start_row', start_row, 'number')
|
||||
validate('start_col', start_col, 'number')
|
||||
validate('end_row', end_row, 'number')
|
||||
validate('end_col', end_col, 'number')
|
||||
|
||||
if buf == 0 then
|
||||
buf = api.nvim_get_current_buf()
|
||||
end
|
||||
|
||||
local start = vim.pos.mark(buf, start_row, start_col)
|
||||
local end_ = vim.pos.mark(buf, end_row, end_col)
|
||||
|
||||
if vim.o.selection ~= 'exclusive' then
|
||||
end_[1], end_[2] = to_exclusive_pos(buf, end_[1], end_[2])
|
||||
end
|
||||
return M.new(start, end_)
|
||||
end
|
||||
|
||||
--- Converts |vim.Range| to extmark range (see |api-indexing|).
|
||||
---
|
||||
--- Example:
|
||||
|
||||
@@ -80,6 +80,18 @@ describe('vim.range', function()
|
||||
}, range)
|
||||
end)
|
||||
|
||||
it('converts between inclusive mark ranges ending on multibyte characters', function()
|
||||
insert('🙂')
|
||||
|
||||
local range, mark_range = exec_lua(function()
|
||||
vim.o.selection = 'inclusive'
|
||||
local range = vim.range.mark(0, 1, 0, 1, 0)
|
||||
return { range[1], range[2], range[3], range[4] }, { range:to_mark() }
|
||||
end)
|
||||
eq({ 0, 0, 0, 4 }, range)
|
||||
eq({ 1, 0, 1, 0 }, mark_range)
|
||||
end)
|
||||
|
||||
it('checks whether a range contains a position', function()
|
||||
eq(
|
||||
true,
|
||||
|
||||
@@ -1456,7 +1456,7 @@ describe('vim.lsp.buf', function()
|
||||
eq('textDocument/rangeFormatting', result[3].method)
|
||||
local expected_range = {
|
||||
start = { line = 0, character = 0 },
|
||||
['end'] = { line = 1, character = 4 },
|
||||
['end'] = { line = 2, character = 0 },
|
||||
}
|
||||
eq(expected_range, result[3].params.range)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user