# Using JETLS in neovim with dynamic registration

**URL:** <https://discourse.julialang.org/t/using-jetls-in-neovim-with-dynamic-registration/137196>\
**Category:** Tooling\
**Tags:** neovim, lsp, jetls\
**Created:** [May 19, 2026, 4:02pm UTC](https://discourse.julialang.org/t/using-jetls-in-neovim-with-dynamic-registration/137196 "2026-05-19T16:02:51Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![qwjyh](https://avatars.discourse-cdn.com/v4/letter/q/a4c791/32.png) [@qwjyh](https://discourse.julialang.org/u/qwjyh)\
**Post date:** [May 19, 2026, 4:02pm UTC](https://discourse.julialang.org/t/using-jetls-in-neovim-with-dynamic-registration/137196/1 "2026-05-19T16:02:51Z")

</div>

Since JETLS assumes `textDocuments/completions/dynamicRegistration = true` ([LSP specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionClientCapabilities)) in capabilities (for “lazy completion”) while cmp-nvim-lsp doesn’t support dynamic registration ([source](https://github.com/hrsh7th/cmp-nvim-lsp/blob/cbc7b02bb99fae35cb42f514762b89b5126651ef/lua/cmp_nvim_lsp/init.lua#L43)), it seems that the completion candidates are not updated correctly.

I also checked nvim’s built-in completion, [mini.completion](https://github.com/nvim-mini/mini.completion/blob/04abe6fc7860858785ba63c435d76bf5b8b64b5f/lua/mini/completion.lua#L647), and [blink.cmp](https://github.com/saghen/blink.cmp/blob/2ef3db111181c5eef22a462aa0122349a6027f28/doc/development/lsp-tracker.md?plain=1#L9), but none of them supports this features according to the client capabilities definitions on the source codes and `:=vim.lsp.protocol.make_client_capabilities()['textDocument']['completion']['dynamicRegistration']`.  
[nvim-cmp-kit](https://github.com/hrsh7th/nvim-cmp-kit/blob/b2f8930ed9d2ee7c1269202e884972a039173c0d/lua/cmp-kit/init.lua#L9) seems to support this feature but it looks experimental.

Does anyone have a configuration for JETLS with properly working completion?

---

<div class="post-metadata">

**Author:** ![qwjyh](https://avatars.discourse-cdn.com/v4/letter/q/a4c791/32.png) [@qwjyh](https://discourse.julialang.org/u/qwjyh)\
**Post date:** [May 22, 2026, 1:57pm UTC](https://discourse.julialang.org/t/using-jetls-in-neovim-with-dynamic-registration/137196/2 "2026-05-22T13:57:12Z")

</div>

I found that client not supporting `textDocuments/completions/dynamicRegistration` is not the cause of the problem.  
Even though client doesn’t allow resolving completion item kind later (in client capabilities, `textDocuments/completion/completionItem/resolveSupport` ([definition in LSP specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionClientCapabilities) doesn’t include kind (for cmp-nvim-lsp, defined [here](https://github.com/hrsh7th/cmp-nvim-lsp/blob/cbc7b02bb99fae35cb42f514762b89b5126651ef/lua/cmp_nvim_lsp/init.lua#L55-L62))) while JETLS updates kind during `completionItem/resolve`.

Below are dumped JSON RPC when completing

```julia
V # here's the cursor

```

> **JSON RPC log**
>
> First `textDocument/completion` request:
> 
> ```json
> {
> "jsonrpc": "2.0",
> "method": "textDocument/completion",
> "id": 11,
> "params": {
> "textDocument": {
> "uri": "file:///tmp/example.jl"
> },
> "position": {
> "line": 0,
> "character": 1
> },
> "context": {
> "triggerKind": 1
> }
> }
> }
> 
> ```
> 
> part of the response:
> 
> ```json
> {
> "label": "Val",
> "labelDetails": {
> "description": "global"
> },
> "sortText": "100000",
> "insertTextFormat": 1,
> "textEdit": {
> "range": {
> "start": {
> "line": 0,
> "character": 0
> },
> "end": {
> "line": 0,
> "character": 1
> }
> },
> "newText": "Val"
> },
> "data": {
> "resolver_id": "##GlobalCompletionResolverInfo_resovler_id#286",
> "name": "Val"
> }
> }
> 
> ```
> 
> then, `completionItem/resolve` request:
> 
> ```json
> {
> "jsonrpc": "2.0",
> "method": "completionItem/resolve",
> "id": 21,
> "params": {
> "sortText": "100000",
> "textEdit": {
> "newText": "Val",
> "range": {
> "end": {
> "line": 0,
> "character": 1
> },
> "start": {
> "line": 0,
> "character": 0
> }
> }
> },
> "data": {
> "resolver_id": "##GlobalCompletionResolverInfo_resovler_id#286",
> "name": "Val"
> },
> "insertTextFormat": 1,
> "label": "Val",
> "labelDetails": {
> "description": "global"
> }
> }
> }
> 
> ```
> 
> and its response:
> 
> ````json
> {
> "jsonrpc": "2.0",
> "id": 21,
> "result": {
> "label": "Val",
> "labelDetails": {
> "description": "global [type]"
> },
> "kind": 22,
> "detail": "[type]",
> "documentation": {
> "kind": "markdown",
> "value": "```julia\nVal(c)\n```\n\nReturn `Val{c}()`, which contains no run-time data. Types like this can be used to pass the information between functions through the value `c`, which must be an `isbits` value or a `Symbol`. The intent of this construct is to be able to dispatch on constants directly (at compile time) without having to test the value of the constant at run time.\n\n# Examples\n\n```julia\njulia> f(::Val{true}) = \"Good\"\nf (generic function with 1 method)\n\njulia> f(::Val{false}) = \"Bad\"\nf (generic function with 2 methods)\n\njulia> f(Val(true))\n\"Good\"\n```\n"
> },
> "sortText": "100000",
> "insertTextFormat": 1,
> "textEdit": {
> "range": {
> "start": {
> "line": 0,
> "character": 0
> },
> "end": {
> "line": 0,
> "character": 1
> }
> },
> "newText": "Val"
> },
> "data": {
> "resolver_id": "##GlobalCompletionResolverInfo_resovler_id#286",
> "name": "Val"
> }
> }
> }
> 
> ````
> 
> `result.kind` is updated later (22 = Struct)

Since this is the problem of JETLS, I’ll open an issue on JETLS repo.

---

<div class="post-metadata">

**Author:** ![qwjyh](https://avatars.discourse-cdn.com/v4/letter/q/a4c791/32.png) [@qwjyh](https://discourse.julialang.org/u/qwjyh)\
**Post date:** [May 22, 2026, 2:36pm UTC](https://discourse.julialang.org/t/using-jetls-in-neovim-with-dynamic-registration/137196/3 "2026-05-22T14:36:45Z")

</div>

> <https://github.com/aviatesk/JETLS.jl/issues/711>
>
> \### Pre-submission checklist
> 
> \- \[x\] I have searched \[existing issues\](https://gi…thub.com/aviatesk/JETLS.jl/issues) and confirmed this is not a duplicate.
> 
> \### Client
> 
> Neovim 0.12.2 with builtin LSP client and cmp-nvim-lsp completion plugin (https://github.com/hrsh7th/cmp-nvim-lsp)
> 
> \### Julia \`versioninfo()\`
> 
> \`\`\`text
> julia\> versioninfo()
> Julia Version 1.12.6
> Commit 15346901f00 (2026-04-09 19:20 UTC)
> Build Info:
> Official https://julialang.org release
> Platform Info:
> OS: Linux (aarch64-linux-gnu)
> CPU: 8 × unknown
> WORD\_SIZE: 64
> LLVM: libLLVM-18.1.7 (ORCJIT, apple-m2)
> GC: Built with stock GC
> Threads: 1 default, 1 interactive, 1 GC (on 8 virtual cores)
> \`\`\`
> 
> \### JETLS version
> 
> 2026-05-08
> 
> \### Reproduction with the VSCode reference client
> 
> \- \[x\] I have confirmed this issue also reproduces with the VSCode reference client.
> \- \[\] This issue does NOT reproduce with the VSCode reference client, but I believe JETLS-side changes are needed.
> 
> \### Description
> 
> Some properties (\`kind\`) in \`completionItem\` is resolved later even though that property is not listed in \[\`CompletionClientCapabilities.completionItem.resolveSupport.properties\`\](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionClientCapabilities).
> This cause client completion list updated abnormally like this record
> 
> https://github.com/user-attachments/assets/c867e3ea-c35c-4ed4-9dd9-cd57f546f53e
> 
> On VS code, completion item kind is not propery displayed:
> 
> \<img width="563" height="143" alt="Image" src="https://github.com/user-attachments/assets/0d82f696-c8bb-44f1-a69f-6a7ddcef69b0" /\>
> 
> In this image, even \`xor\` is a function, it is displayed as a property (\[icon description\](https://code.visualstudio.com/docs/editing/intellisense#\_types-of-completions)).
> 
> Properties not listed in \`resolveSupport\` should be resolved in the first \`textDocument/completion\` request.
> It seems that VS code also doesn't support resolving "kind" lazily \[vscode-languageserver-node\](https://github.com/microsoft/vscode-languageserver-node/blob/d4f8eae22e6a33ff63a7fb57e977142d60360bbe/client/src/common/completion.ts#L84)
> 
> From LSP spec:
> \`\`\`js
> /\*\*
> \* Indicates which properties a client can resolve lazily on a
> \* completion item. Before version 3.16.0 only the predefined properties
> \* \`documentation\` and \`detail\` could be resolved lazily.
> \*
> \* @since 3.16.0
> \*/
> resolveSupport?: {
> /\*\*
> \* The properties that a client can resolve lazily.
> \*/
> properties: string\[\];
> };
> \`\`\`
> 
> For cmp-nvim-lsp, \`resolveSupport\` in client capabilities is defined \[here\](https://github.com/hrsh7th/cmp-nvim-lsp/blob/cbc7b02bb99fae35cb42f514762b89b5126651ef/lua/cmp\_nvim\_lsp/init.lua#L55-L62).
> 
> Below are dumped JSON RPC when completing (dumped using \`socat\`)
> \`\`\`julia
> V # here's the cursor
> \`\`\`
> \<details\>
> \<summary\>
> JSON RPC log
> \</summary\>
> 
> First \`textDocument/completion\` request:
> \`\`\`json
> {
> "jsonrpc": "2.0",
> "method": "textDocument/completion",
> "id": 11,
> "params": {
> "textDocument": {
> "uri": "file:///tmp/example.jl"
> },
> "position": {
> "line": 0,
> "character": 1
> },
> "context": {
> "triggerKind": 1
> }
> }
> }
> \`\`\`
> 
> part of the response:
> \`\`\`json
> {
> "label": "Val",
> "labelDetails": {
> "description": "global"
> },
> "sortText": "100000",
> "insertTextFormat": 1,
> "textEdit": {
> "range": {
> "start": {
> "line": 0,
> "character": 0
> },
> "end": {
> "line": 0,
> "character": 1
> }
> },
> "newText": "Val"
> },
> "data": {
> "resolver\_id": "##GlobalCompletionResolverInfo\_resovler\_id#286",
> "name": "Val"
> }
> }
> \`\`\`
> 
> then, \`completionItem/resolve\` request:
> \`\`\`json
> {
> "jsonrpc": "2.0",
> "method": "completionItem/resolve",
> "id": 21,
> "params": {
> "sortText": "100000",
> "textEdit": {
> "newText": "Val",
> "range": {
> "end": {
> "line": 0,
> "character": 1
> },
> "start": {
> "line": 0,
> "character": 0
> }
> }
> },
> "data": {
> "resolver\_id": "##GlobalCompletionResolverInfo\_resovler\_id#286",
> "name": "Val"
> },
> "insertTextFormat": 1,
> "label": "Val",
> "labelDetails": {
> "description": "global"
> }
> }
> }
> \`\`\`
> 
> and its response:
> \`\`\`json
> {
> "jsonrpc": "2.0",
> "id": 21,
> "result": {
> "label": "Val",
> "labelDetails": {
> "description": "global \[type\]"
> },
> "kind": 22,
> "detail": "\[type\]",
> "documentation": {
> "kind": "markdown",
> "value": "\`\`\`julia\\nVal(c)\\n\`\`\`\\n\\nReturn \`Val{c}()\`, which contains no run-time data. Types like this can be used to pass the information between functions through the value \`c\`, which must be an \`isbits\` value or a \`Symbol\`. The intent of this construct is to be able to dispatch on constants directly (at compile time) without having to test the value of the constant at run time.\\n\\n# Examples\\n\\n\`\`\`julia\\njulia\> f(::Val{true}) = \\"Good\\"\\nf (generic function with 1 method)\\n\\njulia\> f(::Val{false}) = \\"Bad\\"\\nf (generic function with 2 methods)\\n\\njulia\> f(Val(true))\\n\\"Good\\"\\n\`\`\`\\n"
> },
> "sortText": "100000",
> "insertTextFormat": 1,
> "textEdit": {
> "range": {
> "start": {
> "line": 0,
> "character": 0
> },
> "end": {
> "line": 0,
> "character": 1
> }
> },
> "newText": "Val"
> },
> "data": {
> "resolver\_id": "##GlobalCompletionResolverInfo\_resovler\_id#286",
> "name": "Val"
> }
> }
> }
> \`\`\`
> 
> \`result.kind\` is updated later (22 = Struct)
> \</details\>
> 
> \### Steps to reproduce
> 
> 1. Open any julia file
> 2. Type any character and trigger \`textDocument/completion\`
> 3. Select candidate triggering \`completionItem/resolve\`
> 
> \### JETLS configuration (if applicable)
> 
> \_No response\_
> 
> \### Additional context (optional)
> 
> \_No response\_
