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.
* deprecate old signatures
* move to new str_byteindex/str_utfindex signature
* use single-underscore name (double-underscore is reserved for Lua itself)
Problem:
- `vim.highlight` module does not follow `:help dev-name-common`, which
documents the name for "highlight" as "hl".
- Shorter names are usually preferred.
Solution:
Rename `vim.highlight` to `vim.hl`.
This is not a breaking change until 2.0 (or maybe never).
Problem:
Previously the index was only checked against the UTF8 length. This
could cause unexpected behaviours for strings containing multibyte chars
Solution:
Check indicies correctly against their max value before returning the
fallback length
Problem:
tagfunc failed in a weird buffer (either a directory or some other
non-file buffer, I don't remember):
E987: Invalid return value from tagfunc
E5108: Error executing lua …/runtime/lua/vim/lsp/util.lua:311: EISDIR: illegal operation on a directory
stack traceback:
at this line:
local data = assert(uv.fs_read(fd, stat.size, 0))
Solution:
Check for directory.
Problem:
- Some servers like LuaLS add unwanted blank lines after multiline
`@param` description.
- List items do not wrap nicely.
Solution:
- When rendering the LSP doc hover, remove blank lines in each `@param`
or `@return`.
- But ensure exactly one empty line before each.
- Set 'breakindent'.
Problem:
The LSP omnifunc can insert nil bytes, which when read in other places
(like semantic token) could cause an error:
semantic_tokens.lua:304: Vim:E976: Using a Blob as a String
Solution:
Use `#line` instead of `vim.fn.strlen(line)`. Both return UTF-8 bytes
but the latter can't handle nil bytes.
Completion candidates can currently insert nil bytes, if other parts of
Alternative fix to https://github.com/neovim/neovim/pull/30359
Note that https://github.com/neovim/neovim/pull/30315 will avoid the
insertion of nil bytes from the LSP omnifunc, but the change of this PR
can more easily be backported.
Problem:
str_utfindex_enc could return an error if the index was longer than the
line length. This was handled in each of the calls to it individually
Solution:
* Fix the call at the source level so that if the index is higher than
the line length, utf length is returned
Problem:
str_byteindex_enc could return an error if the index was longer than the
lline length. This was handled in each of the calls to it individually
Solution:
* Fix the call at the source level so that if the index is higher than
the line length, line length is returned as per LSP specification
* Remove pcalls on str_byteindex_enc calls. No longer needed now that
str_byteindex_enc has a bounds check.
Reverts https://github.com/neovim/neovim/pull/29212 and adds a few
additional test cases
From the spec
> All text edits ranges refer to positions in the document they are
> computed on. They therefore move a document from state S1 to S2 without
> describing any intermediate state. Text edits ranges must never overlap,
> that means no part of the original document must be manipulated by more
> than one edit. However, it is possible that multiple edits have the same
> start position: multiple inserts, or any number of inserts followed by a
> single remove or replace edit. If multiple inserts have the same
> position, the order in the array defines the order in which the inserted
> strings appear in the resulting text.
The previous fix seems wrong. The important part:
> If multiple inserts have the same position, the order in the array
> defines the order in which the inserted strings appear in the
> resulting text.
Emphasis on _appear in the resulting text_
Which means that in:
local edits1 = {
make_edit(0, 3, 0, 3, { 'World' }),
make_edit(0, 3, 0, 3, { 'Hello' }),
}
`World` must appear before `Hello` in the final text. That means the old
logic was correct, and the fix was wrong.
This reduces the number of nil checks around buf_versions usage
Test changes were lifted from 5c33815
Co-authored-by: Mathias Fussenegger <f.mathias@zignar.net>
Problem:
Text edits with the same position (both line and character) were being
reverse sorted prior to being applied which differs from the lsp spec
Solution:
Change the sort order for just the same position edits
* Revert "fix(lsp): account for changedtick version gap on modified reset (#29170)"
This reverts commit 2e6d295f79.
* Revert "refactor(lsp): replace util.buf_versions with changedtick (#28943)"
This reverts commit 5c33815448.
`lsp.util.buf_versions` was already derived from changedtick (`on_lines`
from `buf_attach` synced the version)
As far as I can tell there is no need to keep track of the state in a
separate table.