diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index bce223fb88872d675d85da320edba85094373e93..ebac70b73b1ddd5cb20f8bda0e1bb400fe44a640 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -883,6 +883,7 @@ impl MultiBuffer { completion.old_range.end, ), new_text: completion.new_text, + label: completion.label, lsp_completion: completion.lsp_completion, }) .collect() @@ -939,6 +940,7 @@ impl MultiBuffer { old_range: completion.old_range.start.text_anchor ..completion.old_range.end.text_anchor, new_text: completion.new_text, + label: completion.label, lsp_completion: completion.lsp_completion, }, true, diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index f5ea67f5fed29ad5f6a89700cea4a17b5f511155..23b2a752c611a4bf28550e46ae1e9f018dfd8fcc 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -119,6 +119,7 @@ pub struct Diagnostic { pub struct Completion { pub old_range: Range, pub new_text: String, + pub label: Option, pub lsp_completion: lsp::CompletionItem, } @@ -203,6 +204,7 @@ pub trait File { &self, buffer_id: u64, position: Anchor, + language: Option>, cx: &mut MutableAppContext, ) -> Task>>>; @@ -286,6 +288,7 @@ impl File for FakeFile { &self, _: u64, _: Anchor, + _: Option>, _: &mut MutableAppContext, ) -> Task>>> { Task::ready(Ok(Default::default())) @@ -1800,10 +1803,11 @@ impl Buffer { } else { return Task::ready(Ok(Default::default())); }; + let language = self.language.clone(); if let Some(file) = file.as_local() { - let server = if let Some(lang) = self.language_server.as_ref() { - lang.server.clone() + let server = if let Some(language_server) = self.language_server.as_ref() { + language_server.server.clone() } else { return Task::ready(Ok(Default::default())); }; @@ -1850,6 +1854,7 @@ impl Buffer { Some(Completion { old_range: this.anchor_before(old_range.start)..this.anchor_after(old_range.end), new_text, + label: language.as_ref().and_then(|l| l.label_for_completion(&lsp_completion)), lsp_completion, }) } else { @@ -1859,7 +1864,12 @@ impl Buffer { }) }) } else { - file.completions(self.remote_id(), self.anchor_before(position), cx.as_mut()) + file.completions( + self.remote_id(), + self.anchor_before(position), + language, + cx.as_mut(), + ) } } @@ -2668,7 +2678,7 @@ impl Default for Diagnostic { impl Completion { pub fn label(&self) -> &str { - &self.lsp_completion.label + self.label.as_deref().unwrap_or(&self.lsp_completion.label) } pub fn filter_range(&self) -> Range { diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 22accb422c2970b723a0cf19f2bb116100ce9bf4..b694e82df135c1d9812d566bdeb7efb59795f605 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -43,8 +43,11 @@ pub trait ToLspPosition { fn to_lsp_position(self) -> lsp::Position; } -pub trait DiagnosticProcessor: 'static + Send + Sync { +pub trait LspPostProcessor: 'static + Send + Sync { fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams); + fn label_for_completion(&self, _completion: &lsp::CompletionItem) -> Option { + None + } } #[derive(Default, Deserialize)] @@ -77,7 +80,7 @@ pub struct BracketPair { pub struct Language { pub(crate) config: LanguageConfig, pub(crate) grammar: Option>, - pub(crate) diagnostic_processor: Option>, + pub(crate) lsp_post_processor: Option>, } pub struct Grammar { @@ -144,7 +147,7 @@ impl Language { highlight_map: Default::default(), }) }), - diagnostic_processor: None, + lsp_post_processor: None, } } @@ -188,8 +191,8 @@ impl Language { Ok(self) } - pub fn with_diagnostics_processor(mut self, processor: impl DiagnosticProcessor) -> Self { - self.diagnostic_processor = Some(Box::new(processor)); + pub fn with_lsp_post_processor(mut self, processor: impl LspPostProcessor) -> Self { + self.lsp_post_processor = Some(Box::new(processor)); self } @@ -241,11 +244,17 @@ impl Language { } pub fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) { - if let Some(processor) = self.diagnostic_processor.as_ref() { + if let Some(processor) = self.lsp_post_processor.as_ref() { processor.process_diagnostics(diagnostics); } } + pub fn label_for_completion(&self, completion: &lsp::CompletionItem) -> Option { + self.lsp_post_processor + .as_ref() + .and_then(|p| p.label_for_completion(completion)) + } + pub fn brackets(&self) -> &[BracketPair] { &self.config.brackets } diff --git a/crates/language/src/proto.rs b/crates/language/src/proto.rs index c95735493dcf5e26e85e4a877b83715d09e1141b..c934e0f3e4be7681d12b26a098fa9d78e08033e1 100644 --- a/crates/language/src/proto.rs +++ b/crates/language/src/proto.rs @@ -1,4 +1,4 @@ -use crate::{diagnostic_set::DiagnosticEntry, Completion, Diagnostic, Operation}; +use crate::{diagnostic_set::DiagnosticEntry, Completion, Diagnostic, Language, Operation}; use anyhow::{anyhow, Result}; use clock::ReplicaId; use collections::HashSet; @@ -387,7 +387,10 @@ pub fn serialize_completion(completion: &Completion) -> proto::Completio } } -pub fn deserialize_completion(completion: proto::Completion) -> Result> { +pub fn deserialize_completion( + completion: proto::Completion, + language: Option<&Arc>, +) -> Result> { let old_start = completion .old_start .and_then(deserialize_anchor) @@ -396,9 +399,11 @@ pub fn deserialize_completion(completion: proto::Completion) -> Result>, cx: &mut MutableAppContext, ) -> Task>>> { let worktree = self.worktree.read(cx); @@ -1448,7 +1451,9 @@ impl language::File for File { response .completions .into_iter() - .map(language::proto::deserialize_completion) + .map(|completion| { + language::proto::deserialize_completion(completion, language.as_ref()) + }) .collect() }) } diff --git a/crates/zed/src/language.rs b/crates/zed/src/language.rs index 4901f6ceaa1395d326e5f11a86a001b12b19fad7..b268647c0bfbb6ac8ddbf4da23196c3625fae20a 100644 --- a/crates/zed/src/language.rs +++ b/crates/zed/src/language.rs @@ -9,9 +9,9 @@ use std::{str, sync::Arc}; #[folder = "languages"] struct LanguageDir; -struct RustDiagnosticProcessor; +struct RustPostProcessor; -impl DiagnosticProcessor for RustDiagnosticProcessor { +impl LspPostProcessor for RustPostProcessor { fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) { lazy_static! { static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap(); @@ -31,6 +31,15 @@ impl DiagnosticProcessor for RustDiagnosticProcessor { } } } + + fn label_for_completion(&self, completion: &lsp::CompletionItem) -> Option { + let detail = completion.detail.as_ref()?; + if detail.starts_with("fn(") { + Some(completion.label.replace("(…)", &detail[2..])) + } else { + None + } + } } pub fn build_language_registry() -> LanguageRegistry { @@ -52,7 +61,7 @@ fn rust() -> Language { .unwrap() .with_outline_query(load_query("rust/outline.scm").as_ref()) .unwrap() - .with_diagnostics_processor(RustDiagnosticProcessor) + .with_lsp_post_processor(RustPostProcessor) } fn markdown() -> Language { @@ -72,9 +81,9 @@ fn load_query(path: &str) -> Cow<'static, str> { #[cfg(test)] mod tests { - use language::DiagnosticProcessor; + use language::LspPostProcessor; - use super::RustDiagnosticProcessor; + use super::RustPostProcessor; #[test] fn test_process_rust_diagnostics() { @@ -100,7 +109,7 @@ mod tests { }, ], }; - RustDiagnosticProcessor.process_diagnostics(&mut params); + RustPostProcessor.process_diagnostics(&mut params); assert_eq!(params.diagnostics[0].message, "use of moved value `a`");