From 92e2c329e24dd1bfda3d2fa9a4219902589b0b2c Mon Sep 17 00:00:00 2001 From: Fred Minkowski Date: Sat, 27 Jan 2024 22:14:19 -0500 Subject: [PATCH 1/6] C# Support: Add treesitter and OmniSharp LSP support --- Cargo.lock | 10 + Cargo.toml | 1 + crates/zed/Cargo.toml | 1 + crates/zed/src/languages.rs | 6 + crates/zed/src/languages/csharp.rs | 144 ++++++ crates/zed/src/languages/csharp/config.toml | 12 + crates/zed/src/languages/csharp/folds.scm | 12 + .../zed/src/languages/csharp/highlights.scm | 469 ++++++++++++++++++ .../zed/src/languages/csharp/injections.scm | 2 + 9 files changed, 657 insertions(+) create mode 100644 crates/zed/src/languages/csharp.rs create mode 100644 crates/zed/src/languages/csharp/config.toml create mode 100644 crates/zed/src/languages/csharp/folds.scm create mode 100644 crates/zed/src/languages/csharp/highlights.scm create mode 100644 crates/zed/src/languages/csharp/injections.scm diff --git a/Cargo.lock b/Cargo.lock index 8a141a31cb4885..c54266a7c4218a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8453,6 +8453,15 @@ dependencies = [ "tree-sitter", ] +[[package]] +name = "tree-sitter-c-sharp" +version = "0.20.0" +source = "git+https://github.com/tree-sitter/tree-sitter-c-sharp?rev=dd5e59721a5f8dae34604060833902b882023aaf#dd5e59721a5f8dae34604060833902b882023aaf" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-cpp" version = "0.20.0" @@ -9811,6 +9820,7 @@ dependencies = [ "tree-sitter", "tree-sitter-bash", "tree-sitter-c", + "tree-sitter-c-sharp", "tree-sitter-cpp", "tree-sitter-css", "tree-sitter-elixir", diff --git a/Cargo.toml b/Cargo.toml index eaa09c4c8f92fb..0d49975536f3d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -136,6 +136,7 @@ uuid = { version = "1.1.2", features = ["v4"] } tree-sitter-bash = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "7331995b19b8f8aba2d5e26deb51d2195c18bc94" } tree-sitter-c = "0.20.1" tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev="f44509141e7e483323d2ec178f2d2e6c0fc041c1" } +tree-sitter-c-sharp = { git = "https://github.com/tree-sitter/tree-sitter-c-sharp", rev = "dd5e59721a5f8dae34604060833902b882023aaf" } tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" } tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "a2861e88a730287a60c11ea9299c033c7d076e30" } tree-sitter-elm = { git = "https://github.com/elm-tooling/tree-sitter-elm", rev = "692c50c0b961364c40299e73c1306aecb5d20f40"} diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 97c5a6e394d4e5..d57e50300cfb7a 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -116,6 +116,7 @@ tree-sitter.workspace = true tree-sitter-bash.workspace = true tree-sitter-c.workspace = true tree-sitter-cpp.workspace = true +tree-sitter-c-sharp.workspace = true tree-sitter-css.workspace = true tree-sitter-elixir.workspace = true tree-sitter-elm.workspace = true diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index ac3d7f2ee8ad60..08b22795a3ca06 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -10,6 +10,7 @@ use util::{asset_str, paths::PLUGINS_DIR}; use self::{deno::DenoSettings, elixir::ElixirSettings}; mod c; +mod csharp; mod css; mod deno; mod elixir; @@ -72,6 +73,11 @@ pub fn init( tree_sitter_cpp::language(), vec![Arc::new(c::CLspAdapter)], ); + language( + "csharp", + tree_sitter_c_sharp::language(), + vec![Arc::new(csharp::OmniSharpAdapter {})], + ); language( "css", tree_sitter_css::language(), diff --git a/crates/zed/src/languages/csharp.rs b/crates/zed/src/languages/csharp.rs new file mode 100644 index 00000000000000..e70bc78279f8a7 --- /dev/null +++ b/crates/zed/src/languages/csharp.rs @@ -0,0 +1,144 @@ +use anyhow::{anyhow, Context, Result}; +use async_compression::futures::bufread::GzipDecoder; +use async_tar::Archive; +use async_trait::async_trait; +use futures::{io::BufReader, StreamExt}; +use language::{LanguageServerName, LspAdapterDelegate}; +use lsp::LanguageServerBinary; +use smol::fs; +use std::env::consts::ARCH; +use std::ffi::OsString; +use std::{any::Any, path::PathBuf}; +use util::async_maybe; +use util::github::latest_github_release; +use util::{github::GitHubLspBinaryVersion, ResultExt}; + +pub struct OmniSharpAdapter; + +#[async_trait] +impl super::LspAdapter for OmniSharpAdapter { + fn name(&self) -> LanguageServerName { + LanguageServerName("OmniSharp".into()) + } + + fn short_name(&self) -> &'static str { + "OmniSharp" + } + + async fn fetch_latest_server_version( + &self, + delegate: &dyn LspAdapterDelegate, + ) -> Result> { + let release = + latest_github_release("OmniSharp/omnisharp-roslyn", false, delegate.http_client()) + .await?; + + let mapped_arch = match ARCH { + "aarch64" => Some("arm64"), + "x86_64" => Some("x64"), + _ => None, + }; + + match mapped_arch { + None => Ok(Box::new(())), + Some(arch) => { + let asset_name = format!("omnisharp-osx-{}-net6.0.tar.gz", arch); + let asset = release + .assets + .iter() + .find(|asset| asset.name == asset_name) + .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?; + let version = GitHubLspBinaryVersion { + name: release.name, + url: asset.browser_download_url.clone(), + }; + + Ok(Box::new(version) as Box<_>) + } + } + } + + async fn fetch_server_binary( + &self, + version: Box, + container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, + ) -> Result { + let version = version.downcast::().unwrap(); + let binary_path = container_dir.join("omnisharp"); + + if fs::metadata(&binary_path).await.is_err() { + let mut response = delegate + .http_client() + .get(&version.url, Default::default(), true) + .await + .context("error downloading release")?; + let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut())); + let archive = Archive::new(decompressed_bytes); + archive.unpack(container_dir).await?; + } + + fs::set_permissions( + &binary_path, + ::from_mode(0o755), + ) + .await?; + Ok(LanguageServerBinary { + path: binary_path, + arguments: server_binary_arguments(), + }) + } + + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { + get_cached_server_binary(container_dir).await + } + + async fn installation_test_binary( + &self, + container_dir: PathBuf, + ) -> Option { + get_cached_server_binary(container_dir) + .await + .map(|mut binary| { + binary.arguments = vec!["--help".into()]; + binary + }) + } +} + +async fn get_cached_server_binary(container_dir: PathBuf) -> Option { + async_maybe!({ + let mut last_binary_path = None; + let mut entries = fs::read_dir(&container_dir).await?; + while let Some(entry) = entries.next().await { + let entry = entry?; + if entry.file_type().await?.is_file() + && entry + .file_name() + .to_str() + .map_or(false, |name| name == "omnisharp") + { + last_binary_path = Some(entry.path()); + } + } + + if let Some(path) = last_binary_path { + Ok(LanguageServerBinary { + path, + arguments: server_binary_arguments(), + }) + } else { + Err(anyhow!("no cached binary")) + } + }) + .await + .log_err() +} + +fn server_binary_arguments() -> Vec { + vec!["-lsp".into()] +} diff --git a/crates/zed/src/languages/csharp/config.toml b/crates/zed/src/languages/csharp/config.toml new file mode 100644 index 00000000000000..7835283df496e7 --- /dev/null +++ b/crates/zed/src/languages/csharp/config.toml @@ -0,0 +1,12 @@ +name = "CSharp" +path_suffixes = ["cs"] +line_comments = ["// "] +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, not_in = ["string"] }, + { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] }, + { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] }, +] diff --git a/crates/zed/src/languages/csharp/folds.scm b/crates/zed/src/languages/csharp/folds.scm new file mode 100644 index 00000000000000..640242c6767460 --- /dev/null +++ b/crates/zed/src/languages/csharp/folds.scm @@ -0,0 +1,12 @@ +body: + [ + (declaration_list) + (switch_body) + (enum_member_declaration_list) + ] @fold + +accessors: (accessor_list) @fold + +initializer: (initializer_expression) @fold + +(block) @fold diff --git a/crates/zed/src/languages/csharp/highlights.scm b/crates/zed/src/languages/csharp/highlights.scm new file mode 100644 index 00000000000000..73205c31d31ce3 --- /dev/null +++ b/crates/zed/src/languages/csharp/highlights.scm @@ -0,0 +1,469 @@ +(identifier) @variable + +((identifier) @keyword + (#eq? @keyword "value") + (#has-ancestor? @keyword accessor_declaration)) + +((identifier) @variable.builtin + (#eq? @variable.builtin "_")) + +(method_declaration + name: (identifier) @function.method) + +(local_function_statement + name: (identifier) @function.method) + +(method_declaration + type: (identifier) @type) + +(declaration_pattern + type: (identifier) @type) + +(local_function_statement + type: (identifier) @type) + +(interpolation) @none + +(member_access_expression + name: (identifier) @variable.member) + +(invocation_expression + (member_access_expression + name: (identifier) @function.method.call)) + +(invocation_expression + function: + (conditional_access_expression + (member_binding_expression + name: (identifier) @function.method.call))) + +(namespace_declaration + name: + [ + (qualified_name) + (identifier) + ] @module) + +(qualified_name + (identifier) @type) + +(namespace_declaration + name: + [ + (qualified_name + (identifier) @module) + (identifier) @module + ]) + +(invocation_expression + (identifier) @function.method.call) + +(field_declaration + (variable_declaration + (variable_declarator + (identifier) @variable.member))) + +(initializer_expression + (assignment_expression + left: (identifier) @variable.member)) + +(parameter_list + (parameter + name: (identifier) @variable.parameter)) + +(implicit_parameter_list + (parameter + name: (identifier) @variable.parameter)) + +(parameter_list + (parameter + type: (identifier) @type)) + +(integer_literal) @number + +(real_literal) @number.float + +(null_literal) @constant.builtin + +(character_literal) @character + +[ + (string_literal) + (verbatim_string_literal) + (interpolated_string_expression) +] @string + +(boolean_literal) @boolean + +(predefined_type) @type.builtin + +(implicit_type) @keyword + +(comment) @comment @spell + +((comment) @comment.documentation + (#lua-match? @comment.documentation "^/[*][*][^*].*[*]/$")) + +((comment) @comment.documentation + (#lua-match? @comment.documentation "^///[^/]")) + +((comment) @comment.documentation + (#lua-match? @comment.documentation "^///$")) + +(using_directive + (identifier) @type) + +(using_directive + (name_equals + (identifier) @type.definition)) + +(property_declaration + name: (identifier) @property) + +(property_declaration + type: (identifier) @type) + +(nullable_type + (identifier) @type) + +(catch_declaration + type: (identifier) @type) + +(interface_declaration + name: (identifier) @type) + +(class_declaration + name: (identifier) @type) + +(record_declaration + name: (identifier) @type) + +(enum_declaration + name: (identifier) @type) + +(constructor_declaration + name: (identifier) @constructor) + +(constructor_initializer + "base" @constructor) + +(variable_declaration + (identifier) @type) + +(object_creation_expression + (identifier) @type) + +; Generic Types. +(type_of_expression + (generic_name + (identifier) @type)) + +(type_argument_list + (generic_name + (identifier) @type)) + +(base_list + (generic_name + (identifier) @type)) + +(type_constraint + (generic_name + (identifier) @type)) + +(object_creation_expression + (generic_name + (identifier) @type)) + +(property_declaration + (generic_name + (identifier) @type)) + +(_ + type: + (generic_name + (identifier) @type)) + +; Generic Method invocation with generic type +(invocation_expression + function: + (generic_name + . + (identifier) @function.method.call)) + +(invocation_expression + (member_access_expression + (generic_name + (identifier) @function.method))) + +(base_list + (identifier) @type) + +(type_argument_list + (identifier) @type) + +(type_parameter_list + (type_parameter) @type) + +(type_parameter_constraints_clause + target: (identifier) @type) + +(attribute + name: (identifier) @attribute) + +(for_each_statement + type: (identifier) @type) + +(tuple_element + type: (identifier) @type) + +(tuple_expression + (argument + (declaration_expression + type: (identifier) @type))) + +(as_expression + right: (identifier) @type) + +(type_of_expression + (identifier) @type) + +(name_colon + (identifier) @variable.parameter) + +(warning_directive) @comment.warning + +(error_directive) @keyword.exception + +(define_directive + (identifier) @constant) @constant.macro + +(undef_directive + (identifier) @constant) @constant.macro + +(line_directive) @constant.macro + +(line_directive + (preproc_integer_literal) @constant + (preproc_string_literal)? @string) + +(pragma_directive + (identifier) @constant) @constant.macro + +(pragma_directive + (preproc_string_literal) @string) @constant.macro + +[ + (nullable_directive) + (region_directive) + (endregion_directive) +] @constant.macro + +[ + "if" + "else" + "switch" + "break" + "case" + "when" + (if_directive) + (elif_directive) + (else_directive) + (endif_directive) +] @keyword.conditional + +(if_directive + (identifier) @constant) + +(elif_directive + (identifier) @constant) + +[ + "while" + "for" + "do" + "continue" + "goto" + "foreach" +] @keyword.repeat + +[ + "try" + "catch" + "throw" + "finally" +] @keyword.exception + +[ + "+" + "?" + ":" + "++" + "-" + "--" + "&" + "&&" + "|" + "||" + "!" + "!=" + "==" + "*" + "/" + "%" + "<" + "<=" + ">" + ">=" + "=" + "-=" + "+=" + "*=" + "/=" + "%=" + "^" + "^=" + "&=" + "|=" + "~" + ">>" + ">>>" + "<<" + "<<=" + ">>=" + ">>>=" + "=>" + "??" + "??=" +] @operator + +[ + ";" + "." + "," + ":" +] @punctuation.delimiter + +(conditional_expression + [ + "?" + ":" + ] @keyword.conditional.ternary) + +[ + "[" + "]" + "{" + "}" + "(" + ")" +] @punctuation.bracket + +(type_argument_list + [ + "<" + ">" + ] @punctuation.bracket) + +[ + (this_expression) + (base_expression) + "this" +] @variable.builtin + +[ + "using" + "as" +] @keyword.import + +(alias_qualified_name + (identifier + "global") @keyword.import) + +[ + "with" + "new" + "typeof" + "sizeof" + "is" + "and" + "or" + "not" + "stackalloc" + "in" + "out" + "ref" +] @keyword.operator + +[ + "lock" + "params" + "operator" + "default" + "implicit" + "explicit" + "override" + "class" + "delegate" + "enum" + "interface" + "namespace" + "struct" + "get" + "set" + "init" + "where" + "record" + "event" + "add" + "remove" + "checked" + "unchecked" + "fixed" + "alias" +] @keyword + +[ + "async" + "await" +] @keyword.coroutine + +[ + "const" + "extern" + "readonly" + "static" + "volatile" + "required" +] @keyword.storage + +[ + "abstract" + "private" + "protected" + "internal" + "public" + "partial" + "sealed" + "virtual" +] @type.qualifier + +(parameter_modifier) @operator + +(query_expression + (_ + [ + "from" + "orderby" + "select" + "group" + "by" + "ascending" + "descending" + "equals" + "let" + ] @keyword)) + +[ + "return" + "yield" +] @keyword.return diff --git a/crates/zed/src/languages/csharp/injections.scm b/crates/zed/src/languages/csharp/injections.scm new file mode 100644 index 00000000000000..2f0e58eb643151 --- /dev/null +++ b/crates/zed/src/languages/csharp/injections.scm @@ -0,0 +1,2 @@ +((comment) @injection.content + (#set! injection.language "comment")) From 3260d065703a260904bbf0c1d7761703ce9e84c3 Mon Sep 17 00:00:00 2001 From: Fred Minkowski Date: Sun, 28 Jan 2024 11:19:07 -0500 Subject: [PATCH 2/6] PR feedback: Update highlights and add outline.scm --- .../zed/src/languages/csharp/highlights.scm | 609 ++++++------------ crates/zed/src/languages/csharp/outline.scm | 47 ++ 2 files changed, 244 insertions(+), 412 deletions(-) create mode 100644 crates/zed/src/languages/csharp/outline.scm diff --git a/crates/zed/src/languages/csharp/highlights.scm b/crates/zed/src/languages/csharp/highlights.scm index 73205c31d31ce3..cb3c1ad4ad1bbb 100644 --- a/crates/zed/src/languages/csharp/highlights.scm +++ b/crates/zed/src/languages/csharp/highlights.scm @@ -1,469 +1,254 @@ -(identifier) @variable +;; Methods +(method_declaration name: (identifier) @function) +(local_function_statement name: (identifier) @function) -((identifier) @keyword - (#eq? @keyword "value") - (#has-ancestor? @keyword accessor_declaration)) +;; Types +(interface_declaration name: (identifier) @type) +(class_declaration name: (identifier) @type) +(enum_declaration name: (identifier) @type) +(struct_declaration (identifier) @type) +(record_declaration (identifier) @type) +(record_struct_declaration (identifier) @type) +(namespace_declaration name: (identifier) @type) -((identifier) @variable.builtin - (#eq? @variable.builtin "_")) +(constructor_declaration name: (identifier) @constructor) +(destructor_declaration name: (identifier) @constructor) -(method_declaration - name: (identifier) @function.method) - -(local_function_statement - name: (identifier) @function.method) - -(method_declaration - type: (identifier) @type) - -(declaration_pattern - type: (identifier) @type) - -(local_function_statement - type: (identifier) @type) - -(interpolation) @none - -(member_access_expression - name: (identifier) @variable.member) - -(invocation_expression - (member_access_expression - name: (identifier) @function.method.call)) - -(invocation_expression - function: - (conditional_access_expression - (member_binding_expression - name: (identifier) @function.method.call))) - -(namespace_declaration - name: - [ - (qualified_name) - (identifier) - ] @module) - -(qualified_name - (identifier) @type) - -(namespace_declaration - name: - [ - (qualified_name - (identifier) @module) - (identifier) @module - ]) - -(invocation_expression - (identifier) @function.method.call) - -(field_declaration - (variable_declaration - (variable_declarator - (identifier) @variable.member))) - -(initializer_expression - (assignment_expression - left: (identifier) @variable.member)) - -(parameter_list - (parameter - name: (identifier) @variable.parameter)) - -(implicit_parameter_list - (parameter - name: (identifier) @variable.parameter)) - -(parameter_list - (parameter - type: (identifier) @type)) - -(integer_literal) @number +[ + (implicit_type) + (predefined_type) +] @type.builtin -(real_literal) @number.float +(_ type: (identifier) @type) -(null_literal) @constant.builtin +;; Enum +(enum_member_declaration (identifier) @property) -(character_literal) @character +;; Literals +[ + (real_literal) + (integer_literal) +] @number [ + (character_literal) (string_literal) (verbatim_string_literal) - (interpolated_string_expression) -] @string - -(boolean_literal) @boolean - -(predefined_type) @type.builtin - -(implicit_type) @keyword - -(comment) @comment @spell - -((comment) @comment.documentation - (#lua-match? @comment.documentation "^/[*][*][^*].*[*]/$")) - -((comment) @comment.documentation - (#lua-match? @comment.documentation "^///[^/]")) - -((comment) @comment.documentation - (#lua-match? @comment.documentation "^///$")) - -(using_directive - (identifier) @type) - -(using_directive - (name_equals - (identifier) @type.definition)) - -(property_declaration - name: (identifier) @property) - -(property_declaration - type: (identifier) @type) - -(nullable_type - (identifier) @type) - -(catch_declaration - type: (identifier) @type) - -(interface_declaration - name: (identifier) @type) - -(class_declaration - name: (identifier) @type) - -(record_declaration - name: (identifier) @type) - -(enum_declaration - name: (identifier) @type) - -(constructor_declaration - name: (identifier) @constructor) - -(constructor_initializer - "base" @constructor) - -(variable_declaration - (identifier) @type) - -(object_creation_expression - (identifier) @type) - -; Generic Types. -(type_of_expression - (generic_name - (identifier) @type)) - -(type_argument_list - (generic_name - (identifier) @type)) - -(base_list - (generic_name - (identifier) @type)) - -(type_constraint - (generic_name - (identifier) @type)) - -(object_creation_expression - (generic_name - (identifier) @type)) - -(property_declaration - (generic_name - (identifier) @type)) - -(_ - type: - (generic_name - (identifier) @type)) - -; Generic Method invocation with generic type -(invocation_expression - function: - (generic_name - . - (identifier) @function.method.call)) - -(invocation_expression - (member_access_expression - (generic_name - (identifier) @function.method))) - -(base_list - (identifier) @type) - -(type_argument_list - (identifier) @type) - -(type_parameter_list - (type_parameter) @type) - -(type_parameter_constraints_clause - target: (identifier) @type) - -(attribute - name: (identifier) @attribute) - -(for_each_statement - type: (identifier) @type) - -(tuple_element - type: (identifier) @type) - -(tuple_expression - (argument - (declaration_expression - type: (identifier) @type))) - -(as_expression - right: (identifier) @type) - -(type_of_expression - (identifier) @type) - -(name_colon - (identifier) @variable.parameter) - -(warning_directive) @comment.warning - -(error_directive) @keyword.exception - -(define_directive - (identifier) @constant) @constant.macro - -(undef_directive - (identifier) @constant) @constant.macro - -(line_directive) @constant.macro - -(line_directive - (preproc_integer_literal) @constant - (preproc_string_literal)? @string) - -(pragma_directive - (identifier) @constant) @constant.macro - -(pragma_directive - (preproc_string_literal) @string) @constant.macro - -[ - (nullable_directive) - (region_directive) - (endregion_directive) -] @constant.macro + (interpolated_string_text) + (interpolated_verbatim_string_text) + "\"" + "$\"" + "@$\"" + "$@\"" + ] @string [ - "if" - "else" - "switch" - "break" - "case" - "when" - (if_directive) - (elif_directive) - (else_directive) - (endif_directive) -] @keyword.conditional - -(if_directive - (identifier) @constant) + (boolean_literal) + (null_literal) +] @constant -(elif_directive - (identifier) @constant) +;; Comments +(comment) @comment +;; Tokens [ - "while" - "for" - "do" - "continue" - "goto" - "foreach" -] @keyword.repeat - -[ - "try" - "catch" - "throw" - "finally" -] @keyword.exception + ";" + "." + "," +] @punctuation.delimiter [ - "+" - "?" - ":" - "++" - "-" "--" + "-" + "-=" "&" + "&=" "&&" - "|" - "||" - "!" - "!=" - "==" - "*" - "/" - "%" + "+" + "++" + "+=" "<" "<=" + "<<" + "<<=" + "=" + "==" + "!" + "!=" + "=>" ">" ">=" - "=" - "-=" - "+=" - "*=" - "/=" - "%=" - "^" - "^=" - "&=" - "|=" - "~" ">>" - ">>>" - "<<" - "<<=" ">>=" + ">>>" ">>>=" - "=>" + "|" + "|=" + "||" + "?" "??" "??=" -] @operator - -[ - ";" - "." - "," + "^" + "^=" + "~" + "*" + "*=" + "/" + "/=" + "%" + "%=" ":" -] @punctuation.delimiter - -(conditional_expression - [ - "?" - ":" - ] @keyword.conditional.ternary) +] @operator [ + "(" + ")" "[" "]" "{" "}" - "(" - ")" -] @punctuation.bracket +] @punctuation.bracket -(type_argument_list - [ - "<" - ">" - ] @punctuation.bracket) +;; Keywords +(modifier) @keyword +(this_expression) @keyword +(escape_sequence) @keyword [ - (this_expression) - (base_expression) - "this" -] @variable.builtin - -[ - "using" + "add" + "alias" "as" -] @keyword.import - -(alias_qualified_name - (identifier - "global") @keyword.import) - -[ - "with" - "new" - "typeof" - "sizeof" - "is" - "and" - "or" - "not" - "stackalloc" - "in" - "out" - "ref" -] @keyword.operator - -[ - "lock" - "params" - "operator" - "default" - "implicit" - "explicit" - "override" + "base" + "break" + "case" + "catch" + "checked" "class" + "continue" + "default" "delegate" + "do" + "else" "enum" + "event" + "explicit" + "extern" + "finally" + "for" + "foreach" + "global" + "goto" + "if" + "implicit" "interface" + "is" + "lock" "namespace" + "notnull" + "operator" + "params" + "return" + "remove" + "sizeof" + "stackalloc" + "static" "struct" + "switch" + "throw" + "try" + "typeof" + "unchecked" + "using" + "while" + "new" + "await" + "in" + "yield" "get" "set" - "init" + "when" + "out" + "ref" + "from" "where" + "select" "record" - "event" - "add" - "remove" - "checked" - "unchecked" - "fixed" - "alias" + "init" + "with" + "let" ] @keyword -[ - "async" - "await" -] @keyword.coroutine -[ - "const" - "extern" - "readonly" - "static" - "volatile" - "required" -] @keyword.storage +;; Linq +(from_clause (identifier) @variable) +(group_clause (identifier) @variable) +(order_by_clause (identifier) @variable) +(join_clause (identifier) @variable) +(select_clause (identifier) @variable) +(query_continuation (identifier) @variable) @keyword + +;; Record +(with_expression + (with_initializer_expression + (simple_assignment_expression + (identifier) @variable))) + +;; Exprs +(binary_expression (identifier) @variable (identifier) @variable) +(binary_expression (identifier)* @variable) +(conditional_expression (identifier) @variable) +(prefix_unary_expression (identifier) @variable) +(postfix_unary_expression (identifier)* @variable) +(assignment_expression (identifier) @variable) +(cast_expression (_) (identifier) @variable) + +;; Class +(base_list (identifier) @type) ;; applies to record_base too +(property_declaration (generic_name)) +(property_declaration + name: (identifier) @variable) +(property_declaration + name: (identifier) @variable) +(property_declaration + name: (identifier) @variable) -[ - "abstract" - "private" - "protected" - "internal" - "public" - "partial" - "sealed" - "virtual" -] @type.qualifier +;; Lambda +(lambda_expression) @variable -(parameter_modifier) @operator +;; Attribute +(attribute) @attribute -(query_expression - (_ - [ - "from" - "orderby" - "select" - "group" - "by" - "ascending" - "descending" - "equals" - "let" - ] @keyword)) +;; Parameter +(parameter + name: (identifier) @variable) +(parameter (identifier) @variable) +(parameter_modifier) @keyword -[ - "return" - "yield" -] @keyword.return +;; Variable declarations +(variable_declarator (identifier) @variable) +(for_each_statement left: (identifier) @variable) +(catch_declaration (_) (identifier) @variable) + +;; Return +(return_statement (identifier) @variable) +(yield_statement (identifier) @variable) + +;; Type +(generic_name (identifier) @type) +(type_parameter (identifier) @property) +(type_argument_list (identifier) @type) +(as_expression right: (identifier) @type) +(is_expression right: (identifier) @type) + +;; Type constraints +(type_parameter_constraints_clause (identifier) @property) + +;; Switch +(switch_statement (identifier) @variable) +(switch_expression (identifier) @variable) + +;; Lock statement +(lock_statement (identifier) @variable) + +;; Method calls +(invocation_expression (member_access_expression name: (identifier) @function)) diff --git a/crates/zed/src/languages/csharp/outline.scm b/crates/zed/src/languages/csharp/outline.scm new file mode 100644 index 00000000000000..e8d4594076a61c --- /dev/null +++ b/crates/zed/src/languages/csharp/outline.scm @@ -0,0 +1,47 @@ +(class_declaration + (modifier)? @context + "class" @context + name: (identifier) @name +) @item + +(constructor_declaration + (modifier)? @context + name: (identifier) @name +) @item + +(property_declaration + (modifier)? @context + type: (identifier)? @context + type: (predefined_type)? @context + name: (identifier) @name +) @item + +(field_declaration + (modifier)? @context + (modifier)? @context + (variable_declaration) @context +) @item + +(method_declaration + (modifier)? @context + (modifier)? @context + type: (generic_name)? @context + name: (identifier) @name +) @item + +(enum_declaration + (modifier)? @context + "enum" @context + name: (identifier) @name +) @item + +(namespace_declaration + "namespace" @context + name: (qualified_name) @name +) @item + +(interface_declaration + (modifier)? @context + "interface" @context + name: (identifier) @name +) @item From 6eae2e319dc9386e2b3f3d20b9f3eedbc0a82506 Mon Sep 17 00:00:00 2001 From: Fred Minkowski Date: Sun, 28 Jan 2024 11:34:28 -0500 Subject: [PATCH 3/6] Add additional method signature matchers --- crates/zed/src/languages/csharp/outline.scm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/zed/src/languages/csharp/outline.scm b/crates/zed/src/languages/csharp/outline.scm index e8d4594076a61c..0eb185011f6635 100644 --- a/crates/zed/src/languages/csharp/outline.scm +++ b/crates/zed/src/languages/csharp/outline.scm @@ -25,8 +25,11 @@ (method_declaration (modifier)? @context (modifier)? @context + type: (predefined_type)? @context + type: (identifier)? @context type: (generic_name)? @context name: (identifier) @name + parameters: (parameter_list) @context ) @item (enum_declaration From 773a725046ea08cf1a0e1e27d3ed5dfb836ec70f Mon Sep 17 00:00:00 2001 From: Fred Minkowski Date: Sun, 28 Jan 2024 16:01:16 -0500 Subject: [PATCH 4/6] Shorten matchers so they fit in modal --- crates/zed/src/languages/csharp/outline.scm | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/crates/zed/src/languages/csharp/outline.scm b/crates/zed/src/languages/csharp/outline.scm index 0eb185011f6635..aed899b37b30cd 100644 --- a/crates/zed/src/languages/csharp/outline.scm +++ b/crates/zed/src/languages/csharp/outline.scm @@ -1,39 +1,28 @@ (class_declaration - (modifier)? @context "class" @context name: (identifier) @name ) @item (constructor_declaration - (modifier)? @context name: (identifier) @name ) @item (property_declaration - (modifier)? @context type: (identifier)? @context type: (predefined_type)? @context name: (identifier) @name ) @item (field_declaration - (modifier)? @context - (modifier)? @context (variable_declaration) @context ) @item (method_declaration - (modifier)? @context - (modifier)? @context - type: (predefined_type)? @context - type: (identifier)? @context - type: (generic_name)? @context name: (identifier) @name parameters: (parameter_list) @context ) @item (enum_declaration - (modifier)? @context "enum" @context name: (identifier) @name ) @item @@ -44,7 +33,6 @@ ) @item (interface_declaration - (modifier)? @context "interface" @context name: (identifier) @name ) @item From 53df8ed8163bc4c9acc92c0a033b2413fe5201fa Mon Sep 17 00:00:00 2001 From: Fred Minkowski Date: Mon, 29 Jan 2024 13:39:49 -0500 Subject: [PATCH 5/6] Remove folds.scm --- crates/zed/src/languages/csharp/folds.scm | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 crates/zed/src/languages/csharp/folds.scm diff --git a/crates/zed/src/languages/csharp/folds.scm b/crates/zed/src/languages/csharp/folds.scm deleted file mode 100644 index 640242c6767460..00000000000000 --- a/crates/zed/src/languages/csharp/folds.scm +++ /dev/null @@ -1,12 +0,0 @@ -body: - [ - (declaration_list) - (switch_body) - (enum_member_declaration_list) - ] @fold - -accessors: (accessor_list) @fold - -initializer: (initializer_expression) @fold - -(block) @fold From 7ed7f807d62658daa62df93c22e5887f4200cb6b Mon Sep 17 00:00:00 2001 From: Fred Minkowski Date: Mon, 29 Jan 2024 16:15:39 -0500 Subject: [PATCH 6/6] Add C# doc --- docs/src/languages/csharp.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs/src/languages/csharp.md diff --git a/docs/src/languages/csharp.md b/docs/src/languages/csharp.md new file mode 100644 index 00000000000000..1de49c503c9656 --- /dev/null +++ b/docs/src/languages/csharp.md @@ -0,0 +1,4 @@ +# C# + +- Tree Sitter: [tree-sitter-c-sharp](https://github.com/tree-sitter/tree-sitter-c-sharp) +- Language Server: [OmniSharp](https://github.com/OmniSharp/omnisharp-roslyn)