Introduce support for C++

Antonio Scandurra created

Change summary

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(-)

Detailed changes

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",

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" }

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<dyn LspAdapter>),
         ),
+        (
+            "cpp",
+            tree_sitter_cpp::language(),
+            Some(Arc::new(cpp::CppLspAdapter) as Arc<dyn LspAdapter>),
+        ),
         (
             "json",
             tree_sitter_json::language(),

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<dyn HttpClient>,
+    ) -> BoxFuture<'static, Result<Box<dyn 'static + Send + Any>>> {
+        super::c::CLspAdapter.fetch_latest_server_version(http)
+    }
+
+    fn fetch_server_binary(
+        &self,
+        version: Box<dyn 'static + Send + Any>,
+        http: Arc<dyn HttpClient>,
+        container_dir: PathBuf,
+    ) -> BoxFuture<'static, Result<PathBuf>> {
+        super::c::CLspAdapter.fetch_server_binary(version, http, container_dir)
+    }
+
+    fn cached_server_binary(&self, container_dir: PathBuf) -> BoxFuture<'static, Option<PathBuf>> {
+        super::c::CLspAdapter.cached_server_binary(container_dir)
+    }
+
+    fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
+}

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 },
+]

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

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

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 {