From d4da5135f45b542f8b0729019e04c3a24e58a9f0 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Jun 2022 10:44:42 +0200 Subject: [PATCH 1/6] Introduce support for C++ --- Cargo.lock | 11 ++ crates/zed/Cargo.toml | 1 + crates/zed/src/languages.rs | 6 + crates/zed/src/languages/c/config.toml | 2 +- crates/zed/src/languages/c/highlights.scm | 1 - crates/zed/src/languages/cpp.rs | 35 +++++ crates/zed/src/languages/cpp/brackets.scm | 3 + crates/zed/src/languages/cpp/config.toml | 11 ++ crates/zed/src/languages/cpp/highlights.scm | 158 ++++++++++++++++++++ crates/zed/src/languages/cpp/indents.scm | 7 + crates/zed/src/languages/cpp/outline.scm | 101 +++++++++++++ crates/zed/src/main.rs | 14 ++ 12 files changed, 348 insertions(+), 2 deletions(-) create mode 100644 crates/zed/src/languages/cpp.rs create mode 100644 crates/zed/src/languages/cpp/brackets.scm create mode 100644 crates/zed/src/languages/cpp/config.toml create mode 100644 crates/zed/src/languages/cpp/highlights.scm create mode 100644 crates/zed/src/languages/cpp/indents.scm create mode 100644 crates/zed/src/languages/cpp/outline.scm diff --git a/Cargo.lock b/Cargo.lock index 882558c051..9a3a333fe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5318,6 +5318,16 @@ dependencies = [ "tree-sitter", ] +[[package]] +name = "tree-sitter-cpp" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a869e3c5cef4e5db4e9ab16a8dc84d73010e60ada14cdc60d2f6d8aed17779d" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-json" version = "0.19.0" @@ -6030,6 +6040,7 @@ dependencies = [ "toml", "tree-sitter", "tree-sitter-c", + "tree-sitter-cpp", "tree-sitter-json 0.20.0", "tree-sitter-markdown", "tree-sitter-rust", diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index a9a266a6b7..7e203a15ff 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -88,6 +88,7 @@ tiny_http = "0.8" toml = "0.5" tree-sitter = "0.20.6" tree-sitter-c = "0.20.1" +tree-sitter-cpp = "0.20.0" tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8" } tree-sitter-rust = "0.20.1" tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" } diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index 36900e3e71..ab2bb16d17 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -4,6 +4,7 @@ use rust_embed::RustEmbed; use std::{borrow::Cow, str, sync::Arc}; mod c; +mod cpp; mod installation; mod json; mod rust; @@ -22,6 +23,11 @@ pub fn build_language_registry(login_shell_env_loaded: Task<()>) -> LanguageRegi tree_sitter_c::language(), Some(Arc::new(c::CLspAdapter) as Arc), ), + ( + "cpp", + tree_sitter_cpp::language(), + Some(Arc::new(cpp::CppLspAdapter) as Arc), + ), ( "json", tree_sitter_json::language(), diff --git a/crates/zed/src/languages/c/config.toml b/crates/zed/src/languages/c/config.toml index b7e1f07443..5b48415610 100644 --- a/crates/zed/src/languages/c/config.toml +++ b/crates/zed/src/languages/c/config.toml @@ -1,5 +1,5 @@ name = "C" -path_suffixes = ["c", "h"] +path_suffixes = ["c"] line_comment = "// " autoclose_before = ";:.,=}])>" brackets = [ diff --git a/crates/zed/src/languages/c/highlights.scm b/crates/zed/src/languages/c/highlights.scm index 4a9c7bf2ea..007c871ffa 100644 --- a/crates/zed/src/languages/c/highlights.scm +++ b/crates/zed/src/languages/c/highlights.scm @@ -75,7 +75,6 @@ (comment) @comment -(null) @constant (number_literal) @number [ diff --git a/crates/zed/src/languages/cpp.rs b/crates/zed/src/languages/cpp.rs new file mode 100644 index 0000000000..d6e4bf0819 --- /dev/null +++ b/crates/zed/src/languages/cpp.rs @@ -0,0 +1,35 @@ +use anyhow::Result; +use client::http::HttpClient; +use futures::future::BoxFuture; +pub use language::*; +use std::{any::Any, path::PathBuf, sync::Arc}; + +pub struct CppLspAdapter; + +impl super::LspAdapter for CppLspAdapter { + fn name(&self) -> LanguageServerName { + LanguageServerName("clangd".into()) + } + + fn fetch_latest_server_version( + &self, + http: Arc, + ) -> BoxFuture<'static, Result>> { + super::c::CLspAdapter.fetch_latest_server_version(http) + } + + fn fetch_server_binary( + &self, + version: Box, + http: Arc, + container_dir: PathBuf, + ) -> BoxFuture<'static, Result> { + super::c::CLspAdapter.fetch_server_binary(version, http, container_dir) + } + + fn cached_server_binary(&self, container_dir: PathBuf) -> BoxFuture<'static, Option> { + super::c::CLspAdapter.cached_server_binary(container_dir) + } + + fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} +} diff --git a/crates/zed/src/languages/cpp/brackets.scm b/crates/zed/src/languages/cpp/brackets.scm new file mode 100644 index 0000000000..9e8c9cd93c --- /dev/null +++ b/crates/zed/src/languages/cpp/brackets.scm @@ -0,0 +1,3 @@ +("[" @open "]" @close) +("{" @open "}" @close) +("\"" @open "\"" @close) diff --git a/crates/zed/src/languages/cpp/config.toml b/crates/zed/src/languages/cpp/config.toml new file mode 100644 index 0000000000..e9a793ec3c --- /dev/null +++ b/crates/zed/src/languages/cpp/config.toml @@ -0,0 +1,11 @@ +name = "C++" +path_suffixes = ["cc", "cpp", "h", "hpp"] +line_comment = "// " +autoclose_before = ";:.,=}])>" +brackets = [ + { start = "{", end = "}", close = true, newline = true }, + { start = "[", end = "]", close = true, newline = true }, + { start = "(", end = ")", close = true, newline = true }, + { start = "\"", end = "\"", close = true, newline = false }, + { start = "/*", end = " */", close = true, newline = false }, +] diff --git a/crates/zed/src/languages/cpp/highlights.scm b/crates/zed/src/languages/cpp/highlights.scm new file mode 100644 index 0000000000..d579d70187 --- /dev/null +++ b/crates/zed/src/languages/cpp/highlights.scm @@ -0,0 +1,158 @@ +(call_expression + function: (qualified_identifier + name: (identifier) @function)) + +(call_expression + function: (identifier) @function) + +(call_expression + function: (field_expression + field: (field_identifier) @function)) + +(preproc_function_def + name: (identifier) @function.special) + +(template_function + name: (identifier) @function) + +(template_method + name: (field_identifier) @function) + +(function_declarator + declarator: (identifier) @function) + +(function_declarator + declarator: (qualified_identifier + name: (identifier) @function)) + +(function_declarator + declarator: (field_identifier) @function) + +((namespace_identifier) @type + (#match? @type "^[A-Z]")) + +(auto) @type +(type_identifier) @type + +(identifier) @variable + +((identifier) @constant + (#match? @constant "^[A-Z][A-Z\\d_]*$")) + +(field_identifier) @property +(statement_identifier) @label +(this) @variable.builtin + +[ + "break" + "case" + "catch" + "class" + "co_await" + "co_return" + "co_yield" + "const" + "constexpr" + "continue" + "default" + "delete" + "do" + "else" + "enum" + "explicit" + "extern" + "final" + "for" + "friend" + "if" + "if" + "inline" + "mutable" + "namespace" + "new" + "noexcept" + "override" + "private" + "protected" + "public" + "return" + "sizeof" + "static" + "struct" + "switch" + "template" + "throw" + "try" + "typedef" + "typename" + "union" + "using" + "virtual" + "volatile" + "while" + (primitive_type) + (type_qualifier) +] @keyword + +[ + "#define" + "#elif" + "#else" + "#endif" + "#if" + "#ifdef" + "#ifndef" + "#include" + (preproc_directive) +] @keyword + +(comment) @comment + +[ + (true) + (false) + (null) + (nullptr) +] @constant + +(number_literal) @number + +[ + (string_literal) + (system_lib_string) + (char_literal) + (raw_string_literal) +] @string + +[ + "." + ";" +] @punctuation.delimiter + +[ + "{" + "}" + "(" + ")" + "[" + "]" +] @punctuation.bracket + +[ + "--" + "-" + "-=" + "->" + "=" + "!=" + "*" + "&" + "&&" + "+" + "++" + "+=" + "<" + "==" + ">" + "||" +] @operator diff --git a/crates/zed/src/languages/cpp/indents.scm b/crates/zed/src/languages/cpp/indents.scm new file mode 100644 index 0000000000..a17f4c4821 --- /dev/null +++ b/crates/zed/src/languages/cpp/indents.scm @@ -0,0 +1,7 @@ +[ + (field_expression) + (assignment_expression) +] @indent + +(_ "{" "}" @end) @indent +(_ "(" ")" @end) @indent diff --git a/crates/zed/src/languages/cpp/outline.scm b/crates/zed/src/languages/cpp/outline.scm new file mode 100644 index 0000000000..cefbac314d --- /dev/null +++ b/crates/zed/src/languages/cpp/outline.scm @@ -0,0 +1,101 @@ +(preproc_def + "#define" @context + name: (_) @name) @item + +(preproc_function_def + "#define" @context + name: (_) @name + parameters: (preproc_params + "(" @context + ")" @context)) @item + +(type_definition + "typedef" @context + declarator: (_) @name) @item + +(struct_specifier + "struct" @context + name: (_) @name) @item + +(class_specifier + "class" @context + name: (_) @name) @item + +(enum_specifier + "enum" @context + name: (_) @name) @item + +(enumerator + name: (_) @name) @item + +(declaration + (storage_class_specifier) @context + (type_qualifier)? @context + type: (_) @context + declarator: (init_declarator + declarator: (_) @name)) @item + +(function_definition + (type_qualifier)? @context + type: (_)? @context + declarator: [ + (function_declarator + declarator: (_) @name + parameters: (parameter_list + "(" @context + ")" @context)) + (pointer_declarator + "*" @context + declarator: (function_declarator + declarator: (_) @name + parameters: (parameter_list + "(" @context + ")" @context))) + ] + (type_qualifier)? @context) @item + +(declaration + (type_qualifier)? @context + type: (_)? @context + declarator: [ + (field_identifier) @name + (pointer_declarator + "*" @context + declarator: (field_identifier) @name) + (function_declarator + declarator: (_) @name + parameters: (parameter_list + "(" @context + ")" @context)) + (pointer_declarator + "*" @context + declarator: (function_declarator + declarator: (_) @name + parameters: (parameter_list + "(" @context + ")" @context))) + ] + (type_qualifier)? @context) @item + +(field_declaration + (type_qualifier)? @context + type: (_) @context + declarator: [ + (field_identifier) @name + (pointer_declarator + "*" @context + declarator: (field_identifier) @name) + (function_declarator + declarator: (_) @name + parameters: (parameter_list + "(" @context + ")" @context)) + (pointer_declarator + "*" @context + declarator: (function_declarator + declarator: (_) @name + parameters: (parameter_list + "(" @context + ")" @context))) + ] + (type_qualifier)? @context) @item diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 20d467f276..794c6eff34 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -74,6 +74,20 @@ fn main() { ..Default::default() }, ) + .with_overrides( + "C", + settings::LanguageOverride { + tab_size: Some(2), + ..Default::default() + }, + ) + .with_overrides( + "C++", + settings::LanguageOverride { + tab_size: Some(2), + ..Default::default() + }, + ) .with_overrides( "Markdown", settings::LanguageOverride { From 8ca012765883d89b5e59cf9f5dcf5b0c90b7f706 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Jun 2022 10:56:26 +0200 Subject: [PATCH 2/6] Make `LspAdapter::process_diagnostics` optional --- crates/language/src/language.rs | 3 ++- crates/zed/src/languages/c.rs | 2 -- crates/zed/src/languages/cpp.rs | 2 -- crates/zed/src/languages/json.rs | 2 -- crates/zed/src/languages/typescript.rs | 2 -- 5 files changed, 2 insertions(+), 9 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index b9d28c76a1..00f86a2488 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -77,7 +77,8 @@ pub trait LspAdapter: 'static + Send + Sync { container_dir: PathBuf, ) -> BoxFuture<'static, Result>; fn cached_server_binary(&self, container_dir: PathBuf) -> BoxFuture<'static, Option>; - fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams); + + fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} fn label_for_completion(&self, _: &lsp::CompletionItem, _: &Language) -> Option { None diff --git a/crates/zed/src/languages/c.rs b/crates/zed/src/languages/c.rs index 974742ad33..a411c34f2d 100644 --- a/crates/zed/src/languages/c.rs +++ b/crates/zed/src/languages/c.rs @@ -105,6 +105,4 @@ impl super::LspAdapter for CLspAdapter { .log_err() .boxed() } - - fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} } diff --git a/crates/zed/src/languages/cpp.rs b/crates/zed/src/languages/cpp.rs index d6e4bf0819..f624c0e930 100644 --- a/crates/zed/src/languages/cpp.rs +++ b/crates/zed/src/languages/cpp.rs @@ -30,6 +30,4 @@ impl super::LspAdapter for CppLspAdapter { fn cached_server_binary(&self, container_dir: PathBuf) -> BoxFuture<'static, Option> { super::c::CLspAdapter.cached_server_binary(container_dir) } - - fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} } diff --git a/crates/zed/src/languages/json.rs b/crates/zed/src/languages/json.rs index 5bbaba8d90..dab6922c71 100644 --- a/crates/zed/src/languages/json.rs +++ b/crates/zed/src/languages/json.rs @@ -120,8 +120,6 @@ impl LspAdapter for JsonLspAdapter { .boxed() } - fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} - fn initialization_options(&self) -> Option { Some(json!({ "provideFormatter": true diff --git a/crates/zed/src/languages/typescript.rs b/crates/zed/src/languages/typescript.rs index 79c74c521d..96682d26d7 100644 --- a/crates/zed/src/languages/typescript.rs +++ b/crates/zed/src/languages/typescript.rs @@ -113,8 +113,6 @@ impl LspAdapter for TypeScriptLspAdapter { .boxed() } - fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} - fn label_for_completion( &self, item: &lsp::CompletionItem, From c6e6a9f1eb3082a75dfe487d1da7708d64c339f1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Jun 2022 11:32:42 +0200 Subject: [PATCH 3/6] Show prettier completions for C++ --- crates/zed/src/languages/cpp.rs | 76 +++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/crates/zed/src/languages/cpp.rs b/crates/zed/src/languages/cpp.rs index f624c0e930..44ccb36e63 100644 --- a/crates/zed/src/languages/cpp.rs +++ b/crates/zed/src/languages/cpp.rs @@ -30,4 +30,80 @@ impl super::LspAdapter for CppLspAdapter { fn cached_server_binary(&self, container_dir: PathBuf) -> BoxFuture<'static, Option> { super::c::CLspAdapter.cached_server_binary(container_dir) } + + fn label_for_completion( + &self, + completion: &lsp::CompletionItem, + language: &Language, + ) -> Option { + let label = completion + .label + .strip_prefix("•") + .unwrap_or(&completion.label) + .trim(); + + match completion.kind { + Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => { + let detail = completion.detail.as_ref().unwrap(); + let text = format!("{} {}", detail, label); + let source = Rope::from(format!("struct S {{ {} }}", text).as_str()); + let runs = language.highlight_text(&source, 11..11 + text.len()); + return Some(CodeLabel { + filter_range: detail.len() + 1..text.len(), + text, + runs, + }); + } + Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE) + if completion.detail.is_some() => + { + let detail = completion.detail.as_ref().unwrap(); + let text = format!("{} {}", detail, label); + let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len()); + return Some(CodeLabel { + filter_range: detail.len() + 1..text.len(), + text, + runs, + }); + } + Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD) + if completion.detail.is_some() => + { + let detail = completion.detail.as_ref().unwrap(); + let text = format!("{} {}", detail, label); + let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len()); + return Some(CodeLabel { + filter_range: detail.len() + 1..text.rfind('(').unwrap_or(text.len()), + text, + runs, + }); + } + Some(kind) => { + let highlight_name = match kind { + lsp::CompletionItemKind::STRUCT + | lsp::CompletionItemKind::INTERFACE + | lsp::CompletionItemKind::ENUM => Some("type"), + lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"), + lsp::CompletionItemKind::KEYWORD => Some("keyword"), + lsp::CompletionItemKind::VALUE | lsp::CompletionItemKind::CONSTANT => { + Some("constant") + } + _ => None, + }; + if let Some(highlight_id) = language + .grammar() + .and_then(|g| g.highlight_id_for_name(highlight_name?)) + { + let mut label = CodeLabel::plain(label.to_string(), None); + label.runs.push(( + 0..label.text.rfind('(').unwrap_or(label.text.len()), + highlight_id, + )); + return Some(label); + } + } + _ => {} + } + Some(CodeLabel::plain(label.to_string(), None)) + } } From 416496225e934754c1fee346ad88c99efecd9692 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Jun 2022 11:47:21 +0200 Subject: [PATCH 4/6] Syntax-highlight project-wide symbols for C++ --- crates/zed/src/languages/cpp.rs | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/crates/zed/src/languages/cpp.rs b/crates/zed/src/languages/cpp.rs index 44ccb36e63..e2dba3c5c3 100644 --- a/crates/zed/src/languages/cpp.rs +++ b/crates/zed/src/languages/cpp.rs @@ -82,6 +82,7 @@ impl super::LspAdapter for CppLspAdapter { let highlight_name = match kind { lsp::CompletionItemKind::STRUCT | lsp::CompletionItemKind::INTERFACE + | lsp::CompletionItemKind::CLASS | lsp::CompletionItemKind::ENUM => Some("type"), lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"), lsp::CompletionItemKind::KEYWORD => Some("keyword"), @@ -106,4 +107,63 @@ impl super::LspAdapter for CppLspAdapter { } Some(CodeLabel::plain(label.to_string(), None)) } + + fn label_for_symbol( + &self, + name: &str, + kind: lsp::SymbolKind, + language: &Language, + ) -> Option { + let (text, filter_range, display_range) = match kind { + lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { + let text = format!("void {} () {{}}", name); + let filter_range = 0..name.len(); + let display_range = 5..5 + name.len(); + (text, filter_range, display_range) + } + lsp::SymbolKind::STRUCT => { + let text = format!("struct {} {{}}", name); + let filter_range = 7..7 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::ENUM => { + let text = format!("enum {} {{}}", name); + let filter_range = 5..5 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::INTERFACE | lsp::SymbolKind::CLASS => { + let text = format!("class {} {{}}", name); + let filter_range = 6..6 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::CONSTANT => { + let text = format!("const int {} = 0;", name); + let filter_range = 10..10 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::MODULE => { + let text = format!("namespace {} {{}}", name); + let filter_range = 10..10 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::TYPE_PARAMETER => { + let text = format!("typename {} {{}};", name); + let filter_range = 9..9 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + _ => return None, + }; + + Some(CodeLabel { + runs: language.highlight_text(&text.as_str().into(), display_range.clone()), + text: text[display_range].to_string(), + filter_range, + }) + } } From 1db4970c5a2b82d5fd5348a84deda3c031a57c2a Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Jun 2022 17:49:31 +0200 Subject: [PATCH 5/6] Implement `CppLspAdapter::name` by delegating to `CLspAdapter::name` This makes it more evident that both languages share the same language server. Co-Authored-By: Max Brunsfeld --- crates/zed/src/languages/cpp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zed/src/languages/cpp.rs b/crates/zed/src/languages/cpp.rs index e2dba3c5c3..2842da2397 100644 --- a/crates/zed/src/languages/cpp.rs +++ b/crates/zed/src/languages/cpp.rs @@ -8,7 +8,7 @@ pub struct CppLspAdapter; impl super::LspAdapter for CppLspAdapter { fn name(&self) -> LanguageServerName { - LanguageServerName("clangd".into()) + super::c::CLspAdapter.name() } fn fetch_latest_server_version( From 55fc2341d8a6f4c4b0eba7437b2ede716686d121 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 3 Jun 2022 18:05:43 +0200 Subject: [PATCH 6/6] Consolidate C and C++ LSP adapters Co-Authored-By: Max Brunsfeld --- crates/zed/src/languages.rs | 3 +- crates/zed/src/languages/c.rs | 136 +++++++++++++++++++++++++ crates/zed/src/languages/cpp.rs | 169 -------------------------------- 3 files changed, 137 insertions(+), 171 deletions(-) delete mode 100644 crates/zed/src/languages/cpp.rs diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index ab2bb16d17..6fad623858 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -4,7 +4,6 @@ use rust_embed::RustEmbed; use std::{borrow::Cow, str, sync::Arc}; mod c; -mod cpp; mod installation; mod json; mod rust; @@ -26,7 +25,7 @@ pub fn build_language_registry(login_shell_env_loaded: Task<()>) -> LanguageRegi ( "cpp", tree_sitter_cpp::language(), - Some(Arc::new(cpp::CppLspAdapter) as Arc), + Some(Arc::new(c::CLspAdapter) as Arc), ), ( "json", diff --git a/crates/zed/src/languages/c.rs b/crates/zed/src/languages/c.rs index a411c34f2d..99358453f4 100644 --- a/crates/zed/src/languages/c.rs +++ b/crates/zed/src/languages/c.rs @@ -105,4 +105,140 @@ impl super::LspAdapter for CLspAdapter { .log_err() .boxed() } + + fn label_for_completion( + &self, + completion: &lsp::CompletionItem, + language: &Language, + ) -> Option { + let label = completion + .label + .strip_prefix("•") + .unwrap_or(&completion.label) + .trim(); + + match completion.kind { + Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => { + let detail = completion.detail.as_ref().unwrap(); + let text = format!("{} {}", detail, label); + let source = Rope::from(format!("struct S {{ {} }}", text).as_str()); + let runs = language.highlight_text(&source, 11..11 + text.len()); + return Some(CodeLabel { + filter_range: detail.len() + 1..text.len(), + text, + runs, + }); + } + Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE) + if completion.detail.is_some() => + { + let detail = completion.detail.as_ref().unwrap(); + let text = format!("{} {}", detail, label); + let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len()); + return Some(CodeLabel { + filter_range: detail.len() + 1..text.len(), + text, + runs, + }); + } + Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD) + if completion.detail.is_some() => + { + let detail = completion.detail.as_ref().unwrap(); + let text = format!("{} {}", detail, label); + let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len()); + return Some(CodeLabel { + filter_range: detail.len() + 1..text.rfind('(').unwrap_or(text.len()), + text, + runs, + }); + } + Some(kind) => { + let highlight_name = match kind { + lsp::CompletionItemKind::STRUCT + | lsp::CompletionItemKind::INTERFACE + | lsp::CompletionItemKind::CLASS + | lsp::CompletionItemKind::ENUM => Some("type"), + lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"), + lsp::CompletionItemKind::KEYWORD => Some("keyword"), + lsp::CompletionItemKind::VALUE | lsp::CompletionItemKind::CONSTANT => { + Some("constant") + } + _ => None, + }; + if let Some(highlight_id) = language + .grammar() + .and_then(|g| g.highlight_id_for_name(highlight_name?)) + { + let mut label = CodeLabel::plain(label.to_string(), None); + label.runs.push(( + 0..label.text.rfind('(').unwrap_or(label.text.len()), + highlight_id, + )); + return Some(label); + } + } + _ => {} + } + Some(CodeLabel::plain(label.to_string(), None)) + } + + fn label_for_symbol( + &self, + name: &str, + kind: lsp::SymbolKind, + language: &Language, + ) -> Option { + let (text, filter_range, display_range) = match kind { + lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { + let text = format!("void {} () {{}}", name); + let filter_range = 0..name.len(); + let display_range = 5..5 + name.len(); + (text, filter_range, display_range) + } + lsp::SymbolKind::STRUCT => { + let text = format!("struct {} {{}}", name); + let filter_range = 7..7 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::ENUM => { + let text = format!("enum {} {{}}", name); + let filter_range = 5..5 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::INTERFACE | lsp::SymbolKind::CLASS => { + let text = format!("class {} {{}}", name); + let filter_range = 6..6 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::CONSTANT => { + let text = format!("const int {} = 0;", name); + let filter_range = 10..10 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::MODULE => { + let text = format!("namespace {} {{}}", name); + let filter_range = 10..10 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + lsp::SymbolKind::TYPE_PARAMETER => { + let text = format!("typename {} {{}};", name); + let filter_range = 9..9 + name.len(); + let display_range = 0..filter_range.end; + (text, filter_range, display_range) + } + _ => return None, + }; + + Some(CodeLabel { + runs: language.highlight_text(&text.as_str().into(), display_range.clone()), + text: text[display_range].to_string(), + filter_range, + }) + } } diff --git a/crates/zed/src/languages/cpp.rs b/crates/zed/src/languages/cpp.rs deleted file mode 100644 index 2842da2397..0000000000 --- a/crates/zed/src/languages/cpp.rs +++ /dev/null @@ -1,169 +0,0 @@ -use anyhow::Result; -use client::http::HttpClient; -use futures::future::BoxFuture; -pub use language::*; -use std::{any::Any, path::PathBuf, sync::Arc}; - -pub struct CppLspAdapter; - -impl super::LspAdapter for CppLspAdapter { - fn name(&self) -> LanguageServerName { - super::c::CLspAdapter.name() - } - - fn fetch_latest_server_version( - &self, - http: Arc, - ) -> BoxFuture<'static, Result>> { - super::c::CLspAdapter.fetch_latest_server_version(http) - } - - fn fetch_server_binary( - &self, - version: Box, - http: Arc, - container_dir: PathBuf, - ) -> BoxFuture<'static, Result> { - super::c::CLspAdapter.fetch_server_binary(version, http, container_dir) - } - - fn cached_server_binary(&self, container_dir: PathBuf) -> BoxFuture<'static, Option> { - super::c::CLspAdapter.cached_server_binary(container_dir) - } - - fn label_for_completion( - &self, - completion: &lsp::CompletionItem, - language: &Language, - ) -> Option { - let label = completion - .label - .strip_prefix("•") - .unwrap_or(&completion.label) - .trim(); - - match completion.kind { - Some(lsp::CompletionItemKind::FIELD) if completion.detail.is_some() => { - let detail = completion.detail.as_ref().unwrap(); - let text = format!("{} {}", detail, label); - let source = Rope::from(format!("struct S {{ {} }}", text).as_str()); - let runs = language.highlight_text(&source, 11..11 + text.len()); - return Some(CodeLabel { - filter_range: detail.len() + 1..text.len(), - text, - runs, - }); - } - Some(lsp::CompletionItemKind::CONSTANT | lsp::CompletionItemKind::VARIABLE) - if completion.detail.is_some() => - { - let detail = completion.detail.as_ref().unwrap(); - let text = format!("{} {}", detail, label); - let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len()); - return Some(CodeLabel { - filter_range: detail.len() + 1..text.len(), - text, - runs, - }); - } - Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD) - if completion.detail.is_some() => - { - let detail = completion.detail.as_ref().unwrap(); - let text = format!("{} {}", detail, label); - let runs = language.highlight_text(&Rope::from(text.as_str()), 0..text.len()); - return Some(CodeLabel { - filter_range: detail.len() + 1..text.rfind('(').unwrap_or(text.len()), - text, - runs, - }); - } - Some(kind) => { - let highlight_name = match kind { - lsp::CompletionItemKind::STRUCT - | lsp::CompletionItemKind::INTERFACE - | lsp::CompletionItemKind::CLASS - | lsp::CompletionItemKind::ENUM => Some("type"), - lsp::CompletionItemKind::ENUM_MEMBER => Some("variant"), - lsp::CompletionItemKind::KEYWORD => Some("keyword"), - lsp::CompletionItemKind::VALUE | lsp::CompletionItemKind::CONSTANT => { - Some("constant") - } - _ => None, - }; - if let Some(highlight_id) = language - .grammar() - .and_then(|g| g.highlight_id_for_name(highlight_name?)) - { - let mut label = CodeLabel::plain(label.to_string(), None); - label.runs.push(( - 0..label.text.rfind('(').unwrap_or(label.text.len()), - highlight_id, - )); - return Some(label); - } - } - _ => {} - } - Some(CodeLabel::plain(label.to_string(), None)) - } - - fn label_for_symbol( - &self, - name: &str, - kind: lsp::SymbolKind, - language: &Language, - ) -> Option { - let (text, filter_range, display_range) = match kind { - lsp::SymbolKind::METHOD | lsp::SymbolKind::FUNCTION => { - let text = format!("void {} () {{}}", name); - let filter_range = 0..name.len(); - let display_range = 5..5 + name.len(); - (text, filter_range, display_range) - } - lsp::SymbolKind::STRUCT => { - let text = format!("struct {} {{}}", name); - let filter_range = 7..7 + name.len(); - let display_range = 0..filter_range.end; - (text, filter_range, display_range) - } - lsp::SymbolKind::ENUM => { - let text = format!("enum {} {{}}", name); - let filter_range = 5..5 + name.len(); - let display_range = 0..filter_range.end; - (text, filter_range, display_range) - } - lsp::SymbolKind::INTERFACE | lsp::SymbolKind::CLASS => { - let text = format!("class {} {{}}", name); - let filter_range = 6..6 + name.len(); - let display_range = 0..filter_range.end; - (text, filter_range, display_range) - } - lsp::SymbolKind::CONSTANT => { - let text = format!("const int {} = 0;", name); - let filter_range = 10..10 + name.len(); - let display_range = 0..filter_range.end; - (text, filter_range, display_range) - } - lsp::SymbolKind::MODULE => { - let text = format!("namespace {} {{}}", name); - let filter_range = 10..10 + name.len(); - let display_range = 0..filter_range.end; - (text, filter_range, display_range) - } - lsp::SymbolKind::TYPE_PARAMETER => { - let text = format!("typename {} {{}};", name); - let filter_range = 9..9 + name.len(); - let display_range = 0..filter_range.end; - (text, filter_range, display_range) - } - _ => return None, - }; - - Some(CodeLabel { - runs: language.highlight_text(&text.as_str().into(), display_range.clone()), - text: text[display_range].to_string(), - filter_range, - }) - } -}