Skip to content

fix(lsp): Convert LSP positions to each client's offset encoding - #49

Merged
mhiro2 merged 3 commits into
mainfrom
fix/lsp-offset-encoding
Oct 3, 2026
Merged

mhiro2 merged 3 commits into
mainfrom
fix/lsp-offset-encoding

Conversation

@mhiro2

@mhiro2 mhiro2 commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • LSP requests and responses are converted between byte columns and each client's offset_encoding, so popups open on the right column on lines with Japanese text or emoji.
  • All internal locations use byte columns, so the same-position filter compares the cursor and results in one unit.
  • LocationLink results land on targetSelectionRange instead of the whole targetRange.

Changes

  • 3e5048a : fix(lsp): convert positions between byte columns and client offset encoding
    • The request position is sent in each client's encoding, and returned ranges (including document symbols) are converted back to bytes from the loaded buffer or the file on disk.
    • Covers UTF-8 / UTF-16 / UTF-32, multiple clients, unloaded files and requests from a copy popup.
  • 1b1e22e : fix(location): land LocationLink results on targetSelectionRange
    • Popups open on the symbol name, and requests from inside a function body are no longer dropped as the same position.
    • The unused originSelectionRange copy, kept in client units, is no longer stored.
  • d43226b : fix(lsp): convert against the text Neovim shows and isolate failures
    • Unloaded files are read without BOM and CRs, and loaded buffers are matched by resolved path so unsaved text wins over stale disk content.
    • A response that fails to convert no longer discards its client's slot and delays completion until the timeout.

mhiro2 added 3 commits October 3, 2026 08:58
…coding

LSP requests sent the cursor's byte column as the position character and
used the response characters as byte columns, so on lines with Japanese
text or emoji a UTF-16 server received the wrong position and popups
opened on the wrong column.

- Convert the request position into each client's offset_encoding and
  convert every returned range, including document symbols, back to byte
  columns using the loaded buffer or the file on disk.
- Keep all internal locations in byte columns so the same-position filter
  compares the cursor and results in one unit.
- Cover UTF-8 / UTF-16 / UTF-32, multiple clients, unloaded files and
  requests from a copy popup.
LocationLink results used targetRange, which spans the whole symbol, so
popups opened at the start of the declaration instead of its name, and a
request from inside a function body was dropped as the same position.
The link's selection range is now the location range for both navigation
and the same-position filter, and the unused originSelectionRange copy,
kept in client units, is no longer stored.
Column conversion read unloaded files byte for byte and matched loaded
buffers by exact URI, so a UTF-8 BOM shifted the first line, and a
symlinked or differently escaped URI fell back to stale disk text instead
of the unsaved buffer.

- Strip the BOM and CRs when reading unloaded files, and match loaded
  buffers by resolved path as well as by URI.
- Convert inside the per-response pcall so a malformed response no longer
  discards that client's slot and delays completion until the timeout.
- Cover multiline ranges, LocationLink selection ranges and malformed
  responses alongside valid clients.
@mhiro2 mhiro2 self-assigned this Oct 3, 2026
@mhiro2 mhiro2 added the bug Something isn't working label Oct 3, 2026
@mhiro2
mhiro2 merged commit 8334766 into main Oct 3, 2026
3 checks passed
@mhiro2
mhiro2 deleted the fix/lsp-offset-encoding branch October 3, 2026 00:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant