yegappan / lsp

Language Server Protocol (LSP) plugin for Vim9
MIT License
480 stars 56 forks source link

How to get several language servers to cooperate on the same filetype? #369

Open MartinAskestad opened 1 year ago

MartinAskestad commented 1 year ago

I've added a few language servers, for example I have vscode-css language server that gives me a great hover function to preview how my selectors behave and I get diagnostics to tell me when something is wrong. This is great. I also add Emmet-language-server to get a different kind of completion.

How ever, when I do it doesn't work, having both servers running, I'm not getting the Emmet completion. I've tried setting features: #{ completion: v:true } on Emmet and false on vscode-css, but this doesn't help. I've tried changing the order of when the servers are added, hasn't helped.

This is the output of LspServer show capabilities

'C:\Users\m\scoop\apps\nodejs-lts\current\bin\emmet-language-server.cmd' Language Server Capabilities

completionProvider: {'resolveProvider': false} textDocumentSync: 2

'C:\Users\m\scoop\apps\nodejs-lts\current\bin\vscode-css-language-server.cmd' Language Server Capabilities

codeActionProvider: true colorProvider: {} definitionProvider: true diagnosticProvider: {'workspaceDiagnostics': false, 'interFileDependencies': false, 'documentSelector': null} documentFormattingProvider: false documentHighlightProvider: true documentLinkProvider: {'resolveProvider': false} documentRangeFormattingProvider: false documentSymbolProvider: true foldingRangeProvider: true hoverProvider: true referencesProvider: true renameProvider: true selectionRangeProvider: true textDocumentSync: 2

And this is a snippet from my vimrc

      \ #{ name: 'css', filetype: ['css', 'scss'],
      \ path: expand('$HOME/scoop/apps/nodejs-lts/current/bin/vscode-css-language-server.cmd'),
      \ args: ['--stdio'], features: #{ snippetSupport: v:true, completion: v:false } },
      \ #{ name: 'emmet', filetype: ['html', 'css', 'scss'],
      \ path: expand('$HOME/scoop/apps/nodejs-lts/current/bin/emmet-language-server.cmd'),
      \ args: ['--stdio'], features: #{ completion: v:true } },

Any suggestions on what I'm doing wrong is much appriciated.

Shane-XB-Qian commented 1 year ago

https://github.com/yegappan/lsp/issues/368#issuecomment-1656811086

yegappan commented 1 year ago

I am not able to reproduce this problem using the vscode-css language and the emmet language servers. I registered these servers using the following commands:

  call LspAddServer([#{name: 'vscode-css',
                   \   filetype: 'css',
                   \   path: '/home/yega/node_modules/.bin/vscode-css-language-server',
                   \   args: ['--stdio'],
           \   features: #{
           \      completion: v:false,
           \   },
               \   debug: v:true,
                   \ }])

  call LspAddServer([#{name: 'emmet',
                   \   filetype: 'css',
                   \   path: '/home/yega/node_modules/.bin/emmet-language-server',
                   \   args: ['--stdio'],
           \   features: #{
           \      completion: v:true,
           \   },
               \   debug: v:true,
                   \ }])

The emmet server is used for getting completion matches and the vscode-css language server is used for everything else.

MartinAskestad commented 1 year ago

I have used LspOptionsSet to set a bunch of settings I want to use, and I think something among them caused the issue. Because I got it to work when I removed the call to LspOptionsSet.

yegappan commented 1 year ago

Are you setting the options from the .vimrc file or are you dynamically changing the options at runtime? If you can get the list of steps that can reproduce the issue, then it will be helpful for debugging.

MartinAskestad commented 1 year ago

This is what my vimrc looks like right now regarding lsp, I don't change anything after the fact. I think it might have something to do with inlay hints because I'm getting a message saying Key not present in Dictionary: "isInlayHintProvider".

packadd lsp
call LspAddServer([#{ name: 'vscode-css',
      \ filetype: 'css',
      \ path: 'vscode-css-language-server.cmd',
      \ args: ['--stdio'],
      \ features: #{
      \   completion: v:false,
      \ },
      \ debug: v:true,
      \ },
      \ #{ name: 'emmet',
      \ filetype: 'css',
      \ path: 'emmet-language-server.cmd',
      \ args: ['--stdio'],
      \ features: #{
      \   completion: v:true,
      \ },
      \ debug: v:true,
      \ }])

let lsp_options = #{
      \ autoHighlight: v:true,
      \ autoHighlightDiags: v:true,
      \ autoPopulateDiags: v:true,
      \ completionMatcher: 'fuzzy',
      \ diagVirtualTextAlign: 'after',
      \ echoSignature: v:true,
      \ hideDisabledCodeActions: v:true,
      \ ignoreMissingServer: v:true,
      \ noNewlineInCompletion: v:false,
      \ showDiagWithVirtualText: v:true,
      \ showInlayHints: v:true,
      \ usePopupInCodeAction: v:true,
      \}
call LspOptionsSet(lsp_options)
yegappan commented 1 year ago

I am able to reproduce the problem using your code snippet and fixed the issue. I have committed 165ec19af8089bdb3701e2a8c061cccd6cc2a871 with the fix for this issue. Can you try the latest plugin version?

MartinAskestad commented 1 year ago

I think I'm starting to understand how the lsp-plugin works. If we move from css to html, in vscode I used the vscode-html-language-server obviously since it's built in. I also added angular-language-service since I frequently work with angular projects.

So I added both to my vimrc and tried the hover feature. I get the hover from what ever lsp I added first in the LspAddServer command, I can of course control this using the features property. So for this example in vscode

<button (click)="onClick()">click</button>

If I hover over the button I get the html lsp hover, but if I hover over the onClick() I get the angular-lsp hover. This is because html-lsp doesn't know about that attribute, but angular does.

In the vim lsp plugin I can only pick hover for one or the other, not both so I can either have useful hovers for html or useful hovers for angular specific attributes, not both. This example is a bit contrived since hovers on html-documents probably isn't that big deal, but I believe this applies to other parts of lsp too.

The reason for only getting one or the other I think is lsp.vim line 766 def Hover that only tries to get hovers from one lsp. I think what it probably should to is retrieve a list of servers that supports hover, try to hover the cursor location for each and if the server returns a positive result display that result.

This will make the order of loading lsp important, but in the button example above, it should result in the same behavior as vscode. And I'm guessing its the same for definition, declaration, rename and such?

What do you think? Being able to query several servers for the same feature and pick the result would be a great improvement.