Commit Graph

35 Commits (9259c526062f7e80e7d43c6d2e5ae97e9cf0487a)

Author SHA1 Message Date
Michael Davis e0bb032f0e
LSP: Forcefully shutdown uninitialized servers (#7449)
The LSP spec has this to say about initialize:

> Until the server has responded to the `initialize` request with an
> `InitializeResult`, the client must not send any additional requests
> or notifications to the server.

(https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#initialize)

The spec is not really explicit about how to handle this scenario.
Before a client sends the 'initialize' request we are allowed to send an
'exit' notification, but after 'initialize' we can't send any requests
(like shutdown) or notifications (like exit). So my intepretation is
that we should forcefully close the server in this state.

This matches the behavior of Neovim's built-in LSP client:
5ceb2238d3/runtime/lua/vim/lsp.lua (L1610-L1628)
1 year ago
Philipp Mildenberger 71551d395b Adds support for multiple language servers per language.
Language Servers are now configured in a separate table in `languages.toml`:

```toml
[langauge-server.mylang-lsp]
command = "mylang-lsp"
args = ["--stdio"]
config = { provideFormatter = true }

[language-server.efm-lsp-prettier]
command = "efm-langserver"

[language-server.efm-lsp-prettier.config]
documentFormatting = true
languages = { typescript = [ { formatCommand ="prettier --stdin-filepath ${INPUT}", formatStdin = true } ] }
```

The language server for a language is configured like this (`typescript-language-server` is configured by default):

```toml
[[language]]
name = "typescript"
language-servers = [ { name = "efm-lsp-prettier", only-features = [ "format" ] }, "typescript-language-server" ]
```

or equivalent:

```toml
[[language]]
name = "typescript"
language-servers = [ { name = "typescript-language-server", except-features = [ "format" ] }, "efm-lsp-prettier" ]
```

Each requested LSP feature is priorized in the order of the `language-servers` array.
For example the first `goto-definition` supported language server (in this case `typescript-language-server`) will be taken for the relevant LSP request (command `goto_definition`).

If no `except-features` or `only-features` is given all features for the language server are enabled, as long as the language server supports these. If it doesn't the next language server which supports the feature is tried.

The list of supported features are:

- `format`
- `goto-definition`
- `goto-declaration`
- `goto-type-definition`
- `goto-reference`
- `goto-implementation`
- `signature-help`
- `hover`
- `document-highlight`
- `completion`
- `code-action`
- `workspace-command`
- `document-symbols`
- `workspace-symbols`
- `diagnostics`
- `rename-symbol`
- `inlay-hints`

Another side-effect/difference that comes with this PR, is that only one language server instance is started if different languages use the same language server.
2 years ago
Michael Davis e6dad960cf
Drain pending requests on language server termination (#4852)
This prevents a freeze while shutting down when using `efm-langserver`.
`efm-langserver` exits immediately after seeing a shutdown request,
without responding to the request. We block awaiting the reply to the
shutdown request which will never come, so we time out.

This change responds to any pending requests with `Err` saying that the
stream has been closed.
2 years ago
Michael Davis 8be2d1dcbf
Handle language server termination (#4797)
This change handles a language server exiting. This was a UX sore-spot:
if a language server crashed, Helix did not recognize the exit and
continued to send requests to it. All requests would timeout since they
would not receive responses. This would also hold-up Helix closing
itself down since it would try to gracefully shutdown the server which
is implemented in the LSP spec as a request.

We could attempt to automatically restart the language server on crash.
I left this for future work since that change will need to be slightly
complicated: it will need to cover the case of a language server
repeatedly crashing.
2 years ago
Michael Davis 45ce1ebdb6
embed jsonrpc types from jsonrpc-core crate (#2801)
We should not depend on jsonrpc-core anymore:

* The project just announced it's no longer actively maintained[^1],
  preferring their new implementation in `jsonrpsee`.
* The types are too strict: we would benefit from removing some
  `#[serde(deny_unknown_fields)]` annotations to allow language
  servers that disrespect the spec[^2].
* We don't use much of the project. Just the types out of core.
  These are easy to embed directly into the `helix-lsp` crate.

[^1]: https://github.com/paritytech/jsonrpc/pull/674
[^2]: https://github.com/helix-editor/helix/issues/2786
2 years ago
Michael Davis 50dd11985c
prevent panic when handling an LSP response with no request (#2475)
A language server may push a response which doesn't belong to any
request. With this change, we discard the response rather than
crashing.

In the case of #2474, the language server sends an error message
with a null request ID which should not ever exist in the
`pending_requests` HashMap.

closes #2474
3 years ago
Blaž Hrastnik be81f40df8 lsp: This doesn't need to be a mutable reference 3 years ago
Blaž Hrastnik 46f3c69f06 lsp: Don't send notifications until initialize completes
Then send open events for all documents with the LSP attached.
3 years ago
Blaž Hrastnik 5a558e0d8e lsp: Delay requests & notifications until initialization is complete 3 years ago
Blaž Hrastnik 41f1e8e4fb fix: lsp: Terminate transport on EOF
If stdout/stderr is closed, read_line will return 0 indicating EOF.
3 years ago
Blaž Hrastnik 847d1fa496 fix: Work around crashes on LSPs that don't just emit JSON-RPC 3 years ago
Blaž Hrastnik 7eff905680 lsp: slightly refactor header parsing, add more logging 3 years ago
Timothy DeHerrera ed8c3e6574
don't panic on defunct lsp process (#583) 3 years ago
Blaž Hrastnik 385a6b5a1a lsp: Refactor duplex to avoid issues with select! + read_exact
read_exact isn't cancellation safe.

Fixes #504
3 years ago
wojciechkepka dd0af78079 Fix unwraps in lsp::transport 3 years ago
wojciechkepka 38cb934d8f Add unique id to each lsp client/server pair 3 years ago
Ivan Tham 7cc13fefe9 Derive debug without feature
Note that this also removed those `finish_non_exhaustive()`.
3 years ago
notoria 1a3a924634 Implement Debug for data structure as a feature 3 years ago
Egor Karavaev ea6667070f helix-lsp cleanup 3 years ago
Blaž Hrastnik fd4fd12fa3 clippy lint 4 years ago
Blaž Hrastnik 355ad3cb82 Tokio migration. 4 years ago
Blaž Hrastnik ceea5eacd8 clippy lint 4 years ago
Blaž Hrastnik 87a6d4e736 minor: Simplify some code. 4 years ago
Blaž Hrastnik 004a4f37a7 lsp: Handle responses being returned after request timed out. 4 years ago
Blaž Hrastnik 48ef6598db Increase the log level in LSP and log server errors. 4 years ago
Blaž Hrastnik 777a80917d Address clippy lints. 4 years ago
Blaž Hrastnik 3cbab20908 lsp: Fix pos_to_lsp_pos calculation. 4 years ago
Blaž Hrastnik cd16df19c1 lsp: generate_transaction_from_text_edits 4 years ago
Blaž Hrastnik 8695415fbf wip: Move to new rendering structure. 4 years ago
Blaž Hrastnik cc6bdf8f66 Text change generation, RPC call handling. 4 years ago
Blaž Hrastnik af1924404a Configure logging (-vv for debug level logs) 4 years ago
Blaž Hrastnik eff6fac9ec clippy lint 4 years ago
Blaž Hrastnik 81ccca0c6a Improve error typing. 4 years ago
Blaž Hrastnik f9bfba4d96 Reroute LSP notification events into the main app event loop. 4 years ago
Blaž Hrastnik 13cb442850 wip: Fetching diagnostics, parsing notifications. 4 years ago