Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Language Server Implementation (LSP) #5522

Closed
tjdevries opened this issue Oct 22, 2016 · 47 comments
Closed

Language Server Implementation (LSP) #5522

tjdevries opened this issue Oct 22, 2016 · 47 comments
Labels
enhancement feature request lsp needs:design needs a clear design proposal needs:discussion issue needs attention from an expert, or PR proposes significant changes to architecture or API plugin plugins and Vim "pack"
Milestone

Comments

@tjdevries
Copy link
Contributor

@justinmk, I have been looking into trying to write some sort of shim/plugin/client (still not sure what the name should be) to provide (at least some amount of) integration between the language server protocol and Neovim.

I have read your discussion in Gitter a bit ago and it got me interested in trying to implement some part of it. However, before I got working on implementing it, I wanted to try and figure out if I was understanding the idea of the integration correctly.

I made this diagram to explain some of what I was thinking. Obviously there are a lot more scenarios to cover, but this is what I was thinking.

basic

Also, do you know what language this client should be written in? I was thinking one of the remote plugins. It appears that Microsoft is working with this (https://github.com/Microsoft/vscode-languageserver-node) for a lot of their stuff, and we might be able to use it as well. Do you know which of the neovim node libraries would work well with this?

Thanks.

@KillTheMule
Copy link
Contributor

Awesome, this things seems to be getting traction: https://internals.rust-lang.org/t/introducing-rust-language-server-source-release/4209.

@tjdevries
Copy link
Contributor Author

Yeah, it looks like there are several implementations coming along quite nicely (https://github.com/Microsoft/language-server-protocol/wiki/Protocol-Implementations). I think this would be a pretty killer feature for neovim.

@justinmk
Copy link
Member

The node implementation would be a good start. A lua implementation could be shipped with Neovim later.

@tjdevries
Copy link
Contributor Author

Here's where I'll be working on this: https://github.com/tjdevries/nvim-langserver-shim

I will try and make it so we can swap out the remote plugin later (so get a lua implementation when a SDK for the language protocol is available).

@justinmk justinmk added enhancement feature request plugin plugins and Vim "pack" labels Oct 23, 2016
@justinmk justinmk added this to the todo milestone Oct 23, 2016
@euclio
Copy link
Contributor

euclio commented Oct 24, 2016

cc #4982

@tbelaire
Copy link
Contributor

Just to note, I had started on a python client with the intent of then writing vim and neovim, and making sure I can support the Rust LSP.

@purpleP
Copy link

purpleP commented Oct 30, 2016

Not sure that this is the right piece for it, but I have this idea for a while.

If there would be a thing that would take a language specification (BNF etc) and make a parser for that language (should be totally possible and there is YACC).

The parser can generate AST and it should be possible to create a DSL for linting rules, so that not only linter designers could write them but users too. Which would solve a problem where pylint (python linter program) would complain in wrong places and won't where it should have been.

This tool should have integration with editors similar to what Microsoft proposes.

This would give smarter completions that take types (possibly inferred for dynamically typed languages) into account.

Next thing is refactorings. Because refactoring is just a function from one AST to another it should be possible to create fairly simple DSL or service for that also. So language specific refactorings could be added easily.

This thing could also remove the need of ctags as it could store all information about various program components (like classes, variable names etc) in some database like sqlite, mongo etc) and where ctags gives you ability only to jump to tag that is for the word under cursor this thing could integrate with Unite plugin and show things like all classes or all variables or all strings etc (more complex queries).

@tjdevries
Copy link
Contributor Author

If I'm understanding correctly, that's pretty much a language server as defined by microsoft's protocol.

@justinmk
Copy link
Member

justinmk commented Oct 30, 2016

If there would be a thing that would take a language specification (BNF etc) and make a parser for that language (should be totally possible and there is YACC).

Check out the scintillua project for a library of PEG grammars for various languages. I'd really like to see this used for syntax highlighting in Nvim.

Because refactoring is just a function from one AST to another it should be possible to create fairly simple DSL or service for that also.

Refactoring is not AST => AST. Useful refactoring depends heavily on semantic analysis (type system) or more sophisticated inspection.

This thing could also remove the need of ctags as it could store all information about various program components

Microsoft Language Server Protocol abstracts those things into a common interface (this could be the DSL you mentioned) that can be used by any front end. AFAIK it is not a one-size-fits-all solution for storing, indexing, querying.

@purpleP
Copy link

purpleP commented Oct 31, 2016

@justinmk As I've said type checker will be also implemented in my proposed solution. And ANY code change is AST -> AST and so is refactoring. As to scintilla it only have lexer, right? Whereas I'm talking about parser.

@purpleP
Copy link

purpleP commented Oct 31, 2016

@tjdevries I've read briefly about Language Server. It differs from my idea in two ways. First I'm talking about implementation and protocol, whereas MLS is only a protocol. Second, in my solution protocol differs a bit. For example MLS doesn't define any means of querying the code base. Only jump to definitions. But I could be wrong about it.

One of the reasons I'm talking about this is that my proposed solution could be compatible at least partially with MLS, so if neovim would support that it would be good.

@prabirshrestha
Copy link

I would also be very interested in how this goes.

Given that my work machine is windows and neovim hasn't been working well there 😞 I managed to write LSP client in pure vimscript that works asynchronously in both vim8 and neovim.

Currently it just the client part.

https://github.com/prabirshrestha/vim-lsp

@tjdevries
Copy link
Contributor Author

Oh this is nice. I will take a look at this later today. Maybe we can
combine our work somewhere!

On Sun, Nov 6, 2016, 4:22 AM Prabir Shrestha notifications@github.com
wrote:

I would also be very interested in how this goes.

Given that my work machine is windows and neovim hasn't been working well
there 😞 I managed to write LSP client in pure vimscript that works
asynchronously in both vim8 and neovim.

Currently it just the client part.

https://github.com/prabirshrestha/vim-lsp


You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
#5522 (comment), or mute
the thread
https://github.com/notifications/unsubscribe-auth/AEQo0-Zwd_lQ8-KnCa6hZrCVfQZpSxWbks5q7Zw-gaJpZM4Kd6cE
.

@prabirshrestha
Copy link

I'm all for working together.

@tjdevries
Copy link
Contributor Author

I'll try and post a screen cast of some features that I've gotten working, but I think I've got:

all set to go (at least in a very basic form). So it's working quite well :D

I'm excited about the results.

@tjdevries
Copy link
Contributor Author

Big shoutout to @prabirshrestha for his work on vim-lsp which I modified a bit and included in the shim.

@mhartington
Copy link
Contributor

Very excited to see your progress @tjdevries. I've recreated something similar for typescript but using the python api

https://github.com/mhartington/deoplete-typescript/blob/master/rplugin/python3/nvim-typescript/__init__.py

@prabirshrestha
Copy link

prabirshrestha commented Nov 17, 2016

Glad to see this coming out very well. @tjdevries awesome job.

@mhartington unfortunately typescript (tsserver) does not implement the language server protocol :( microsoft/TypeScript#11274 There does seem to be an effort by sourcegraph team https://github.com/sourcegraph/javascript-typescript-langserver

It will be interesting to see these LSP implementation working inside vim. https://github.com/Microsoft/language-server-protocol/wiki/Protocol-Implementations

@tjdevries
Copy link
Contributor Author

I have confirmed it working on at least the sourcegraph go langserver and their python langserver. So that's pretty exciting.

Documentation will come out soon with some more ease of use type things :) I'll keep you all posted when that's ready.

@dumblob
Copy link

dumblob commented Dec 5, 2016

How did you solve the issue with concurrent edition of the same buffer (e.g. split buffer - possibly among different clients)? The Microsoft Language Server protocol still does not support it (microsoft/language-server-protocol#23 (comment) ).

@hauleth
Copy link

hauleth commented Dec 16, 2016

@dumblob but where is the issue? Vim has things enabled mostly per buffer, not per window, so there should be no problem with anything when using LS.

@dumblob
Copy link

dumblob commented Dec 16, 2016

@hauleth I'm sorry, but I don't understand what you mean. What are "things enabled per buffer"? How does it relate to e.g. split buffer edition among different clients?

@hauleth
Copy link

hauleth commented Dec 16, 2016

If you meant different instances of nvim then it would be the same problem among all editors, so nothing nvim specific and IMHO not an issue as when you edit files in different places simultaneously, then there always be problems. On the other hand, if you were talking about different vim windows then this is not an issue as LS would be operating on buffers not windows and windows shares the same buffer.

Am I missing something?

@prabirshrestha
Copy link

Something like file change notification would be useful to have in vim and neovim to create better integration for language server. Started a discussion in vim_dev at https://groups.google.com/forum/#!topic/vim_dev/oubHkRbdQW0. Some more discussion about this at #1380 including a WIP PR at #1791

@prabirshrestha
Copy link

In case anyone is curious to see demos :)

Async goto defintion in typescript using vim-lsp. More info at Quramy/tsuquyomi#57 (comment) This works in both vim and neovim.

lsp-ts-gotodef

async completion in vim (Fork of completor.vim with python removed implemented in pure vim script. Currently doesn't work yet in neovim as I'm waiting for neovim to support lambdas. More info at tjdevries/nvim-langserver-shim#11) Wished async completion was just part of core like completfunc and omnifunc

async_completion

Currently simulating async completion with timers.

function! s:emoji_completor(args, done)
  call timer_start(1000, {timer->a:done([{'word': ':smile:'}, { 'word': ':+1:'}])})
  " for sync directly call a:done()
  " call a:done([{'word': 'smile:'}, { 'word': '+1:'}])
endfunction

call completor#providers#register({
      \ 'name': 'emoji',
      \ 'filetypes': ['javascript'],
      \ 'completor': function('s:emoji_completor'),
      \ 'trigger': completor#providers#trigger_from_chars([':'])
      \ })

