-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Feature request: add general support for the Language Server Protocol #517
Comments
Yep, I had planned on doing that for TypeScript, perhaps. Supporting this probably won't be easy, but it'll be worth doing. My short term plan for TypeScript is to add a linter which grabs results form tsuquyomi, when it's installed, which implements parts of the LSP for TypeScript. |
https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md I recommend reading this, for anyone interested in implementing an LSP client. It took me a while to track that page down. That's the best specification I can find. |
Just FYI, TypeScript (well, Broadly, I think the process will look like:
I'm certainly not an expert on the protocol, but I think that's all that is necessary since a lot of the protocol is for refactoring, IDE hints, etc. Easier said than done, of course, but it may not be too horrible |
I have created the branch Now I think it would be a good idea to try out a real LSP server for some other language. |
I fixed the way the handling of diagnostic responses figured out which errors are for which buffers for TSServer and merged that into |
I'm moving the milestone for actual language server support, as none of the servers listed in the table support diagnostics yet, which is what we really care about. The table is here: http://langserver.org/ |
Rust definitely supports diagnostics. Seems the table is outdated.
…On Wed, Jun 14, 2017, 5:07 AM w0rp ***@***.***> wrote:
I'm moving the milestone for actual language server support, as none of
the servers listed in the table support diagnostics yet, which is what we
really care about. The table is here: http://langserver.org/
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#517 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABTxFvJpV0Oguics-GpRprcQSHbJOhEtks5sD6KzgaJpZM4NL4jT>
.
|
Aha, thanks for the information. In that case, we can integrate with the Rust LSP server for 1.4. |
I'm removing the release milestone. If someone can suggest a language server which works well and which doesn't require some complicated installation process, I can work on this. |
@w0rp did you have trouble installing the RLS? |
Yeah, I don't know how Rust stuff works. |
If I can write |
Not a one-liner, but curl https://sh.rustup.rs -sSf | sh
rustup update nightly
rustup component add rls --toolchain nightly
rustup component add rust-analysis --toolchain nightly
rustup component add rust-src --toolchain nightly and $ rls +nightly should get you there. You also will need to set up a cargo project to actually use the server. You could also try the Typescript or Go language servers from https://github.com/sourcegraph/, but I haven't used them personally. |
@w0rp I'm experimenting with the PHP language server (I honestly have no idea how well it works) which I'd be happy to contribute if I can get the thing going. Shouldn't have a very complex installation process (it's just a However, after playing around a bit (read: starting with tsserver.vim and changing some names and paths) I get The relevant part of my (failing) linter definition is as follows: call ale#linter#Define('php', {
\ 'name': 'langserver',
\ 'lsp': 'lsp',
\ 'executable_callback': 'ale_linters#php#langserver#GetExecutable',
\ 'callback': 'ale_linters#php#langserver#Handle',
\}) |
Support for language servers hasn't been fully implemented yet. The only thing that has is tsserver, which works differently. I realised more recently that both connections to network sockets and reading and writing to and from stdio and stdout will need to be supported, as the protocol doesn't specify how to actually connect to the servers, so that part is basically a free-for-all. |
Sending |
I may or may not have fixed that issue with getting the original diagnostics back again. I was sending the |
Played around with the Rust LS a bit today as well (as much as I can for how infrequently I use the language). Managed to break the thing to where it was spewing a bunch of stuff to stderr, which I think may be closed to moving files around underneath it (I don't think moving That aside, it worked well, quickly, and with no configuration once I actually had RLS installed (ignoring telling Ale to use it). Far more useful than the PHP one. From a practical standpoint, I wish the I think sending |
|
I think the |
Sounds good. I don't know the exact semantics of file vs buffer especially with multiple splits or tabs, but as long as it only fires |
I can explain that. Splitting the window shows the same buffer in two windows, and tabs contain windows. ALE cleans up a buffer before it is unloaded with |
* upstream/master: Cover the SaveEvent function with a test dense-analysis#734 - Use the buffer number from the events for entering buffers and saving buffers for checking buffers dense-analysis#734 - Do not clear file linter results when no buffers are run Add stylelint fixer Cover special LSP initialize response handling with Vader tests dense-analysis#517 - Get the Rust language server working in a basic way When servers never send an initialize response, but instead just publish diagnostics straight away, handle that as an initialize response Add some error message handling for LSP, for test purposes Fix some bugs so the PHP language server will show errors at least once
The PHP language server seems to work pretty well now. It looks like the problem was sending the |
I just pushed a commit which renames the Rust LSP linter to |
* upstream/master: Cover the Rust LSP with tests, allow LSP linters to be named anything, and rename the Rust LSP linter to `rls` Use g: for the PHP Vader tests Cover the PHP language server functions with Vader tests dense-analysis#517 Enable the PHP language server Fix indentation and a typo in the gometalinter documentation Rubocop: Show cop name added gometalinter docs - Fix for dense-analysis#816
I'm also interested in getting the language server protocol working with ale. Currently Plug 'prabirshrestha/asyncomplete.vim'
Plug 'prabirshrestha/async.vim'
Plug 'prabirshrestha/vim-lsp', { 'branch': 'dev' }
Plug 'prabirshrestha/asyncomplete-lsp.vim'
if executable('pyls')
" pip install python-language-server
au User lsp_setup call lsp#register_server({
\ 'name': 'pyls',
\ 'cmd': {server_info->['pyls']},
\ 'whitelist': ['python'],
\ })
endif If ale has public apis it can listen to all the LSP notifications from the language servers and send it to ale using function! s:on_notification(server_name, data) abort
echom a:server_name . json_encode(a:data['response'])
" use ale apis and add diagnostics message if a:data is not error and is of type diagnostics
endfunction
au User lsp_setup call lsp#register_notifications('ale', function('s:on_notification')) |
I don't think depending on other plugins will work. LSP is too new to write stable client for it, and you can't specify dependences for Vim projects like you can with Node or Python projects. The torrent of pull requests would slow down development, and minor changes to the plugin would result in the integration breaking often. |
You could potentially use it as a library, included via git submodules. I believe this is how https://github.com/vim-jp/vital.vim is used |
The LSP implementation in ALE is much further along already, and PHP and Rust support are ready to release. |
git submodules don't really work as a solution for adding plugin dependencies. You can't have two different versions of the same plugin with the same autoload function names, so you'd have to never have two different plugins with the same dependencies. You can't wrap functions in a namespace either, as the full autoload function name is written into the name of every function. If you want to depend on other plugins, then they have to be installed alongside your plugin, and all other plugins have to share the same version of that other plugin. That puts controlling the version you depend on beyond your control. Vim's plugin ecosystem is very much inferior to something like NPM. |
I'll close this now, as basic LSP integration is done. We can worry about TCP connections later, as there's currently no way to make TCP connections natively in stable versions of NeoVim that I know of, but there is in Vim 8. I don't think closing and re-opening documents is essential at the moment. I'll open an issue for handling that. It probably won't be incredibly difficult to implement. |
* upstream/master: Fix dense-analysis#468 - Add a cool down period for when things go wrong Document the extra optional argument for ale#Queue Simplify some comparisons Ban use of ==# or ==? in the codebase, and prefer is# or is? instead Fix dense-analysis#833 - Do not open windows on save when the option is off Fix dense-analysis#271 - Add the ability to open the quickfix or loclist windows only after saving a file Fix the resetting of selections and annotate it added missing visual reselection after quick/location list update (dense-analysis#788) dense-analysis#517 - Document arguments for defining LSP linters Document the PHP langserver integration Document the rls linter The default for ale_rust_cargo_use_check was wrong in the documentation Fix dense-analysis#823 - Write Windows files with CRLF Stop writing a test file in real world usage in some cases
This is looking great. I'm still wondering though, as jez asked in an earlier comment, what the ultimate goal is? Is ALE eventually going to support navigating to symbol definitions and listing references? If not, (and this was also mentioned by prabirshrestha above), there will always be a need for some other LSP plugin to be running its own version of the server alongside ALE, won't there? For example, I am currently using the ALE tsserver linter together with tsuquyomi for typescript, which works great but does mean that there are 2 instances of the server running. I also hope to use the OmniSharp LSP server for C# when it is ready, and that will result in the same situation. So is it not an option to open an ALE API, allowing other plugins to pass in their diagnostics? That would allow the external plugin (whether it was a generic LSP plugin or a specific plugin like tsuquyomi) to maintain their servers, and just let ALE display the results - the external plugin would then depend on ALE, not the other way around. I think (?) this is what @prabirshrestha was getting at. |
Vim plugins for new protocols like LSP cannot work together in such a manner, because you can't configure requirements for dependencies like you can with Python's PIP. I think any attempt to get one plugin to use another plugin's LSP client will result in failure. Until LSP has been seriously adopted in many languages, the specification will continue to evolve, and the clients will evolve with the specification. If the specification eventually becomes stable enough that it will be possible to develop clients without breaking API changes, then it will be possible for two plugins to reliably work together in this manner. Until it becomes possible to have one plugin depend on another, each plugin will have to connect to an LSP separately. This can be undesirable, so ALE is forced to implement other features like completion. |
The best way to get some perspective on this is to try and implement something like this, and then discuss it after having tried to implement it. |
I suppose I was thinking that ALE could define the diagnostic format it expects and let any external plugins conform to that - the external plugin is then responsible for any formatting that might be required from the LSP server to make it fit to ALE's needs. This way ALE still doesn't need to know or worry about the plugin, so no dependency issues from this end. I had imagined this being something like a matter of calling However, as you quite fairly note, I haven't tried implementing something like this and I don't understand all of the implications. |
While the LSP protocol itself has been stable and is versioned to avoid breaking changes, many of the server implementations are not stable. But until and unless we don't push for it I don't think it will ever be. People will continue to use standalone linters since it works the best for them. I was sort of thinking an api like this would be good. I have not read the ale code nor written linters so not sure if this would suffice. ale#messages#clear({ 'buf': bufnr('%') })
ale#messages#add([{
\ 'buf': bufnr('%'),
\ 'severity': 'error',
\ 'message': 'message',
\ 'range': {
\ 'start': { 'line': 1, 'col': 1 },
\ 'end': { 'line': 1, 'col': 10 },
\ },
\ }]) Here is an example how I implemented autocomplete of lsp. https://github.com/prabirshrestha/asyncomplete-lsp.vim/blob/cc168c5a0873dc902d9e1f55032e776a2fcd8d69/plugin/asyncomplete.vim. function! s:on_notification(server_name, data) abort
if s:is_diagnostics_notification(a:data)
call ale#messages#clear()
call ale#messages#add(s:convert_lsp_diagnostics_to_ale(a:data))
endif
endfunction
lsp#register_notifications('*', function('s:on_notification')) There are also other things like |
The idea of having an LSP plugin send errors to ALE is a better one, but there a a number of problems which need to be solved, and some of which might not be possible to solve. The Socratic method applies here. There are many questions to ask. If a separate plugin decides to send a list of problems to ALE at any time, how will ALE then control disabling linting for a file? Should ALE start ignoring messages being sent to it from other plugins? How will ALE implement re-enabling linting? Should there be a hook for telling other plugins that they should resend their list of items back to ALE again? Should other plugins be required to implement a hook for when ALE requests a buffer to be checked? What if a user doesn't want ALE to check a file when it is opened, but another plugin thinks it does? What if the options for ALE change? Should they be required to call a function for checking if linting is enabled for a file? How would you go about disabling particular linters? Should LSP linters be implemented in other plugins in the There are many questions to ask. My recommendation is to think about this, identify legitimate problems with how ALE works now, propose a workable solution which makes sense, and open a pull request for that solution. We could talk about this for weeks, but that would largely be a waste of time. Write some code, and get myself and others to look at it. |
ALE has since implemented full support for Language Server Protocol itself, and there is no need for additional plugins. Servers can be started automatically, in some cases with zero configuration, and you don't pay for the features you don't use. |
Many languages are starting to add support for the Language Server Protocol, which supports (among other things) getting diagnostic errors on files from the language server. I believe ale could leverage this to get pretty reusable support across many languages, and add support for new languages in the future with relatively little effort.
The text was updated successfully, but these errors were encountered: