autozimu / LanguageClient-neovim

Language Server Protocol (LSP) support for vim and neovim.
MIT License
3.55k stars 272 forks source link

Single server for multiple filetypes #1186

Open rottencandy opened 3 years ago

rottencandy commented 3 years ago

Is your feature request related to a problem? Please describe.

Some languages have a single server that can target multiple different filetypes. For example typescript-language-server that works with javascript, typescript & jsx. Or clangd that can work with C, C++, etc.

When working on a project where both filetypes are used, it spins up multiple servers, which feels like a waste of resources and unnecessary duplicated work.

Describe the solution you'd like

It would be great to have a single server set up for multiple filetypes.

I'm unsure if the current way of specifying servers using g:LanguageClient_serverCommands would be sufficient, since it only allows a 1:1 mapping of language to server.

Perhaps it would be possible to extend it? Something like:

let g:LanguageClient_serverCommands = {
\  'js-ts': { 'server': ['typescript-language-server', '--stdio'], 'languages': ['javascript', 'typescript'] }
\ }
martskins commented 3 years ago

Hm there's an open issue here that actually requests the opposite, being able to launch more than one server for a single language type, but this one I don't think we have considered before. This is a rather involved change, but leaving that complexity aside, does the protocol specify whether a single instance of a server should be able to handle different languages? Or is that property derived from somewhere else maybe? I ask because if this is not specified by the protocol I can imagine servers having different behaviours and possibly not every one of them playing nicely to this.


As a side note, we've recently added a different way to specify the server commands, you can do this:

 let g:LanguageClient_serverCommands = {
        \ 'rust': ['rustup', 'run', 'stable', 'rls'],
        \ 'go': {
        \   'name': 'gopls',
        \   'command': ['gopls'],
        \   'initializationOptions': {
        \     'usePlaceholders': v:true,
        \     'codelens': {
        \       'generate': v:true,
        \       'test': v:true,
        \     },
        \   },
        \ },
        \}

or the way we already supported:

let g:LanguageClient_serverCommands = {
        \ 'javascript': ['tcp://127.0.0.1:2089'],
        \ }
rottencandy commented 3 years ago

Haven't seen this mentioned in the protocol spec. But I'd say that it would work, since the supported languages can be used together, like importing a js file inside ts. The server would have to do the same work for both of them anyway. I've also used clients in the past that supported a single server for multiple filetypes, and the servers I mentioned worked fine.

rottencandy commented 3 years ago

Another benefit I can think of: Unsaved changes in one filetype's buffer can be recognized and considered by the server in another filetype, if both filetypes share a single server.

It wouldn't be possible if the filetypes have separate servers, as they would not be aware of changes outside of their own filetype.