2017 might finally be the year of async vim and vim as an IDE :)

@Shougo
Copy link
Contributor

Shougo commented Jan 1, 2017

@prabirshrestha Why don't you use deoplete?

@Shougo
Copy link
Contributor

Shougo commented Jun 7, 2017

The pull request is here.

#6856

@prabirshrestha
Copy link

prabirshrestha commented Jul 19, 2017

Started reworking on my vim-lsp plugin again in dev branch. (still lot of refactoring to do and finalizing the public apis). prabirshrestha/vim-lsp#11

Currently these are supported.

  • :LspGetWorkspaceSymbols
  • :LspGetDocumentSymbols
  • You can send custom request and notifications to the server. (Registering server notifications not supported yet)
call lsp#send_request('server_name', {
    \ 'method': 'initialize',
    \ 'params:' {....},
    \ 'on_notification': {server_name, response->lsp#log(server_name, response)},
    \ })

call lsp#send_notification('server_name', {
    \ 'method': 'initialize',
    \ 'params:' {....},
    \ })

Calling these methods will automatically flush the buffers (i.e. wait for server start, initialize, didOpen and didChange. I had to actually go far as writing an async helper method in vim script to coordinate this https://github.com/prabirshrestha/vim-lsp/blob/31743d44463cd62358503f83d4a87fd54b818cdd/autoload/lsp/utils/step.vim)

function! s:ensure_flush(buf, server_name, cb) abort
    call lsp#utils#step#start([
        \ {s->s:ensure_start(a:buf, a:server_name, s.callback)},
        \ {s->s:is_step_error(s) ? s:throw_step_error(s) : s:ensure_init(a:buf, a:server_name, s.callback)},
        \ {s->s:is_step_error(s) ? s:throw_step_error(s) : s:ensure_open(a:buf, a:server_name, s.callback)},
        \ {s->s:is_step_error(s) ? s:throw_step_error(s) : s:ensure_changed(a:buf, a:server_name, s.callback)},
        \ {s->a:cb(s.result[0])}
        \ ])
