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.
Utf-8 support has been around for a while as an unstable feature but
utf-32 is fairly new. A bunch of LS (like rust-analyzer) added this in
a pinch, but it's pretty broken right now. The performance overhead is
not very large (still a lot better than utf-16). We can switch back
once the ecosystem has matured.
* misc: missing inline, outdated link
* doc: Add new theme keys and config option to book
* fix: don't panic in Tree::try_get(view_id)
Necessary for later, where we could be receiving an LSP response
for a closed window, in which case we don't want to crash while
checking for its existence
* fix: reset idle timer on all mouse events
* refacto: Introduce Overlay::new and InlineAnnotation::new
* refacto: extract make_job_callback from Context::callback
* feat: add LSP display_inlay_hint option to config
* feat: communicate inlay hints support capabilities of helix to LSP server
* feat: Add function to request range of inlay hint from LSP
* feat: Save inlay hints in document, per view
* feat: Update inlay hints on document changes
* feat: Compute inlay hints on idle timeout
* nit: Add todo's about inlay hints for later
* fix: compute text annotations for current view in view.rs, not document.rs
* doc: Improve Document::text_annotations() description
* nit: getters don't use 'get_' in front
* fix: Drop inlay hints annotations on config refresh if necessary
* fix: padding theming for LSP inlay hints
* fix: tracking of outdated inlay hints should not be dependant on document revision (because of undos and such)
* fix: follow LSP spec and don't highlight padding as virtual text
* config: add some LSP inlay hint configs
* LSP: Support textDocument/prepareRename
'textDocument/prepareRename' can be used by the client to ask the
server the range of the symbol under the cursor which would be changed
by a subsequent call to 'textDocument/rename' with that position.
We can use this information to fill the prompt with an accurate prefill
which can improve the UX for renaming symbols when the symbol doesn't
align with the "word" textobject. (We currently use the "word"
textobject as a default value for the prompt.)
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
* clippy fixes
* rustfmt
* Update helix-term/src/commands/lsp.rs
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
* Update helix-term/src/commands/lsp.rs
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
* fix clippy from suggestions
* Update helix-term/src/commands/lsp.rs
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
---------
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
* feat(ui): deprecated completions
Mark deprecated completions using strike-through
(CROSSED_OUT modifier). The deprection information
is taken either from the `deprecated` field of the
completion item or from the completion tags.
The field seems to be the older way of passing
the deprecated information and it was already
marked as deprecated for Symbol. In completion
item the field is still valid but it seems that
the LSP is moving in the general direction of using
tags for this kind of information and as such
relying on tags as well seems reasonable and
future-proof.
So far LSP always required that `PositionEncoding.characters` is an
UTF-16 offset. Now that LSP 3.17 is available in `lsp-types` request
the server to send char offsets (UTF-32) or byte offsets (UTF-8)
instead. For compatability with old servers, UTF-16 remains as the
fallback as required by the standard.
* properly handle LSP position encoding
* add debug assertion to Transaction::change
* Apply suggestions from code review
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
---------
Co-authored-by: Michael Davis <mcarsondavis@gmail.com>
Language Servers may signal that they do not support a method in
the initialization result (server capabilities). We can check these
when making LSP requests and hint in the status line when a method
is not supported by the server. This can also prevent crashes in
servers which assume that clients do not send requests for methods
which are disabled in the server capabilities.
There is an existing pattern the LSP client module where a method
returns `Option<impl Future<Output = Result<_>>>` with `None` signaling
no support in the server. This change extends this pattern to the rest
of the client functions. And we log an error to the statusline for
manually triggered LSP calls which return `None`.
d7d0d5ffb7 resolves completion items on
the idle-timeout event. The `Completion::resolve_completion_item`
function blocks on the LSP request though, which blocks the compositor
and in turn blocks the event loop. So until the language server returns
the resolved completion item, Helix is unable to respond to keypresses
or other LSP messages.
This is typically ok since the resolution request is fast but for some
language servers this can be problematic, and ideally we shouldn't be
blocking like this anyways.
When receiving a `completionItem/resolve` request, the Volar server
sends a `workspace/configuration` request to Helix and blocks itself
on the response, leading to a deadlock. Eventually the resolve request
times out within Helix but Helix is locked up and unresponsive in that
window.
This change resolves the completion item without blocking the
compositor.
* Split helix_core::find_root and helix_loader::find_local_config_dirs
The documentation of find_root described the following priority for
detecting a project root:
- Top-most folder containing a root marker in current git repository
- Git repository root if no marker detected
- Top-most folder containing a root marker if not git repository detected
- Current working directory as fallback
The commit contained in https://github.com/helix-editor/helix/pull/1249
extracted and changed the implementation of find_root in find_root_impl,
actually reversing its result order (since that is the order that made
sense for the local configuration merge, from innermost to outermost
ancestors).
Since the two uses of find_root_impl have different requirements (and
it's not a matter of reversing the order of results since, e.g., the top
repository dir should be used by find_root only if there's not marker in
other dirs), this PR splits the two implementations in two different
specialized functions.
In doing so, find_root_impl is removed and the implementation is moved
back in find_root, moving it closer to the documented behaviour thus
making it easier to verify it's actually correct
* helix-core: remove Option from find_root return type
It always returns some result, so Option is not needed
* Add lsp signature help
* Do not move signature help popup on multiple triggers
* Highlight current parameter in signature help
* Auto close signature help
* Position signature help above to not block completion
* Update signature help on backspace/insert mode delete
* Add lsp.auto-signature-help config option
* Add serde default annotation for LspConfig
* Show LSP inactive message only if signature help is invoked manually
* Do not assume valid signature help response from LSP
Malformed LSP responses are common, and these should not crash the
editor.
* Check signature help capability before sending request
* Reuse Open enum for PositionBias in popup
* Close signature popup and exit insert mode on escape
* Add config to control signature help docs display
* Use new Margin api in signature help
* Invoke signature help on changing to insert mode
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
* allows passing extra formatting options to LSPs
- adds optional field 'format' to [[language]] sections in 'languages.toml'
- passes specified options the LSPs via FormattingOptions
* cleaner conversion of formatting properties
* move formatting options inside lsp::Client
* cleans up formatting properties merge
* Send active diagnostics to LSP when requesting code actions.
This allows for e.g. clangd to properly send the quickfix code actions
corresponding to those diagnostics as options.
The LSP spec v3.16.0 introduced an opaque `data` member that would allow
the server to persist arbitrary data between the diagnostic and the code
actions request, but this is not supported yet by this commit.
* Reuse existing range_to_lsp_range functionality