]> Sergey Matveev's repositories - vim-lsp.git/commitdiff
Add support for CompletionItem commands
authorMagnus Groß <magnus@mggross.com>
Sun, 3 Sep 2023 22:57:59 +0000 (00:57 +0200)
committerMagnus Groß <magnus@mggross.com>
Mon, 4 Sep 2023 15:54:00 +0000 (17:54 +0200)
When we resolve a completion item with a "completionItem/resolve"
request, the LSP server returns a CompletionItem object [0], which may
contain an optional "command" field. This field describes a command that
must be called **after** inserting the completion.

For example the haskell-language-server may respond with the following
command after autocompleting an unimported function (arguments are left
out for brevity):

{'command': '10619:ghcide-extend-import-action:extendImport', 'arguments': [], 'title': 'extend import'}

Then when we send the matching "workspace/executeCommand" request, the
server will respond with a "workspace/applyEdit" request, that
autoimports the function.

Technically the specification dictates that servers should prefer to set
"additionalTextEdits" for that usecase, but there is still some use for
doing it this way, e.g. haskell-language-server also wants to display an
info message to the user, which doesn't happen with
"additionalTextEdits".

In any case it is important to support the "command" field, as it may
also contain actions unrelated to "additionalTextEdits".

[0] https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItem

autoload/lsp/completion.vim

index 3d1c2be3de3db1c510337959d839cc5249a75025..0d64e2b9d9ccbf0aac52de51d4bc2fc0d9dba19e 100644 (file)
@@ -7,6 +7,7 @@ import './buffer.vim' as buf
 import './options.vim' as opt
 import './textedit.vim'
 import './snippet.vim'
+import './codeaction.vim'
 
 # per-filetype omni-completion enabled/disabled table
 var ftypeOmniCtrlMap: dict<bool> = {}
@@ -590,12 +591,17 @@ def LspCompleteDone(bnr: number)
     # additional text edits.  So try to resolve the completion item now to get
     # the text edits.
     completionData = lspserver.resolveCompletion(completionData, true)
-    if completionData->get('additionalTextEdits', {})->empty()
-      return
+    if !completionData->get('additionalTextEdits', {})->empty()
+      textedit.ApplyTextEdits(bnr, completionData.additionalTextEdits)
     endif
   endif
 
-  textedit.ApplyTextEdits(bnr, completionData.additionalTextEdits)
+  if completionData->has_key('command')
+    # Some language servers (e.g. haskell-language-server) want to apply
+    # additional commands after completion.
+    codeaction.DoCommand(lspserver, completionData.command)
+  endif
+
 enddef
 
 # Initialize buffer-local completion options and autocmds