ocaml-lsp
ocaml-lsp copied to clipboard
Incorrect completion range start position for polymorphic variants
When triggering completion just after the ` character of a polymorphic variant's name, the LSP returns completion items where the start and end positions are identical and equal to the position after the `. This causes the client to interpret the completion item as simply inserting text instead of also replacing the already typed ` character upon resolving the completion.
Example
Consider the following code:
type t = [ `T1 | `T2 ]
let x : t = `
Triggering autocomplete after the backtick character (at character 13) results in the wrong behaviour with the LSP returning completion items with ranges where start = end = 13. I would expect the returned items to have a start = 12 and end = 13 so that the completion client can correctly replace the ` character when resolving the completion edit.
If taking the same code, but triggering completion after having typed another character it works correctly.
type t = [ `T1 | `T2 ]
let x : t = `T
In this case triggering completion after the T character (character 14) the LSP returns completion items with ranges where start = 12 and end = 14 which leads to the client being able to correctly interpret the text edit required for resolving the autocomplete.
Ocaml-lsp version:
1.20.1
Logs:
LSP logs from my neovim for the incorrect example
It also returns a lot of irrelevant completion items (which makes the textdocument/completion response too long for github so I'll attach it in a file). However, all the returned completion items share the same incorrect range.
[DEBUG][2024-12-18 18:10:42] ...m/lsp/client.lua:678 "LSP[ocamllsp]" "client.request" 1 "textDocument/completion" { context = { triggerKind = 1 }, position = { character = 13, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" }} <function 1> 1
... (see file for response)
[DEBUG][2024-12-18 18:10:42] ...m/lsp/client.lua:678 "LSP[ocamllsp]" "client.request" 1 "completionItem/resolve" { data = { position = { character = 13, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" } }, deprecated = false, detail = "`T1", kind = 20, label = "`T1", sortText = "0000", textEdit = { newText = "`T1", range = { ["end"] = { character = 13, line = 2 }, start = { character = 13, line = 2 } } }} <function 1> 1
[DEBUG][2024-12-18 18:10:42] .../vim/lsp/rpc.lua:286 "rpc.send" { id = 12, jsonrpc = "2.0", method = "completionItem/resolve", params = { data = { position = { character = 13, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" } }, deprecated = false, detail = "`T1", kind = 20, label = "`T1", sortText = "0000", textEdit = { newText = "`T1", range = { ["end"] = { character = 13, line = 2 }, start = { character = 13, line = 2 } } } }}
[DEBUG][2024-12-18 18:10:42] .../vim/lsp/rpc.lua:408 "rpc.receive" { id = 12, jsonrpc = "2.0", result = { deprecated = false, detail = "`T1", kind = 20, label = "`T1", sortText = "0000", textEdit = { newText = "`T1", range = { ["end"] = { character = 13, line = 2 }, start = { character = 13, line = 2 } } } }}
LSP logs for the correct (second) example:
[DEBUG][2024-12-18 18:08:38] .../vim/lsp/rpc.lua:286 "rpc.send" { id = 11, jsonrpc = "2.0", method = "textDocument/completion", params = { context = { triggerKind = 1 }, position = { character = 14, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" } }}
[DEBUG][2024-12-18 18:08:38] .../vim/lsp/rpc.lua:408 "rpc.receive" { id = 11, jsonrpc = "2.0", result = { isIncomplete = false, items = { { data = { position = { character = 14, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" } }, deprecated = false, detail = "`T1", kind = 20, label = "`T1", sortText = "0000", textEdit = { newText = "`T1", range = { ["end"] = { character = 14, line = 2 }, start = { character = 12, line = 2 } } } }, { data = { position = { character = 14, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" } }, deprecated = false, detail = "`T2", kind = 20, label = "`T2", sortText = "0001", textEdit = { newText = "`T2", range = { ["end"] = { character = 14, line = 2 }, start = { character = 12, line = 2 } } } } } }}
[DEBUG][2024-12-18 18:08:38] ...m/lsp/client.lua:678 "LSP[ocamllsp]" "client.request" 1 "completionItem/resolve" { data = { position = { character = 14, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" } }, deprecated = false, detail = "`T1", kind = 20, label = "`T1", sortText = "0000", textEdit = { newText = "`T1", range = { ["end"] = { character = 14, line = 2 }, start = { character = 12, line = 2 } } }} <function 1> 1
[DEBUG][2024-12-18 18:08:38] .../vim/lsp/rpc.lua:286 "rpc.send" { id = 12, jsonrpc = "2.0", method = "completionItem/resolve", params = { data = { position = { character = 14, line = 2 }, textDocument = { uri = "file:///home/kristof/ocaml-test/main.ml" } }, deprecated = false, detail = "`T1", kind = 20, label = "`T1", sortText = "0000", textEdit = { newText = "`T1", range = { ["end"] = { character = 14, line = 2 }, start = { character = 12, line = 2 } } } }}
[DEBUG][2024-12-18 18:08:38] .../vim/lsp/rpc.lua:408 "rpc.receive" { id = 12, jsonrpc = "2.0", result = { deprecated = false, detail = "`T1", kind = 20, label = "`T1", sortText = "0000", textEdit = { newText = "`T1", range = { ["end"] = { character = 14, line = 2 }, start = { character = 12, line = 2 } } } }}