endfunction

Here is a sample .vimrc on how to use it.

Plug 'prabirshrestha/vim-lsp', { 'branch': 'dev' }
Plug 'prabirshrestha/asyncomplete.vim'    " optional only required for autocompletion
Plug 'prabirshrestha/asyncomplete-lsp.vim' " when server is initialized and it supports completion, asyncomplete source is automatically registered. no need to call asyncomplete#register_source in .vimrc

au User lsp_setup call lsp#register_server({
     \ 'name': 'rust',
     \ 'cmd': {server_info->['rustup', 'run', 'nightly', 'rls']},
     \ 'whitelist': ['rust'],
     \ })

au User lsp_setup call lsp#register_server({
    \ 'name': 'ts',
    \ 'cmd': {server_info->has('win64') ? ['cmd', '/c', 'javascript-typescript-stdio']  : ['sh', '-c', 'javascript-typescript-stdio']},
    \ 'whitelist': ['typescript'],
    \ })

Are there any plans for supporting remote lua plugins in neovim? I would like to support both vimscript and remote lua plugin specially since some of these parsing are very expensive. Another option I have been thinking is to have rpc support in async.vim so that it works in both vim8 and neovim.

@justinmk
Copy link
Member

are there any plans for supporting remote lua plugins in neovim?

Yes.

