dense-analysis / ale

Check syntax in Vim/Neovim asynchronously and fix files, with Language Server Protocol (LSP) support
BSD 2-Clause "Simplified" License
13.56k stars 1.44k forks source link

Feature request: add general support for the Language Server Protocol #517

Closed Firehed closed 7 years ago

Firehed commented 7 years ago

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.

w0rp commented 7 years ago

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.

w0rp commented 7 years ago

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.

nickspoons commented 7 years ago

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 ale#linter#define(...) but passing in a callback method to the external plugin instead of an executable.

However, as you quite fairly note, I haven't tried implementing something like this and I don't understand all of the implications.

prabirshrestha commented 7 years ago

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. add takes in a list of messages and any one include the ale core could take advantage of it. It may also have to be extended to have custom user data so that we can perform code actions.

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. vim-lsp was designed to not include any autocomplete plugins and let users choose their own autocomplete plugins that works for them. It has necessary hooks, lsp_server_init and lsp_server_exited events which allows other plugins to register when a server is initialized or exited. It allows other plugins to send requests using lsp#send_request or receive server notifications using lsp#register_notifications. In the end it would look something like this.

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 textDocument/didChange that needs to be handled.

w0rp commented 7 years ago

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 ale_linters directory like other linters? Linters that are defined with Define are designed to be started by ALE, but diagnostic results in general LSP plugins could arrive at any time. ALE is actually the one asking for a list of problems. Would another plugin implement a callback which is used to return a List of items to ALE through another function call to ALE?

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.

w0rp commented 7 years ago

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.