feat(lsp): require offset_encoding param #31249

Problem:
Since [version 3.17](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocuments),
LSP supports specifying the position encoding (aka offset encoding) supported by
the client through `positionEncoding`. Since #31209, Nvim fully supports
`utf-8`, `utf-16`, and `utf-32` encodings.

Previously, nvim assumed all clients for a buffer had the same
`offset_encoding`, so:
* Nvim provides `vim.lsp._get_offset_encoding()` to get `offset_encoding`, but
  this function is incorrect because `offset_encoding` is per-client, not
  per-buffer.
* Based on the strategy of `vim.lsp._get_offset_encoding()`,
  `vim.lsp.util.make_position_params()`, `vim.lsp.util.make_range_params()`, and
  `vim.lsp.util.make_given_range_params()` do not require the caller to pass
  `offset_encoding`, which is invalid.
* https://github.com/neovim/neovim/issues/25272

Solution:
* Mark `vim.lsp._get_offset_encoding()` as `@deprecated`.
* Change the type annotations of `vim.lsp.util.make_position_params()`,
  `vim.lsp.util.make_range_params()`, `vim.lsp.util.make_given_range_params()`
  to require the `offset_encoding` param.
This commit is contained in:
Yi Ming 2024-11-21 04:19:07 +08:00 committed by GitHub
parent 1b6442034f
commit 629483e24e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 37 additions and 25 deletions

View File

@ -2025,12 +2025,10 @@ make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding})
selection.
• {bufnr} (`integer?`) buffer handle or 0 for current,
defaults to current
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) defaults to
`offset_encoding` of first client of `bufnr`
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
Return: ~
(`table`) { textDocument = { uri = `current_file_uri` }, range = {
start = `start_position`, end = `end_position` } }
(`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`)
*vim.lsp.util.make_position_params()*
make_position_params({window}, {offset_encoding})
@ -2040,9 +2038,7 @@ make_position_params({window}, {offset_encoding})
Parameters: ~
• {window} (`integer?`) window handle or 0 for current,
defaults to current
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'?`) defaults to
`offset_encoding` of first client of buffer of
`window`
• {offset_encoding} (`'utf-8'|'utf-16'|'utf-32'`)
Return: ~
(`lsp.TextDocumentPositionParams`)
@ -2060,13 +2056,10 @@ make_range_params({window}, {offset_encoding})
Parameters: ~
• {window} (`integer?`) window handle or 0 for current,
defaults to current
• {offset_encoding} (`"utf-8"|"utf-16"|"utf-32"?`) defaults to
`offset_encoding` of first client of buffer of
`window`
• {offset_encoding} (`"utf-8"|"utf-16"|"utf-32"`)
Return: ~
(`table`) { textDocument = { uri = `current_file_uri` }, range = {
start = `current_position`, end = `current_position` } }
(`{ textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }`)
*vim.lsp.util.make_text_document_params()*
make_text_document_params({bufnr})

View File

@ -95,6 +95,9 @@ LSP
Instead use: >lua
vim.diagnostic.config(config, vim.lsp.diagnostic.get_namespace(client_id))
<
• |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`
parameter.
LUA

View File

@ -1848,12 +1848,11 @@ function M.try_trim_markdown_code_blocks(lines)
end
---@param window integer?: window handle or 0 for current, defaults to current
---@param offset_encoding? 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of buffer of `window`
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
local function make_position_param(window, offset_encoding)
window = window or 0
local buf = api.nvim_win_get_buf(window)
local row, col = unpack(api.nvim_win_get_cursor(window))
offset_encoding = offset_encoding or M._get_offset_encoding(buf)
row = row - 1
local line = api.nvim_buf_get_lines(buf, row, row + 1, true)[1]
if not line then
@ -1868,13 +1867,19 @@ end
--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
---
---@param window integer?: window handle or 0 for current, defaults to current
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of buffer of `window`
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
---@return lsp.TextDocumentPositionParams
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params(window, offset_encoding)
window = window or 0
local buf = api.nvim_win_get_buf(window)
offset_encoding = offset_encoding or M._get_offset_encoding(buf)
if offset_encoding == nil then
vim.notify_once(
'warning: offset_encoding is required, using the offset_encoding from the first client',
vim.log.levels.WARN
)
offset_encoding = M._get_offset_encoding(buf)
end
return {
textDocument = M.make_text_document_params(buf),
position = make_position_param(window, offset_encoding),
@ -1882,6 +1887,7 @@ function M.make_position_params(window, offset_encoding)
end
--- Utility function for getting the encoding of the first LSP client on the given buffer.
---@deprecated
---@param bufnr integer buffer handle or 0 for current, defaults to current
---@return string encoding first client if there is one, nil otherwise
function M._get_offset_encoding(bufnr)
@ -1904,7 +1910,7 @@ function M._get_offset_encoding(bufnr)
offset_encoding = this_offset_encoding
elseif offset_encoding ~= this_offset_encoding then
vim.notify_once(
'warning: multiple different client offset_encodings detected for buffer, this is not supported yet',
'warning: multiple different client offset_encodings detected for buffer, vim.lsp.util._get_offset_encoding() uses the offset_encoding from the first client',
vim.log.levels.WARN
)
end
@ -1919,12 +1925,17 @@ end
--- `textDocument/rangeFormatting`.
---
---@param window integer? window handle or 0 for current, defaults to current
---@param offset_encoding "utf-8"|"utf-16"|"utf-32"? defaults to `offset_encoding` of first client of buffer of `window`
---@return table { textDocument = { uri = `current_file_uri` }, range = { start =
---`current_position`, end = `current_position` } }
---@param offset_encoding "utf-8"|"utf-16"|"utf-32"
---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }
function M.make_range_params(window, offset_encoding)
local buf = api.nvim_win_get_buf(window or 0)
offset_encoding = offset_encoding or M._get_offset_encoding(buf)
if offset_encoding == nil then
vim.notify_once(
'warning: offset_encoding is required, using the offset_encoding from the first client',
vim.log.levels.WARN
)
offset_encoding = M._get_offset_encoding(buf)
end
local position = make_position_param(window, offset_encoding)
return {
textDocument = M.make_text_document_params(buf),
@ -1940,15 +1951,20 @@ end
---@param end_pos [integer,integer]? {row,col} mark-indexed position.
--- Defaults to the end of the last visual selection.
---@param bufnr integer? buffer handle or 0 for current, defaults to current
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'? defaults to `offset_encoding` of first client of `bufnr`
---@return table { textDocument = { uri = `current_file_uri` }, range = { start =
---`start_position`, end = `end_position` } }
---@param offset_encoding 'utf-8'|'utf-16'|'utf-32'
---@return { textDocument: { uri: lsp.DocumentUri }, range: lsp.Range }
function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
validate('start_pos', start_pos, 'table', true)
validate('end_pos', end_pos, 'table', true)
validate('offset_encoding', offset_encoding, 'string', true)
bufnr = bufnr or api.nvim_get_current_buf()
offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
if offset_encoding == nil then
vim.notify_once(
'warning: offset_encoding is required, using the offset_encoding from the first client',
vim.log.levels.WARN
)
offset_encoding = M._get_offset_encoding(bufnr)
end
--- @type [integer, integer]
local A = { unpack(start_pos or api.nvim_buf_get_mark(bufnr, '<')) }
--- @type [integer, integer]