From 71551d395b4e47804df2d8ecea99e34dbbf16157 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Mon, 23 May 2022 18:10:48 +0200 Subject: 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. --- helix-view/src/gutter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'helix-view/src/gutter.rs') diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 3ecae919..78f879c9 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -55,7 +55,7 @@ pub fn diagnostic<'doc>( let error = theme.get("error"); let info = theme.get("info"); let hint = theme.get("hint"); - let diagnostics = doc.diagnostics(); + let diagnostics = doc.shown_diagnostics().collect::>(); Box::new( move |line: usize, _selected: bool, first_visual_line: bool, out: &mut String| { -- cgit v1.2.3-70-g09d2 From 8ee599942a0e5ff6fa1a908ca076785e0d2bd0c7 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Mon, 20 Mar 2023 00:51:41 +0100 Subject: Optimize gutter diagnostics and simplify shown_diagnostics --- helix-view/src/document.rs | 15 +++------------ helix-view/src/gutter.rs | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 15 deletions(-) (limited to 'helix-view/src/gutter.rs') diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 27f5d279..bc81567e 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -179,7 +179,7 @@ pub struct Document { version: i32, // should be usize? pub(crate) modified_since_accessed: bool, - diagnostics: Vec, + pub(crate) diagnostics: Vec, pub(crate) language_servers: HashMap>, diff_handle: Option, @@ -1605,17 +1605,8 @@ impl Document { pub fn shown_diagnostics(&self) -> impl Iterator + DoubleEndedIterator { self.diagnostics.iter().filter(|d| { - self.language_servers() - .find(|ls| ls.id() == d.language_server_id) - .and_then(|ls| { - let config = self.language_config()?; - let features = config - .language_servers - .iter() - .find(|features| features.name == ls.name())?; - Some(features.has_feature(LanguageServerFeature::Diagnostics)) - }) - == Some(true) + self.language_servers_with_feature(LanguageServerFeature::Diagnostics) + .any(|ls| ls.id() == d.language_server_id) }) } diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 78f879c9..8c8abcc3 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -1,5 +1,7 @@ use std::fmt::Write; +use helix_core::{syntax::LanguageServerFeature, Diagnostic}; + use crate::{ editor::GutterType, graphics::{Style, UnderlineStyle}, @@ -55,7 +57,7 @@ pub fn diagnostic<'doc>( let error = theme.get("error"); let info = theme.get("info"); let hint = theme.get("hint"); - let diagnostics = doc.shown_diagnostics().collect::>(); + let diagnostics = &doc.diagnostics; Box::new( move |line: usize, _selected: bool, first_visual_line: bool, out: &mut String| { @@ -64,12 +66,20 @@ pub fn diagnostic<'doc>( } use helix_core::diagnostic::Severity; if let Ok(index) = diagnostics.binary_search_by_key(&line, |d| d.line) { - let after = diagnostics[index..].iter().take_while(|d| d.line == line); + let on_line_and_is_visible = |d: &&Diagnostic| { + d.line == line + && doc + .language_servers_with_feature(LanguageServerFeature::Diagnostics) + .any(|ls| ls.id() == d.language_server_id) + }; + let after = diagnostics[index..] + .iter() + .take_while(on_line_and_is_visible); let before = diagnostics[..index] .iter() .rev() - .take_while(|d| d.line == line); + .take_while(on_line_and_is_visible); let diagnostics_on_line = after.chain(before); -- cgit v1.2.3-70-g09d2 From 2a21b939c432e4b5a186df780a1e97d20ff53120 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Tue, 28 Mar 2023 04:15:03 +0200 Subject: Fix crash with filtered diagnostics in gutter (e.g. when diagnostics aren't visible) --- helix-view/src/gutter.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'helix-view/src/gutter.rs') diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 8c8abcc3..475ec5a3 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -83,16 +83,15 @@ pub fn diagnostic<'doc>( let diagnostics_on_line = after.chain(before); - // This unwrap is safe because the iterator cannot be empty as it contains at least the item found by the binary search. - let diagnostic = diagnostics_on_line.max_by_key(|d| d.severity).unwrap(); - - write!(out, "●").unwrap(); - return Some(match diagnostic.severity { - Some(Severity::Error) => error, - Some(Severity::Warning) | None => warning, - Some(Severity::Info) => info, - Some(Severity::Hint) => hint, - }); + if let Some(diagnostic) = diagnostics_on_line.max_by_key(|d| d.severity) { + write!(out, "●").ok(); + return Some(match diagnostic.severity { + Some(Severity::Error) => error, + Some(Severity::Warning) | None => warning, + Some(Severity::Info) => info, + Some(Severity::Hint) => hint, + }); + } } None }, -- cgit v1.2.3-70-g09d2 From 656ee24966c17ed505acc2faded2da505e9c7052 Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Wed, 5 Apr 2023 20:03:41 +0200 Subject: Simplify gutter diagnostics rendering by using partition_point instead of binary search Co-authored-by: Pascal Kuthe --- helix-view/src/gutter.rs | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'helix-view/src/gutter.rs') diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index 475ec5a3..d11cbe4d 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -1,6 +1,6 @@ use std::fmt::Write; -use helix_core::{syntax::LanguageServerFeature, Diagnostic}; +use helix_core::syntax::LanguageServerFeature; use crate::{ editor::GutterType, @@ -65,35 +65,27 @@ pub fn diagnostic<'doc>( return None; } use helix_core::diagnostic::Severity; - if let Ok(index) = diagnostics.binary_search_by_key(&line, |d| d.line) { - let on_line_and_is_visible = |d: &&Diagnostic| { + let first_diag_idx_maybe_on_line = diagnostics.partition_point(|d| d.line < line); + if first_diag_idx_maybe_on_line == diagnostics.len() { + return None; + } + let diagnostics_on_line = diagnostics[first_diag_idx_maybe_on_line..] + .iter() + .take_while(|d| { d.line == line && doc .language_servers_with_feature(LanguageServerFeature::Diagnostics) .any(|ls| ls.id() == d.language_server_id) - }; - let after = diagnostics[index..] - .iter() - .take_while(on_line_and_is_visible); - - let before = diagnostics[..index] - .iter() - .rev() - .take_while(on_line_and_is_visible); - - let diagnostics_on_line = after.chain(before); - - if let Some(diagnostic) = diagnostics_on_line.max_by_key(|d| d.severity) { - write!(out, "●").ok(); - return Some(match diagnostic.severity { - Some(Severity::Error) => error, - Some(Severity::Warning) | None => warning, - Some(Severity::Info) => info, - Some(Severity::Hint) => hint, - }); + }); + diagnostics_on_line.max_by_key(|d| d.severity).map(|d| { + write!(out, "●").ok(); + match d.severity { + Some(Severity::Error) => error, + Some(Severity::Warning) | None => warning, + Some(Severity::Info) => info, + Some(Severity::Hint) => hint, } - } - None + }) }, ) } -- cgit v1.2.3-70-g09d2 From f45bbf165e225142b7f1d9f68d0ffcc9fabd265d Mon Sep 17 00:00:00 2001 From: Philipp Mildenberger Date: Thu, 6 Apr 2023 02:37:43 +0200 Subject: Apply all review suggestions (doc_id -> id, error message, unnecessary if) Co-authored-by: Pascal Kuthe --- helix-term/src/ui/completion.rs | 2 +- helix-view/src/editor.rs | 6 +++--- helix-view/src/gutter.rs | 3 --- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'helix-view/src/gutter.rs') diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs index 28a5157c..eaa63e93 100644 --- a/helix-term/src/ui/completion.rs +++ b/helix-term/src/ui/completion.rs @@ -220,7 +220,7 @@ impl Completion { { Some(ls) => ls, None => { - editor.set_error("language server disappeared between completion request and application"); + editor.set_error("completions are outdated"); // TODO close the completion menu somehow, // currently there is no trivial way to access the EditorView to close the completion menu return; diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 280002bd..1f27603c 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1353,10 +1353,10 @@ impl Editor { } doc.set_version_control_head(self.diff_providers.get_current_head_name(&path)); - let doc_id = self.new_document(doc); - let _ = self.launch_language_servers(doc_id); + let id = self.new_document(doc); + let _ = self.launch_language_servers(id); - doc_id + id }; self.switch(id, action); diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index d11cbe4d..a332a8a3 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -66,9 +66,6 @@ pub fn diagnostic<'doc>( } use helix_core::diagnostic::Severity; let first_diag_idx_maybe_on_line = diagnostics.partition_point(|d| d.line < line); - if first_diag_idx_maybe_on_line == diagnostics.len() { - return None; - } let diagnostics_on_line = diagnostics[first_diag_idx_maybe_on_line..] .iter() .take_while(|d| { -- cgit v1.2.3-70-g09d2