refactor(lsp): rename offset_encoding to position_encoding #31286

Problem:
LSP spec uses the term "position encoding" where we say "offset encoding".

Solution:
- Rename it everywhere except `vim.lsp.Client.offset_encoding` (which would be breaking).
- Mention "position encoding" in the documentation for `vim.lsp.Client.offset_encoding`.
This commit is contained in:
Yi Ming 2024-11-26 00:06:05 +08:00 committed by GitHub
parent a811d4babd
commit 165b099fa3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 188 additions and 175 deletions

View File

@ -904,8 +904,9 @@ Lua module: vim.lsp.client *lsp-client*
• {rpc} (`vim.lsp.rpc.PublicClient`) RPC client • {rpc} (`vim.lsp.rpc.PublicClient`) RPC client
object, for low level interaction with the object, for low level interaction with the
client. See |vim.lsp.rpc.start()|. client. See |vim.lsp.rpc.start()|.
• {offset_encoding} (`string`) The encoding used for communicating • {offset_encoding} (`string`) Called "position encoding" in LSP
with the server. You can modify this in the spec, the encoding used for communicating with
the server. You can modify this in the
`config`'s `on_init` method before text is `config`'s `on_init` method before text is
sent to the server. sent to the server.
• {handlers} (`table<string,lsp.Handler>`) The handlers • {handlers} (`table<string,lsp.Handler>`) The handlers
@ -1062,9 +1063,10 @@ Lua module: vim.lsp.client *lsp-client*
• {get_language_id}? (`fun(bufnr: integer, filetype: string): string`) • {get_language_id}? (`fun(bufnr: integer, filetype: string): string`)
Language ID as string. Defaults to the buffer Language ID as string. Defaults to the buffer
filetype. filetype.
• {offset_encoding}? (`'utf-8'|'utf-16'|'utf-32'`) The encoding that • {offset_encoding}? (`'utf-8'|'utf-16'|'utf-32'`) Called "position
the LSP server expects. Client does not verify encoding" in LSP spec, the encoding that the LSP
this is correct. server expects. Client does not verify this is
correct.
• {on_error}? (`fun(code: integer, err: string)`) Callback • {on_error}? (`fun(code: integer, err: string)`) Callback
invoked when the client operation throws an invoked when the client operation throws an
error. `code` is a number describing the error. error. `code` is a number describing the error.
@ -1840,7 +1842,7 @@ Lua module: vim.lsp.util *lsp-util*
*vim.lsp.util.apply_text_document_edit()* *vim.lsp.util.apply_text_document_edit()*
apply_text_document_edit({text_document_edit}, {index}, {offset_encoding}) apply_text_document_edit({text_document_edit}, {index}, {position_encoding})
Applies a `TextDocumentEdit`, which is a list of changes to a single Applies a `TextDocumentEdit`, which is a list of changes to a single
document. document.
@ -1848,30 +1850,30 @@ apply_text_document_edit({text_document_edit}, {index}, {offset_encoding})
• {text_document_edit} (`lsp.TextDocumentEdit`) • {text_document_edit} (`lsp.TextDocumentEdit`)
• {index} (`integer?`) Optional index of the edit, if from • {index} (`integer?`) Optional index of the edit, if from
a list of edits (or nil, if not from a list) a list of edits (or nil, if not from a list)
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'?`)
See also: ~ See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
*vim.lsp.util.apply_text_edits()* *vim.lsp.util.apply_text_edits()*
apply_text_edits({text_edits}, {bufnr}, {offset_encoding}) apply_text_edits({text_edits}, {bufnr}, {position_encoding})
Applies a list of text edits to a buffer. Applies a list of text edits to a buffer.
Parameters: ~ Parameters: ~
• {text_edits} (`lsp.TextEdit[]`) • {text_edits} (`lsp.TextEdit[]`)
• {bufnr} (`integer`) Buffer id • {bufnr} (`integer`) Buffer id
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`) • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
See also: ~ See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
*vim.lsp.util.apply_workspace_edit()* *vim.lsp.util.apply_workspace_edit()*
apply_workspace_edit({workspace_edit}, {offset_encoding}) apply_workspace_edit({workspace_edit}, {position_encoding})
Applies a `WorkspaceEdit`. Applies a `WorkspaceEdit`.
Parameters: ~ Parameters: ~
• {workspace_edit} (`lsp.WorkspaceEdit`) • {workspace_edit} (`lsp.WorkspaceEdit`)
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`) (required) • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'`) (required)
See also: ~ See also: ~
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
@ -1883,13 +1885,13 @@ buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()*
• {bufnr} (`integer?`) Buffer id • {bufnr} (`integer?`) Buffer id
*vim.lsp.util.buf_highlight_references()* *vim.lsp.util.buf_highlight_references()*
buf_highlight_references({bufnr}, {references}, {offset_encoding}) buf_highlight_references({bufnr}, {references}, {position_encoding})
Shows a list of document highlights for a certain buffer. Shows a list of document highlights for a certain buffer.
Parameters: ~ Parameters: ~
• {bufnr} (`integer`) Buffer id • {bufnr} (`integer`) Buffer id
• {references} (`lsp.DocumentHighlight[]`) objects to highlight • {references} (`lsp.DocumentHighlight[]`) objects to highlight
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`) • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
See also: ~ See also: ~
• https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent • https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
@ -1964,7 +1966,7 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
• 'shiftwidth' • 'shiftwidth'
*vim.lsp.util.locations_to_items()* *vim.lsp.util.locations_to_items()*
locations_to_items({locations}, {offset_encoding}) locations_to_items({locations}, {position_encoding})
Returns the items with the byte position calculated correctly and in Returns the items with the byte position calculated correctly and in
sorted order, for display in quickfix and location lists. sorted order, for display in quickfix and location lists.
@ -1975,9 +1977,9 @@ locations_to_items({locations}, {offset_encoding})
|setloclist()|. |setloclist()|.
Parameters: ~ Parameters: ~
• {locations} (`lsp.Location[]|lsp.LocationLink[]`) • {locations} (`lsp.Location[]|lsp.LocationLink[]`)
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) default to first • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) default to first
client of buffer client of buffer
Return: ~ Return: ~
(`vim.quickfix.entry[]`) See |setqflist()| for the format (`vim.quickfix.entry[]`) See |setqflist()| for the format
@ -2012,33 +2014,33 @@ make_formatting_params({options})
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
*vim.lsp.util.make_given_range_params()* *vim.lsp.util.make_given_range_params()*
make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding}) make_given_range_params({start_pos}, {end_pos}, {bufnr}, {position_encoding})
Using the given range in the current buffer, creates an object that is Using the given range in the current buffer, creates an object that is
similar to |vim.lsp.util.make_range_params()|. similar to |vim.lsp.util.make_range_params()|.
Parameters: ~ Parameters: ~
• {start_pos} (`[integer,integer]?`) {row,col} mark-indexed • {start_pos} (`[integer,integer]?`) {row,col} mark-indexed
position. Defaults to the start of the last visual position. Defaults to the start of the last
selection. visual selection.
• {end_pos} (`[integer,integer]?`) {row,col} mark-indexed • {end_pos} (`[integer,integer]?`) {row,col} mark-indexed
position. Defaults to the end of the last visual position. Defaults to the end of the last visual
selection. selection.
• {bufnr} (`integer?`) buffer handle or 0 for current, • {bufnr} (`integer?`) buffer handle or 0 for current,
defaults to current defaults to current
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`) • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
Return: ~ Return: ~
(`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`) (`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`)
*vim.lsp.util.make_position_params()* *vim.lsp.util.make_position_params()*
make_position_params({window}, {offset_encoding}) make_position_params({window}, {position_encoding})
Creates a `TextDocumentPositionParams` object for the current buffer and Creates a `TextDocumentPositionParams` object for the current buffer and
cursor position. cursor position.
Parameters: ~ Parameters: ~
• {window} (`integer?`) window handle or 0 for current, • {window} (`integer?`) window handle or 0 for current,
defaults to current defaults to current
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`) • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
Return: ~ Return: ~
(`lsp.TextDocumentPositionParams`) (`lsp.TextDocumentPositionParams`)
@ -2047,16 +2049,16 @@ make_position_params({window}, {offset_encoding})
• https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
*vim.lsp.util.make_range_params()* *vim.lsp.util.make_range_params()*
make_range_params({window}, {offset_encoding}) make_range_params({window}, {position_encoding})
Using the current position in the current buffer, creates an object that Using the current position in the current buffer, creates an object that
can be used as a building block for several LSP requests, such as can be used as a building block for several LSP requests, such as
`textDocument/codeAction`, `textDocument/colorPresentation`, `textDocument/codeAction`, `textDocument/colorPresentation`,
`textDocument/rangeFormatting`. `textDocument/rangeFormatting`.
Parameters: ~ Parameters: ~
• {window} (`integer?`) window handle or 0 for current, • {window} (`integer?`) window handle or 0 for current,
defaults to current defaults to current
• {offset_encoding} (`"utf-8"|"utf-16"|"utf-32"`) • {position_encoding} (`"utf-8"|"utf-16"|"utf-32"`)
Return: ~ Return: ~
(`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`) (`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`)
@ -2138,17 +2140,17 @@ rename({old_fname}, {new_fname}, {opts}) *vim.lsp.util.rename()*
• {ignoreIfExists}? (`boolean`) • {ignoreIfExists}? (`boolean`)
*vim.lsp.util.show_document()* *vim.lsp.util.show_document()*
show_document({location}, {offset_encoding}, {opts}) show_document({location}, {position_encoding}, {opts})
Shows document and optionally jumps to the location. Shows document and optionally jumps to the location.
Parameters: ~ Parameters: ~
• {location} (`lsp.Location|lsp.LocationLink`) • {location} (`lsp.Location|lsp.LocationLink`)
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) • {position_encoding} (`'utf-8'|'utf-16'|'utf-32'?`)
• {opts} (`table?`) A table with the following fields: • {opts} (`table?`) A table with the following fields:
• {reuse_win}? (`boolean`) Jump to existing window • {reuse_win}? (`boolean`) Jump to existing
if buffer is already open. window if buffer is already open.
• {focus}? (`boolean`) Whether to focus/jump to • {focus}? (`boolean`) Whether to focus/jump to
location if possible. (defaults: true) location if possible. (defaults: true)
Return: ~ Return: ~
(`boolean`) `true` if succeeded (`boolean`) `true` if succeeded

View File

@ -100,7 +100,7 @@ LSP
vim.diagnostic.config(config, vim.lsp.diagnostic.get_namespace(client_id)) vim.diagnostic.config(config, vim.lsp.diagnostic.get_namespace(client_id))
< <
• |vim.lsp.util.make_position_params()|, |vim.lsp.util.make_range_params()| • |vim.lsp.util.make_position_params()|, |vim.lsp.util.make_range_params()|
and |vim.lsp.util.make_given_range_params()| now require the `offset_encoding` and |vim.lsp.util.make_given_range_params()| now require the `position_encoding`
parameter. parameter.
LUA LUA

View File

@ -18,14 +18,14 @@ local M = {}
--- ---
--- None: One group for all clients --- None: One group for all clients
--- Full: One group for all clients --- Full: One group for all clients
--- Incremental: One group per `offset_encoding` --- Incremental: One group per `position_encoding`
--- ---
--- Sending changes can be debounced per buffer. To simplify the implementation the --- Sending changes can be debounced per buffer. To simplify the implementation the
--- smallest debounce interval is used and we don't group clients by different intervals. --- smallest debounce interval is used and we don't group clients by different intervals.
--- ---
--- @class vim.lsp.CTGroup --- @class vim.lsp.CTGroup
--- @field sync_kind integer TextDocumentSyncKind, considers config.flags.allow_incremental_sync --- @field sync_kind integer TextDocumentSyncKind, considers config.flags.allow_incremental_sync
--- @field offset_encoding "utf-8"|"utf-16"|"utf-32" --- @field position_encoding "utf-8"|"utf-16"|"utf-32"
--- ---
--- @class vim.lsp.CTBufferState --- @class vim.lsp.CTBufferState
--- @field name string name of the buffer --- @field name string name of the buffer
@ -46,7 +46,7 @@ local M = {}
---@return string ---@return string
local function group_key(group) local function group_key(group)
if group.sync_kind == protocol.TextDocumentSyncKind.Incremental then if group.sync_kind == protocol.TextDocumentSyncKind.Incremental then
return tostring(group.sync_kind) .. '\0' .. group.offset_encoding return tostring(group.sync_kind) .. '\0' .. group.position_encoding
end end
return tostring(group.sync_kind) return tostring(group.sync_kind)
end end
@ -72,7 +72,7 @@ local function get_group(client)
end end
return { return {
sync_kind = sync_kind, sync_kind = sync_kind,
offset_encoding = client.offset_encoding, position_encoding = client.offset_encoding,
} }
end end
@ -310,7 +310,7 @@ local function send_changes_for_group(bufnr, firstline, lastline, new_lastline,
-- The contents would further change and startline/endline may no longer fit -- The contents would further change and startline/endline may no longer fit
local changes = incremental_changes( local changes = incremental_changes(
buf_state, buf_state,
group.offset_encoding, group.position_encoding,
bufnr, bufnr,
firstline, firstline,
lastline, lastline,

View File

@ -6,12 +6,12 @@ local ms = lsp.protocol.Methods
---@param name string ---@param name string
---@param range lsp.Range ---@param range lsp.Range
---@param uri string ---@param uri string
---@param offset_encoding string ---@param position_encoding string
---@return {name: string, filename: string, cmd: string, kind?: string} ---@return {name: string, filename: string, cmd: string, kind?: string}
local function mk_tag_item(name, range, uri, offset_encoding) local function mk_tag_item(name, range, uri, position_encoding)
local bufnr = vim.uri_to_bufnr(uri) local bufnr = vim.uri_to_bufnr(uri)
-- This is get_line_byte_from_position is 0-indexed, call cursor expects a 1-indexed position -- This is get_line_byte_from_position is 0-indexed, call cursor expects a 1-indexed position
local byte = util._get_line_byte_from_position(bufnr, range.start, offset_encoding) + 1 local byte = util._get_line_byte_from_position(bufnr, range.start, position_encoding) + 1
return { return {
name = name, name = name,
filename = vim.uri_to_fname(uri), filename = vim.uri_to_fname(uri),
@ -32,9 +32,9 @@ local function query_definition(pattern)
--- @param range lsp.Range --- @param range lsp.Range
--- @param uri string --- @param uri string
--- @param offset_encoding string --- @param position_encoding string
local add = function(range, uri, offset_encoding) local add = function(range, uri, position_encoding)
table.insert(results, mk_tag_item(pattern, range, uri, offset_encoding)) table.insert(results, mk_tag_item(pattern, range, uri, position_encoding))
end end
local remaining = #clients local remaining = #clients
@ -78,11 +78,11 @@ local function query_workspace_symbols(pattern)
local results = {} local results = {}
for client_id, responses in pairs(assert(results_by_client)) do for client_id, responses in pairs(assert(results_by_client)) do
local client = lsp.get_client_by_id(client_id) local client = lsp.get_client_by_id(client_id)
local offset_encoding = client and client.offset_encoding or 'utf-16' local position_encoding = client and client.offset_encoding or 'utf-16'
local symbols = responses.result --[[@as lsp.SymbolInformation[]|nil]] local symbols = responses.result --[[@as lsp.SymbolInformation[]|nil]]
for _, symbol in pairs(symbols or {}) do for _, symbol in pairs(symbols or {}) do
local loc = symbol.location local loc = symbol.location
local item = mk_tag_item(symbol.name, loc.range, loc.uri, offset_encoding) local item = mk_tag_item(symbol.name, loc.range, loc.uri, position_encoding)
item.kind = lsp.protocol.SymbolKind[symbol.kind] or 'Unknown' item.kind = lsp.protocol.SymbolKind[symbol.kind] or 'Unknown'
table.insert(results, item) table.insert(results, item)
end end

View File

@ -638,14 +638,14 @@ function M.rename(new_name, opts)
local cword = vim.fn.expand('<cword>') local cword = vim.fn.expand('<cword>')
--- @param range lsp.Range --- @param range lsp.Range
--- @param offset_encoding string --- @param position_encoding string
local function get_text_at_range(range, offset_encoding) local function get_text_at_range(range, position_encoding)
return api.nvim_buf_get_text( return api.nvim_buf_get_text(
bufnr, bufnr,
range.start.line, range.start.line,
util._get_line_byte_from_position(bufnr, range.start, offset_encoding), util._get_line_byte_from_position(bufnr, range.start, position_encoding),
range['end'].line, range['end'].line,
util._get_line_byte_from_position(bufnr, range['end'], offset_encoding), util._get_line_byte_from_position(bufnr, range['end'], position_encoding),
{} {}
)[1] )[1]
end end

View File

@ -94,7 +94,8 @@ local validate = vim.validate
--- Language ID as string. Defaults to the buffer filetype. --- Language ID as string. Defaults to the buffer filetype.
--- @field get_language_id? fun(bufnr: integer, filetype: string): string --- @field get_language_id? fun(bufnr: integer, filetype: string): string
--- ---
--- The encoding that the LSP server expects. Client does not verify this is correct. --- Called "position encoding" in LSP spec, the encoding that the LSP server expects.
--- Client does not verify this is correct.
--- @field offset_encoding? 'utf-8'|'utf-16'|'utf-32' --- @field offset_encoding? 'utf-8'|'utf-16'|'utf-32'
--- ---
--- Callback invoked when the client operation throws an error. `code` is a number describing the error. --- Callback invoked when the client operation throws an error. `code` is a number describing the error.
@ -148,8 +149,10 @@ local validate = vim.validate
--- See |vim.lsp.rpc.start()|. --- See |vim.lsp.rpc.start()|.
--- @field rpc vim.lsp.rpc.PublicClient --- @field rpc vim.lsp.rpc.PublicClient
--- ---
--- The encoding used for communicating with the server. You can modify this in --- Called "position encoding" in LSP spec,
--- the `config`'s `on_init` method before text is sent to the server. --- the encoding used for communicating with the server.
--- You can modify this in the `config`'s `on_init` method
--- before text is sent to the server.
--- @field offset_encoding string --- @field offset_encoding string
--- ---
--- The handlers used by the client as described in |lsp-handler|. --- The handlers used by the client as described in |lsp-handler|.
@ -278,7 +281,7 @@ local function validate_encoding(encoding)
return valid_encodings[encoding:lower()] return valid_encodings[encoding:lower()]
or error( or error(
string.format( string.format(
"Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", "Invalid position encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'",
encoding encoding
) )
) )

View File

@ -550,7 +550,7 @@ local function on_complete_done()
return return
end end
local offset_encoding = client.offset_encoding or 'utf-16' local position_encoding = client.offset_encoding or 'utf-16'
local resolve_provider = (client.server_capabilities.completionProvider or {}).resolveProvider local resolve_provider = (client.server_capabilities.completionProvider or {}).resolveProvider
local function clear_word() local function clear_word()
@ -576,7 +576,7 @@ local function on_complete_done()
if completion_item.additionalTextEdits and next(completion_item.additionalTextEdits) then if completion_item.additionalTextEdits and next(completion_item.additionalTextEdits) then
clear_word() clear_word()
lsp.util.apply_text_edits(completion_item.additionalTextEdits, bufnr, offset_encoding) lsp.util.apply_text_edits(completion_item.additionalTextEdits, bufnr, position_encoding)
apply_snippet_and_command() apply_snippet_and_command()
elseif resolve_provider and type(completion_item) == 'table' then elseif resolve_provider and type(completion_item) == 'table' then
local changedtick = vim.b[bufnr].changedtick local changedtick = vim.b[bufnr].changedtick
@ -591,7 +591,7 @@ local function on_complete_done()
if err then if err then
vim.notify_once(err.message, vim.log.levels.WARN) vim.notify_once(err.message, vim.log.levels.WARN)
elseif result and result.additionalTextEdits then elseif result and result.additionalTextEdits then
lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, offset_encoding) lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, position_encoding)
if result.command then if result.command then
completion_item.command = result.command completion_item.command = result.command
end end

View File

@ -77,7 +77,7 @@ end
local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
local buf_lines = get_buf_lines(bufnr) local buf_lines = get_buf_lines(bufnr)
local client = vim.lsp.get_client_by_id(client_id) local client = vim.lsp.get_client_by_id(client_id)
local offset_encoding = client and client.offset_encoding or 'utf-16' local position_encoding = client and client.offset_encoding or 'utf-16'
--- @param diagnostic lsp.Diagnostic --- @param diagnostic lsp.Diagnostic
--- @return vim.Diagnostic --- @return vim.Diagnostic
return vim.tbl_map(function(diagnostic) return vim.tbl_map(function(diagnostic)
@ -95,9 +95,9 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
--- @type vim.Diagnostic --- @type vim.Diagnostic
return { return {
lnum = start.line, lnum = start.line,
col = vim.str_byteindex(line, offset_encoding, start.character, false), col = vim.str_byteindex(line, position_encoding, start.character, false),
end_lnum = _end.line, end_lnum = _end.line,
end_col = vim.str_byteindex(line, offset_encoding, _end.character, false), end_col = vim.str_byteindex(line, position_encoding, _end.character, false),
severity = severity_lsp_to_vim(diagnostic.severity), severity = severity_lsp_to_vim(diagnostic.severity),
message = message, message = message,
source = diagnostic.source, source = diagnostic.source,

View File

@ -48,21 +48,21 @@ local str_utfindex = vim.str_utfindex
local str_utf_start = vim.str_utf_start local str_utf_start = vim.str_utf_start
local str_utf_end = vim.str_utf_end local str_utf_end = vim.str_utf_end
-- Given a line, byte idx, alignment, and offset_encoding convert to the aligned -- Given a line, byte idx, alignment, and position_encoding convert to the aligned
-- utf-8 index and either the utf-16, or utf-32 index. -- utf-8 index and either the utf-16, or utf-32 index.
---@param line string the line to index into ---@param line string the line to index into
---@param byte integer the byte idx ---@param byte integer the byte idx
---@param offset_encoding string utf-8|utf-16|utf-32|nil (default: utf-8) ---@param position_encoding string utf-8|utf-16|utf-32|nil (default: utf-8)
---@return integer byte_idx of first change position ---@return integer byte_idx of first change position
---@return integer char_idx of first change position ---@return integer char_idx of first change position
local function align_end_position(line, byte, offset_encoding) local function align_end_position(line, byte, position_encoding)
local char --- @type integer local char --- @type integer
-- If on the first byte, or an empty string: the trivial case -- If on the first byte, or an empty string: the trivial case
if byte == 1 or #line == 0 then if byte == 1 or #line == 0 then
char = byte char = byte
-- Called in the case of extending an empty line "" -> "a" -- Called in the case of extending an empty line "" -> "a"
elseif byte == #line + 1 then elseif byte == #line + 1 then
char = str_utfindex(line, offset_encoding) + 1 char = str_utfindex(line, position_encoding) + 1
else else
-- Modifying line, find the nearest utf codepoint -- Modifying line, find the nearest utf codepoint
local offset = str_utf_start(line, byte) local offset = str_utf_start(line, byte)
@ -73,9 +73,9 @@ local function align_end_position(line, byte, offset_encoding)
end end
if byte <= #line then if byte <= #line then
--- Convert to 0 based for input, and from 0 based for output --- Convert to 0 based for input, and from 0 based for output
char = str_utfindex(line, offset_encoding, byte - 1) + 1 char = str_utfindex(line, position_encoding, byte - 1) + 1
else else
char = str_utfindex(line, offset_encoding) + 1 char = str_utfindex(line, position_encoding) + 1
end end
-- Extending line, find the nearest utf codepoint for the last valid character -- Extending line, find the nearest utf codepoint for the last valid character
end end
@ -93,7 +93,7 @@ end
---@param firstline integer firstline from on_lines, adjusted to 1-index ---@param firstline integer firstline from on_lines, adjusted to 1-index
---@param lastline integer lastline from on_lines, adjusted to 1-index ---@param lastline integer lastline from on_lines, adjusted to 1-index
---@param new_lastline integer new_lastline from on_lines, adjusted to 1-index ---@param new_lastline integer new_lastline from on_lines, adjusted to 1-index
---@param offset_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8) ---@param position_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8)
---@return vim.lsp.sync.Range result table include line_idx, byte_idx, and char_idx of first change position ---@return vim.lsp.sync.Range result table include line_idx, byte_idx, and char_idx of first change position
local function compute_start_range( local function compute_start_range(
prev_lines, prev_lines,
@ -101,7 +101,7 @@ local function compute_start_range(
firstline, firstline,
lastline, lastline,
new_lastline, new_lastline,
offset_encoding position_encoding
) )
local char_idx --- @type integer? local char_idx --- @type integer?
local byte_idx --- @type integer? local byte_idx --- @type integer?
@ -115,7 +115,7 @@ local function compute_start_range(
if line then if line then
line_idx = firstline - 1 line_idx = firstline - 1
byte_idx = #line + 1 byte_idx = #line + 1
char_idx = str_utfindex(line, offset_encoding) + 1 char_idx = str_utfindex(line, position_encoding) + 1
else else
line_idx = firstline line_idx = firstline
byte_idx = 1 byte_idx = 1
@ -152,11 +152,11 @@ local function compute_start_range(
char_idx = 1 char_idx = 1
elseif start_byte_idx == #prev_line + 1 then elseif start_byte_idx == #prev_line + 1 then
byte_idx = start_byte_idx byte_idx = start_byte_idx
char_idx = str_utfindex(prev_line, offset_encoding) + 1 char_idx = str_utfindex(prev_line, position_encoding) + 1
else else
byte_idx = start_byte_idx + str_utf_start(prev_line, start_byte_idx) byte_idx = start_byte_idx + str_utf_start(prev_line, start_byte_idx)
--- Convert to 0 based for input, and from 0 based for output --- Convert to 0 based for input, and from 0 based for output
char_idx = vim.str_utfindex(prev_line, offset_encoding, byte_idx - 1) + 1 char_idx = vim.str_utfindex(prev_line, position_encoding, byte_idx - 1) + 1
end end
-- Return the start difference (shared for new and prev lines) -- Return the start difference (shared for new and prev lines)
@ -174,7 +174,7 @@ end
---@param firstline integer ---@param firstline integer
---@param lastline integer ---@param lastline integer
---@param new_lastline integer ---@param new_lastline integer
---@param offset_encoding string ---@param position_encoding string
---@return vim.lsp.sync.Range prev_end_range ---@return vim.lsp.sync.Range prev_end_range
---@return vim.lsp.sync.Range curr_end_range ---@return vim.lsp.sync.Range curr_end_range
local function compute_end_range( local function compute_end_range(
@ -184,7 +184,7 @@ local function compute_end_range(
firstline, firstline,
lastline, lastline,
new_lastline, new_lastline,
offset_encoding position_encoding
) )
-- A special case for the following `firstline == new_lastline` case where lines are deleted. -- A special case for the following `firstline == new_lastline` case where lines are deleted.
-- Even if the buffer has become empty, nvim behaves as if it has an empty line with eol. -- Even if the buffer has become empty, nvim behaves as if it has an empty line with eol.
@ -193,7 +193,7 @@ local function compute_end_range(
return { return {
line_idx = lastline - 1, line_idx = lastline - 1,
byte_idx = #prev_line + 1, byte_idx = #prev_line + 1,
char_idx = str_utfindex(prev_line, offset_encoding) + 1, char_idx = str_utfindex(prev_line, position_encoding) + 1,
}, { line_idx = 1, byte_idx = 1, char_idx = 1 } }, { line_idx = 1, byte_idx = 1, char_idx = 1 }
end end
-- If firstline == new_lastline, the first change occurred on a line that was deleted. -- If firstline == new_lastline, the first change occurred on a line that was deleted.
@ -259,7 +259,7 @@ local function compute_end_range(
prev_end_byte_idx = 1 prev_end_byte_idx = 1
end end
local prev_byte_idx, prev_char_idx = local prev_byte_idx, prev_char_idx =
align_end_position(prev_line, prev_end_byte_idx, offset_encoding) align_end_position(prev_line, prev_end_byte_idx, position_encoding)
local prev_end_range = local prev_end_range =
{ line_idx = prev_line_idx, byte_idx = prev_byte_idx, char_idx = prev_char_idx } { line_idx = prev_line_idx, byte_idx = prev_byte_idx, char_idx = prev_char_idx }
@ -274,7 +274,7 @@ local function compute_end_range(
curr_end_byte_idx = 1 curr_end_byte_idx = 1
end end
local curr_byte_idx, curr_char_idx = local curr_byte_idx, curr_char_idx =
align_end_position(curr_line, curr_end_byte_idx, offset_encoding) align_end_position(curr_line, curr_end_byte_idx, position_encoding)
curr_end_range = curr_end_range =
{ line_idx = curr_line_idx, byte_idx = curr_byte_idx, char_idx = curr_char_idx } { line_idx = curr_line_idx, byte_idx = curr_byte_idx, char_idx = curr_char_idx }
end end
@ -317,7 +317,7 @@ local function extract_text(lines, start_range, end_range, line_ending)
end end
end end
-- rangelength depends on the offset encoding -- rangelength depends on the position encoding
-- bytes for utf-8 (clangd with extension) -- bytes for utf-8 (clangd with extension)
-- codepoints for utf-16 -- codepoints for utf-16
-- codeunits for utf-32 -- codeunits for utf-32
@ -326,10 +326,10 @@ end
---@param lines string[] ---@param lines string[]
---@param start_range vim.lsp.sync.Range ---@param start_range vim.lsp.sync.Range
---@param end_range vim.lsp.sync.Range ---@param end_range vim.lsp.sync.Range
---@param offset_encoding string ---@param position_encoding string
---@param line_ending string ---@param line_ending string
---@return integer ---@return integer
local function compute_range_length(lines, start_range, end_range, offset_encoding, line_ending) local function compute_range_length(lines, start_range, end_range, position_encoding, line_ending)
local line_ending_length = #line_ending local line_ending_length = #line_ending
-- Single line case -- Single line case
if start_range.line_idx == end_range.line_idx then if start_range.line_idx == end_range.line_idx then
@ -339,7 +339,7 @@ local function compute_range_length(lines, start_range, end_range, offset_encodi
local start_line = lines[start_range.line_idx] local start_line = lines[start_range.line_idx]
local range_length --- @type integer local range_length --- @type integer
if start_line and #start_line > 0 then if start_line and #start_line > 0 then
range_length = str_utfindex(start_line, offset_encoding) range_length = str_utfindex(start_line, position_encoding)
- start_range.char_idx - start_range.char_idx
+ 1 + 1
+ line_ending_length + line_ending_length
@ -352,7 +352,7 @@ local function compute_range_length(lines, start_range, end_range, offset_encodi
for idx = start_range.line_idx + 1, end_range.line_idx - 1 do for idx = start_range.line_idx + 1, end_range.line_idx - 1 do
-- Length full line plus newline character -- Length full line plus newline character
if #lines[idx] > 0 then if #lines[idx] > 0 then
range_length = range_length + str_utfindex(lines[idx], offset_encoding) + #line_ending range_length = range_length + str_utfindex(lines[idx], position_encoding) + #line_ending
else else
range_length = range_length + line_ending_length range_length = range_length + line_ending_length
end end
@ -372,7 +372,7 @@ end
---@param firstline integer line to begin search for first difference ---@param firstline integer line to begin search for first difference
---@param lastline integer line to begin search in old_lines for last difference ---@param lastline integer line to begin search in old_lines for last difference
---@param new_lastline integer line to begin search in new_lines for last difference ---@param new_lastline integer line to begin search in new_lines for last difference
---@param offset_encoding string encoding requested by language server ---@param position_encoding string encoding requested by language server
---@param line_ending string ---@param line_ending string
---@return lsp.TextDocumentContentChangeEvent : see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent ---@return lsp.TextDocumentContentChangeEvent : see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
function M.compute_diff( function M.compute_diff(
@ -381,7 +381,7 @@ function M.compute_diff(
firstline, firstline,
lastline, lastline,
new_lastline, new_lastline,
offset_encoding, position_encoding,
line_ending line_ending
) )
-- Find the start of changes between the previous and current buffer. Common between both. -- Find the start of changes between the previous and current buffer. Common between both.
@ -393,7 +393,7 @@ function M.compute_diff(
firstline + 1, firstline + 1,
lastline + 1, lastline + 1,
new_lastline + 1, new_lastline + 1,
offset_encoding position_encoding
) )
-- Find the last position changed in the previous and current buffer. -- Find the last position changed in the previous and current buffer.
-- prev_end_range is sent to the server as as the end of the changed range. -- prev_end_range is sent to the server as as the end of the changed range.
@ -405,7 +405,7 @@ function M.compute_diff(
firstline + 1, firstline + 1,
lastline + 1, lastline + 1,
new_lastline + 1, new_lastline + 1,
offset_encoding position_encoding
) )
-- Grab the changed text of from start_range to curr_end_range in the current buffer. -- Grab the changed text of from start_range to curr_end_range in the current buffer.
@ -414,7 +414,7 @@ function M.compute_diff(
-- Compute the range of the replaced text. Deprecated but still required for certain language servers -- Compute the range of the replaced text. Deprecated but still required for certain language servers
local range_length = local range_length =
compute_range_length(prev_lines, start_range, prev_end_range, offset_encoding, line_ending) compute_range_length(prev_lines, start_range, prev_end_range, position_encoding, line_ending)
-- convert to 0 based indexing -- convert to 0 based indexing
local result = { local result = {

View File

@ -277,9 +277,9 @@ end
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position --- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
---@param position lsp.Position ---@param position lsp.Position
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@return integer ---@return integer
local function get_line_byte_from_position(bufnr, position, offset_encoding) local function get_line_byte_from_position(bufnr, position, position_encoding)
-- LSP's line and characters are 0-indexed -- LSP's line and characters are 0-indexed
-- Vim's line and columns are 1-indexed -- Vim's line and columns are 1-indexed
local col = position.character local col = position.character
@ -287,7 +287,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding)
-- character -- character
if col > 0 then if col > 0 then
local line = get_line(bufnr, position.line) or '' local line = get_line(bufnr, position.line) or ''
return vim.str_byteindex(line, offset_encoding, col, false) return vim.str_byteindex(line, position_encoding, col, false)
end end
return col return col
end end
@ -295,12 +295,12 @@ end
--- Applies a list of text edits to a buffer. --- Applies a list of text edits to a buffer.
---@param text_edits lsp.TextEdit[] ---@param text_edits lsp.TextEdit[]
---@param bufnr integer Buffer id ---@param bufnr integer Buffer id
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
function M.apply_text_edits(text_edits, bufnr, offset_encoding) function M.apply_text_edits(text_edits, bufnr, position_encoding)
validate('text_edits', text_edits, 'table', false) validate('text_edits', text_edits, 'table', false)
validate('bufnr', bufnr, 'number', false) validate('bufnr', bufnr, 'number', false)
validate('offset_encoding', offset_encoding, 'string', false) validate('position_encoding', position_encoding, 'string', false)
if not next(text_edits) then if not next(text_edits) then
return return
@ -359,9 +359,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
-- Convert from LSP style ranges to Neovim style ranges. -- Convert from LSP style ranges to Neovim style ranges.
local start_row = text_edit.range.start.line local start_row = text_edit.range.start.line
local start_col = get_line_byte_from_position(bufnr, text_edit.range.start, offset_encoding) local start_col = get_line_byte_from_position(bufnr, text_edit.range.start, position_encoding)
local end_row = text_edit.range['end'].line local end_row = text_edit.range['end'].line
local end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], offset_encoding) local end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], position_encoding)
local text = vim.split(text_edit.newText, '\n', { plain = true }) local text = vim.split(text_edit.newText, '\n', { plain = true })
local max = api.nvim_buf_line_count(bufnr) local max = api.nvim_buf_line_count(bufnr)
@ -430,14 +430,14 @@ end
--- ---
---@param text_document_edit lsp.TextDocumentEdit ---@param text_document_edit lsp.TextDocumentEdit
---@param index? integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) ---@param index? integer: Optional index of the edit, if from a list of edits (or nil, if not from a list)
---@param offset_encoding? 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding? 'utf-8'|'utf-16'|'utf-32'
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit
function M.apply_text_document_edit(text_document_edit, index, offset_encoding) function M.apply_text_document_edit(text_document_edit, index, position_encoding)
local text_document = text_document_edit.textDocument local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri) local bufnr = vim.uri_to_bufnr(text_document.uri)
if offset_encoding == nil then if position_encoding == nil then
vim.notify_once( vim.notify_once(
'apply_text_document_edit must be called with valid offset encoding', 'apply_text_document_edit must be called with valid position encoding',
vim.log.levels.WARN vim.log.levels.WARN
) )
return return
@ -459,7 +459,7 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding)
return return
end end
M.apply_text_edits(text_document_edit.edits, bufnr, offset_encoding) M.apply_text_edits(text_document_edit.edits, bufnr, position_encoding)
end end
local function path_components(path) local function path_components(path)
@ -619,12 +619,12 @@ end
--- Applies a `WorkspaceEdit`. --- Applies a `WorkspaceEdit`.
--- ---
---@param workspace_edit lsp.WorkspaceEdit ---@param workspace_edit lsp.WorkspaceEdit
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' (required) ---@param position_encoding 'utf-8'|'utf-16'|'utf-32' (required)
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit, offset_encoding) function M.apply_workspace_edit(workspace_edit, position_encoding)
if offset_encoding == nil then if position_encoding == nil then
vim.notify_once( vim.notify_once(
'apply_workspace_edit must be called with valid offset encoding', 'apply_workspace_edit must be called with valid position encoding',
vim.log.levels.WARN vim.log.levels.WARN
) )
return return
@ -641,7 +641,7 @@ function M.apply_workspace_edit(workspace_edit, offset_encoding)
elseif change.kind then --- @diagnostic disable-line:undefined-field elseif change.kind then --- @diagnostic disable-line:undefined-field
error(string.format('Unsupported change: %q', vim.inspect(change))) error(string.format('Unsupported change: %q', vim.inspect(change)))
else else
M.apply_text_document_edit(change, idx, offset_encoding) M.apply_text_document_edit(change, idx, position_encoding)
end end
end end
return return
@ -654,7 +654,7 @@ function M.apply_workspace_edit(workspace_edit, offset_encoding)
for uri, changes in pairs(all_changes) do for uri, changes in pairs(all_changes) do
local bufnr = vim.uri_to_bufnr(uri) local bufnr = vim.uri_to_bufnr(uri)
M.apply_text_edits(changes, bufnr, offset_encoding) M.apply_text_edits(changes, bufnr, position_encoding)
end end
end end
@ -904,17 +904,20 @@ end
--- Shows document and optionally jumps to the location. --- Shows document and optionally jumps to the location.
--- ---
---@param location lsp.Location|lsp.LocationLink ---@param location lsp.Location|lsp.LocationLink
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'?
---@param opts? vim.lsp.util.show_document.Opts ---@param opts? vim.lsp.util.show_document.Opts
---@return boolean `true` if succeeded ---@return boolean `true` if succeeded
function M.show_document(location, offset_encoding, opts) function M.show_document(location, position_encoding, opts)
-- location may be Location or LocationLink -- location may be Location or LocationLink
local uri = location.uri or location.targetUri local uri = location.uri or location.targetUri
if uri == nil then if uri == nil then
return false return false
end end
if offset_encoding == nil then if position_encoding == nil then
vim.notify_once('show_document must be called with valid offset encoding', vim.log.levels.WARN) vim.notify_once(
'show_document must be called with valid position encoding',
vim.log.levels.WARN
)
return false return false
end end
local bufnr = vim.uri_to_bufnr(uri) local bufnr = vim.uri_to_bufnr(uri)
@ -946,7 +949,7 @@ function M.show_document(location, offset_encoding, opts)
if range then if range then
-- Jump to new location (adjusting for encoding of characters) -- Jump to new location (adjusting for encoding of characters)
local row = range.start.line local row = range.start.line
local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) local col = get_line_byte_from_position(bufnr, range.start, position_encoding)
api.nvim_win_set_cursor(win, { row + 1, col }) api.nvim_win_set_cursor(win, { row + 1, col })
vim._with({ win = win }, function() vim._with({ win = win }, function()
-- Open folds under the cursor -- Open folds under the cursor
@ -961,12 +964,12 @@ end
--- ---
---@deprecated use `vim.lsp.util.show_document` with `{focus=true}` instead ---@deprecated use `vim.lsp.util.show_document` with `{focus=true}` instead
---@param location lsp.Location|lsp.LocationLink ---@param location lsp.Location|lsp.LocationLink
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'?
---@param reuse_win boolean? Jump to existing window if buffer is already open. ---@param reuse_win boolean? Jump to existing window if buffer is already open.
---@return boolean `true` if the jump succeeded ---@return boolean `true` if the jump succeeded
function M.jump_to_location(location, offset_encoding, reuse_win) function M.jump_to_location(location, position_encoding, reuse_win)
vim.deprecate('vim.lsp.util.jump_to_location', nil, '0.12') vim.deprecate('vim.lsp.util.jump_to_location', nil, '0.12')
return M.show_document(location, offset_encoding, { reuse_win = reuse_win, focus = true }) return M.show_document(location, position_encoding, { reuse_win = reuse_win, focus = true })
end end
--- Previews a location in a floating window --- Previews a location in a floating window
@ -1661,18 +1664,18 @@ do --[[ References ]]
--- ---
---@param bufnr integer Buffer id ---@param bufnr integer Buffer id
---@param references lsp.DocumentHighlight[] objects to highlight ---@param references lsp.DocumentHighlight[] objects to highlight
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent ---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent
function M.buf_highlight_references(bufnr, references, offset_encoding) function M.buf_highlight_references(bufnr, references, position_encoding)
validate('bufnr', bufnr, 'number', true) validate('bufnr', bufnr, 'number', true)
validate('offset_encoding', offset_encoding, 'string', false) validate('position_encoding', position_encoding, 'string', false)
for _, reference in ipairs(references) do for _, reference in ipairs(references) do
local range = reference.range local range = reference.range
local start_line = range.start.line local start_line = range.start.line
local end_line = range['end'].line local end_line = range['end'].line
local start_idx = get_line_byte_from_position(bufnr, range.start, offset_encoding) local start_idx = get_line_byte_from_position(bufnr, range.start, position_encoding)
local end_idx = get_line_byte_from_position(bufnr, range['end'], offset_encoding) local end_idx = get_line_byte_from_position(bufnr, range['end'], position_encoding)
local document_highlight_kind = { local document_highlight_kind = {
[protocol.DocumentHighlightKind.Text] = 'LspReferenceText', [protocol.DocumentHighlightKind.Text] = 'LspReferenceText',
@ -1706,16 +1709,16 @@ end)
--- |setloclist()|. --- |setloclist()|.
--- ---
---@param locations lsp.Location[]|lsp.LocationLink[] ---@param locations lsp.Location[]|lsp.LocationLink[]
---@param offset_encoding? 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding? 'utf-8'|'utf-16'|'utf-32'
--- default to first client of buffer --- default to first client of buffer
---@return vim.quickfix.entry[] # See |setqflist()| for the format ---@return vim.quickfix.entry[] # See |setqflist()| for the format
function M.locations_to_items(locations, offset_encoding) function M.locations_to_items(locations, position_encoding)
if offset_encoding == nil then if position_encoding == nil then
vim.notify_once( vim.notify_once(
'locations_to_items must be called with valid offset encoding', 'locations_to_items must be called with valid position encoding',
vim.log.levels.WARN vim.log.levels.WARN
) )
offset_encoding = vim.lsp.get_clients({ bufnr = 0 })[1].offset_encoding position_encoding = vim.lsp.get_clients({ bufnr = 0 })[1].offset_encoding
end end
local items = {} --- @type vim.quickfix.entry[] local items = {} --- @type vim.quickfix.entry[]
@ -1752,8 +1755,8 @@ function M.locations_to_items(locations, offset_encoding)
local end_row = end_pos.line local end_row = end_pos.line
local line = lines[row] or '' local line = lines[row] or ''
local end_line = lines[end_row] or '' local end_line = lines[end_row] or ''
local col = vim.str_byteindex(line, offset_encoding, pos.character, false) local col = vim.str_byteindex(line, position_encoding, pos.character, false)
local end_col = vim.str_byteindex(end_line, offset_encoding, end_pos.character, false) local end_col = vim.str_byteindex(end_line, position_encoding, end_pos.character, false)
items[#items + 1] = { items[#items + 1] = {
filename = filename, filename = filename,
@ -1864,8 +1867,8 @@ function M.try_trim_markdown_code_blocks(lines)
end end
---@param window integer?: window handle or 0 for current, defaults to current ---@param window integer?: window handle or 0 for current, defaults to current
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
local function make_position_param(window, offset_encoding) local function make_position_param(window, position_encoding)
window = window or 0 window = window or 0
local buf = api.nvim_win_get_buf(window) local buf = api.nvim_win_get_buf(window)
local row, col = unpack(api.nvim_win_get_cursor(window)) local row, col = unpack(api.nvim_win_get_cursor(window))
@ -1875,7 +1878,7 @@ local function make_position_param(window, offset_encoding)
return { line = 0, character = 0 } return { line = 0, character = 0 }
end end
col = vim.str_utfindex(line, offset_encoding, col, false) col = vim.str_utfindex(line, position_encoding, col, false)
return { line = row, character = col } return { line = row, character = col }
end end
@ -1883,22 +1886,22 @@ end
--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position. --- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
--- ---
---@param window integer?: window handle or 0 for current, defaults to current ---@param window integer?: window handle or 0 for current, defaults to current
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@return lsp.TextDocumentPositionParams ---@return lsp.TextDocumentPositionParams
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params(window, offset_encoding) function M.make_position_params(window, position_encoding)
window = window or 0 window = window or 0
local buf = api.nvim_win_get_buf(window) local buf = api.nvim_win_get_buf(window)
if offset_encoding == nil then if position_encoding == nil then
vim.notify_once( vim.notify_once(
'warning: offset_encoding is required, using the offset_encoding from the first client', 'warning: position_encoding is required, using the offset_encoding from the first client',
vim.log.levels.WARN vim.log.levels.WARN
) )
offset_encoding = M._get_offset_encoding(buf) position_encoding = M._get_offset_encoding(buf)
end end
return { return {
textDocument = M.make_text_document_params(buf), textDocument = M.make_text_document_params(buf),
position = make_position_param(window, offset_encoding), position = make_position_param(window, position_encoding),
} }
end end
@ -1941,18 +1944,18 @@ end
--- `textDocument/rangeFormatting`. --- `textDocument/rangeFormatting`.
--- ---
---@param window integer? window handle or 0 for current, defaults to current ---@param window integer? window handle or 0 for current, defaults to current
---@param offset_encoding "utf-8"|"utf-16"|"utf-32" ---@param position_encoding "utf-8"|"utf-16"|"utf-32"
---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range } ---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }
function M.make_range_params(window, offset_encoding) function M.make_range_params(window, position_encoding)
local buf = api.nvim_win_get_buf(window or 0) local buf = api.nvim_win_get_buf(window or 0)
if offset_encoding == nil then if position_encoding == nil then
vim.notify_once( vim.notify_once(
'warning: offset_encoding is required, using the offset_encoding from the first client', 'warning: position_encoding is required, using the offset_encoding from the first client',
vim.log.levels.WARN vim.log.levels.WARN
) )
offset_encoding = M._get_offset_encoding(buf) position_encoding = M._get_offset_encoding(buf)
end end
local position = make_position_param(window, offset_encoding) local position = make_position_param(window, position_encoding)
return { return {
textDocument = M.make_text_document_params(buf), textDocument = M.make_text_document_params(buf),
range = { start = position, ['end'] = position }, range = { start = position, ['end'] = position },
@ -1967,19 +1970,19 @@ end
---@param end_pos [integer,integer]? {row,col} mark-indexed position. ---@param end_pos [integer,integer]? {row,col} mark-indexed position.
--- Defaults to the end of the last visual selection. --- Defaults to the end of the last visual selection.
---@param bufnr integer? buffer handle or 0 for current, defaults to current ---@param bufnr integer? buffer handle or 0 for current, defaults to current
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range } ---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }
function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding) function M.make_given_range_params(start_pos, end_pos, bufnr, position_encoding)
validate('start_pos', start_pos, 'table', true) validate('start_pos', start_pos, 'table', true)
validate('end_pos', end_pos, 'table', true) validate('end_pos', end_pos, 'table', true)
validate('offset_encoding', offset_encoding, 'string', true) validate('position_encoding', position_encoding, 'string', true)
bufnr = bufnr or api.nvim_get_current_buf() bufnr = bufnr or api.nvim_get_current_buf()
if offset_encoding == nil then if position_encoding == nil then
vim.notify_once( vim.notify_once(
'warning: offset_encoding is required, using the offset_encoding from the first client', 'warning: position_encoding is required, using the offset_encoding from the first client',
vim.log.levels.WARN vim.log.levels.WARN
) )
offset_encoding = M._get_offset_encoding(bufnr) position_encoding = M._get_offset_encoding(bufnr)
end end
--- @type [integer, integer] --- @type [integer, integer]
local A = { unpack(start_pos or api.nvim_buf_get_mark(bufnr, '<')) } local A = { unpack(start_pos or api.nvim_buf_get_mark(bufnr, '<')) }
@ -1988,12 +1991,12 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
-- convert to 0-index -- convert to 0-index
A[1] = A[1] - 1 A[1] = A[1] - 1
B[1] = B[1] - 1 B[1] = B[1] - 1
-- account for offset_encoding. -- account for position_encoding.
if A[2] > 0 then if A[2] > 0 then
A[2] = M.character_offset(bufnr, A[1], A[2], offset_encoding) A[2] = M.character_offset(bufnr, A[1], A[2], position_encoding)
end end
if B[2] > 0 then if B[2] > 0 then
B[2] = M.character_offset(bufnr, B[1], B[2], offset_encoding) B[2] = M.character_offset(bufnr, B[1], B[2], position_encoding)
end end
-- we need to offset the end character position otherwise we loose the last -- we need to offset the end character position otherwise we loose the last
-- character of the selection, as LSP end position is exclusive -- character of the selection, as LSP end position is exclusive
@ -2100,9 +2103,9 @@ end
---@param bufnr integer ---@param bufnr integer
---@param start_line integer ---@param start_line integer
---@param end_line integer ---@param end_line integer
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32' ---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
---@return lsp.Range ---@return lsp.Range
local function make_line_range_params(bufnr, start_line, end_line, offset_encoding) local function make_line_range_params(bufnr, start_line, end_line, position_encoding)
local last_line = api.nvim_buf_line_count(bufnr) - 1 local last_line = api.nvim_buf_line_count(bufnr) - 1
---@type lsp.Position ---@type lsp.Position
@ -2111,7 +2114,12 @@ local function make_line_range_params(bufnr, start_line, end_line, offset_encodi
if end_line == last_line and not vim.bo[bufnr].endofline then if end_line == last_line and not vim.bo[bufnr].endofline then
end_pos = { end_pos = {
line = end_line, line = end_line,
character = M.character_offset(bufnr, end_line, #get_line(bufnr, end_line), offset_encoding), character = M.character_offset(
bufnr,
end_line,
#get_line(bufnr, end_line),
position_encoding
),
} }
else else
end_pos = { line = end_line + 1, character = 0 } end_pos = { line = end_line + 1, character = 0 }

View File

@ -23,7 +23,7 @@ before_each(function()
-- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})] -- local line_ending = format_line_ending[vim.api.nvim_get_option_value('fileformat', {})]
--- @diagnostic disable-next-line:duplicate-set-field --- @diagnostic disable-next-line:duplicate-set-field
function _G.test_register(bufnr, id, offset_encoding, line_ending) function _G.test_register(bufnr, id, position_encoding, line_ending)
local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) local prev_lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true)
local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline) local function callback(_, bufnr0, _changedtick, firstline, lastline, new_lastline)
@ -38,7 +38,7 @@ before_each(function()
firstline, firstline,
lastline, lastline,
new_lastline, new_lastline,
offset_encoding, position_encoding,
line_ending line_ending
) )
@ -63,15 +63,15 @@ local function test_edit(
prev_buffer, prev_buffer,
edit_operations, edit_operations,
expected_text_changes, expected_text_changes,
offset_encoding, position_encoding,
line_ending line_ending
) )
offset_encoding = offset_encoding or 'utf-16' position_encoding = position_encoding or 'utf-16'
line_ending = line_ending or '\n' line_ending = line_ending or '\n'
api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer) api.nvim_buf_set_lines(0, 0, -1, true, prev_buffer)
exec_lua(function() exec_lua(function()
return _G.test_register(0, 'test1', offset_encoding, line_ending) return _G.test_register(0, 'test1', position_encoding, line_ending)
end) end)
for _, edit in ipairs(edit_operations) do for _, edit in ipairs(edit_operations) do

View File

@ -118,9 +118,9 @@ describe('luacats grammar', function()
type = '"rfc2396" | "rfc2732" | "rfc3986" | nil', type = '"rfc2396" | "rfc2732" | "rfc3986" | nil',
}) })
test('@param offset_encoding "utf-8" | "utf-16" | "utf-32" | nil', { test('@param position_encoding "utf-8" | "utf-16" | "utf-32" | nil', {
kind = 'param', kind = 'param',
name = 'offset_encoding', name = 'position_encoding',
type = '"utf-8" | "utf-16" | "utf-32" | nil', type = '"utf-8" | "utf-16" | "utf-32" | nil',
}) })