@justinmk justinmk added the lsp label Aug 5, 2017
@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Aug 31, 2017

The most difficult problem I encounter in vim Langauge client is completion.

LSP's completion item is very rich and expressive, way beyond Vim's builtin completion mechanism.

Detail: https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#textDocument_completion

For example, a server can return a completion item as snippet. In VSCode selecting this item wil trigger snippet expansion.

Item can also have TextEdit field, selecting such item will apply text edition. For example, changing characters before completion position.

Some servers, like Java LS, will even uses AdditionalTextEdit for things like import library.

I wonder how far we can support LSP using current completion in Vim.

@roxma
Copy link
Contributor

roxma commented Aug 31, 2017

For example, a server can return a completion item as snippet. In VSCode selecting this item wil trigger snippet expansion.

I believe the snippet support is possible with existing plugins: deoplete+neosnippet+LanguageClient-neovim
or nvim-completion-manager+neosnippet/ultisnips/snipmate+LanguageClient-neovim

But I haven't seen a language server with this capabilities yet (I've tested php-language-server, go language server, rls, python). Anyone point me a direction so that I can test it on my laptop?

@HerringtonDarkholme
Copy link
Contributor

HerringtonDarkholme commented Aug 31, 2017

Hi @roxma, thanks for reply! You can try https://github.com/vuejs/vetur/tree/master/server.

Example test code

<template>
  <div cl|></div>
</template>

The | indicates cursor position. VLS will return a snippet which expands to

<template>
  <div class="|"></div>
</template>

Note the position of cursor. It's inside of quotation.

Edit: update code demo

@GordianDziwis
Copy link

Hi, I am experimenting with LanguageClient-neovim and java and I stumbled on an issue. The java lsp responses with its own schema jdt://... for following a dependency definitions: autozimu/LanguageClient-neovim#392.
Is there a handler interface in neovim which could be extended to handle this issue?

@vamolessa
Copy link

do any of these LSP plugins work with csharp? couldn't figure it out on how to make it work

@norcalli
Copy link

Guess I can close this now :P

@justinmk justinmk modified the milestones: 0.6, 0.5 Nov 26, 2019
@neovim neovim locked as resolved and limited conversation to collaborators Nov 26, 2019
@clason clason added needs:discussion issue needs attention from an expert, or PR proposes significant changes to architecture or API and removed discuss labels Jul 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement feature request lsp needs:design needs a clear design proposal needs:discussion issue needs attention from an expert, or PR proposes significant changes to architecture or API plugin plugins and Vim "pack"
Projects
None yet
Development

No branches or pull requests