Skip to content

Conversation

@cutiful
Copy link

@cutiful cutiful commented Sep 7, 2025

I was having an issue with method/property completions in TypeScript. Pressing C-X C-O immediately after the dot worked, as did doing it after typing one or two characters after the dot. However completing something like new Function().app to "apply" didn't.

After some debugging, I realized that the text of the completion was getting mangled, so it no longer had the prefix the filter function was looking for. When the column reported by the language server is greater than the current cursor column, the offset calculated by the textEdit handler becomes negative, and d.word is set to the last few characters of newText. I think #161, which introduced the offset, was only meant to apply in cases where LSP column is less than cursor column.

I also looked into the reason this happens in the first place. typescript-language-server finds the dot accessor . or ?. and tries to send a completion that includes it (presumably to allow tsserver to replace . with ?.). It calculates the range based on the current column and the length of the accessor. But, at the same time the completion is requested, it receives a textDocument/didChange notification replacing document contents with a shorter line, one that only includes the text up to the dot.

For example, when I type new Function().app and press C-X C-O, this is the document the language server receives (15 characters on that line):

new Function().

And the completion is requested with the starting position at character 17. So the length of the dot is 1, the starting position of the textEdit span is 17 - 1 = 16, which is greater than the column inside CompletionReply. Trying to find the text of the accessor it gets an empty string; the result is a correct newText not including the accessor dot and with a broken range.

The math typescript-language-server uses is wrong in that case, but I don't want to open an issue there, because I'm not sure this is a correct request from the LSP client. This PR doesn't fix the underlying problem, but it does work around the completions issue after new Function().app by removing a bug and leaving a not fully correct behavior in its place. Feel free to reject if it's too hacky.

(Apologies for the edits, I couldn't find the right PR to reference.)

When the range of a `textEdit` completion starts after the current
column, applying a negative offset mangles completion text.

Additionally, treat the LSP range as zero-indexed in both comparison and
offset calculation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant