From f4bafd58992c8318dc0edd446f0d9ba3120c7a7c Mon Sep 17 00:00:00 2001 From: Abdullah Alsigar Date: Mon, 19 Feb 2024 22:10:08 +0300 Subject: [PATCH] Dart support (#7220) This is my first contribution, feedback is welcome. Release Notes: - Added Dart language support ([#5343](https://github.com/zed-industries/zed/issues/5343)). --- Cargo.lock | 10 + Cargo.toml | 1 + crates/zed/Cargo.toml | 1 + crates/zed/src/languages.rs | 3 + crates/zed/src/languages/dart.rs | 53 +++++ crates/zed/src/languages/dart/brackets.scm | 6 + crates/zed/src/languages/dart/config.toml | 13 ++ crates/zed/src/languages/dart/highlights.scm | 209 +++++++++++++++++++ crates/zed/src/languages/dart/indents.scm | 7 + crates/zed/src/languages/dart/outline.scm | 18 ++ 10 files changed, 321 insertions(+) create mode 100644 crates/zed/src/languages/dart.rs create mode 100644 crates/zed/src/languages/dart/brackets.scm create mode 100644 crates/zed/src/languages/dart/config.toml create mode 100644 crates/zed/src/languages/dart/highlights.scm create mode 100644 crates/zed/src/languages/dart/indents.scm create mode 100644 crates/zed/src/languages/dart/outline.scm diff --git a/Cargo.lock b/Cargo.lock index 943f033079..7bd1471cbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10136,6 +10136,15 @@ dependencies = [ "tree-sitter", ] +[[package]] +name = "tree-sitter-dart" +version = "0.0.1" +source = "git+https://github.com/agent3bood/tree-sitter-dart?rev=48934e3bf757a9b78f17bdfaa3e2b4284656fdc7#48934e3bf757a9b78f17bdfaa3e2b4284656fdc7" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-dockerfile" version = "0.1.0" @@ -12011,6 +12020,7 @@ dependencies = [ "tree-sitter-clojure", "tree-sitter-cpp", "tree-sitter-css", + "tree-sitter-dart", "tree-sitter-dockerfile", "tree-sitter-elixir", "tree-sitter-elm", diff --git a/Cargo.toml b/Cargo.toml index bfb2df80e3..b0fab89002 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -236,6 +236,7 @@ tree-sitter-c-sharp = { git = "https://github.com/tree-sitter/tree-sitter-c-shar tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "f44509141e7e483323d2ec178f2d2e6c0fc041c1" } tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" } tree-sitter-dockerfile = { git = "https://github.com/camdencheek/tree-sitter-dockerfile", rev = "33e22c33bcdbfc33d42806ee84cfd0b1248cc392" } +tree-sitter-dart = { git = "https://github.com/agent3bood/tree-sitter-dart", rev = "48934e3bf757a9b78f17bdfaa3e2b4284656fdc7" } 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" } tree-sitter-embedded-template = "0.20.0" diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index a0bbf53fde..a79ed09782 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -119,6 +119,7 @@ tree-sitter-clojure.workspace = true tree-sitter-cpp.workspace = true tree-sitter-css.workspace = true tree-sitter-dockerfile.workspace = true +tree-sitter-dart.workspace = true tree-sitter-elixir.workspace = true tree-sitter-elm.workspace = true tree-sitter-embedded-template.workspace = true diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index aa3f2166c7..7ae8ca7c40 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -14,6 +14,7 @@ mod c; mod clojure; mod csharp; mod css; +mod dart; mod deno; mod dockerfile; mod elixir; @@ -120,6 +121,7 @@ pub fn init( ("vue", tree_sitter_vue::language()), ("yaml", tree_sitter_yaml::language()), ("zig", tree_sitter_zig::language()), + ("dart", tree_sitter_dart::language()), ]); let language = |asset_dir_name: &'static str, adapters| { @@ -326,6 +328,7 @@ pub fn init( node_runtime.clone(), ))], ); + language("dart", vec![Arc::new(dart::DartLanguageServer {})]); } #[cfg(any(test, feature = "test-support"))] diff --git a/crates/zed/src/languages/dart.rs b/crates/zed/src/languages/dart.rs new file mode 100644 index 0000000000..ba340fc876 --- /dev/null +++ b/crates/zed/src/languages/dart.rs @@ -0,0 +1,53 @@ +use anyhow::{anyhow, Result}; +use async_trait::async_trait; +use language::{LanguageServerName, LspAdapter, LspAdapterDelegate}; +use lsp::LanguageServerBinary; +use std::{any::Any, path::PathBuf}; + +pub struct DartLanguageServer; + +#[async_trait] +impl LspAdapter for DartLanguageServer { + fn name(&self) -> LanguageServerName { + LanguageServerName("dart".into()) + } + + fn short_name(&self) -> &'static str { + "dart" + } + + async fn fetch_latest_server_version( + &self, + _: &dyn LspAdapterDelegate, + ) -> Result> { + Ok(Box::new(())) + } + + async fn fetch_server_binary( + &self, + _: Box, + _: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Result { + Err(anyhow!("dart must me installed from dart.dev/get-dart")) + } + + async fn cached_server_binary( + &self, + _: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { + Some(LanguageServerBinary { + path: "dart".into(), + arguments: vec!["language-server".into(), "--protocol=lsp".into()], + }) + } + + fn can_be_reinstalled(&self) -> bool { + false + } + + async fn installation_test_binary(&self, _: PathBuf) -> Option { + None + } +} diff --git a/crates/zed/src/languages/dart/brackets.scm b/crates/zed/src/languages/dart/brackets.scm new file mode 100644 index 0000000000..8d96f95f86 --- /dev/null +++ b/crates/zed/src/languages/dart/brackets.scm @@ -0,0 +1,6 @@ +("(" @open ")" @close) +("[" @open "]" @close) +("{" @open "}" @close) +("<" @open ">" @close) +("\"" @open "\"" @close) +("'" @open "'" @close) diff --git a/crates/zed/src/languages/dart/config.toml b/crates/zed/src/languages/dart/config.toml new file mode 100644 index 0000000000..140e482289 --- /dev/null +++ b/crates/zed/src/languages/dart/config.toml @@ -0,0 +1,13 @@ +name = "Dart" +grammar = "dart" +path_suffixes = ["dart"] +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"] }, + { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] }, +] diff --git a/crates/zed/src/languages/dart/highlights.scm b/crates/zed/src/languages/dart/highlights.scm new file mode 100644 index 0000000000..270b40ec2d --- /dev/null +++ b/crates/zed/src/languages/dart/highlights.scm @@ -0,0 +1,209 @@ +(dotted_identifier_list) @string + +; Methods +; -------------------- +(function_type + name: (identifier) @function) +(super) @function + +; Annotations +; -------------------- +(annotation + name: (identifier) @attribute) + +; Operators and Tokens +; -------------------- +(template_substitution + "$" @punctuation.special + "{" @punctuation.special + "}" @punctuation.special + ) @none + +(template_substitution + "$" @punctuation.special + (identifier_dollar_escaped) @variable + ) @none + +(escape_sequence) @string.escape + +[ + "@" + "=>" + ".." + "??" + "==" + "?" + ":" + "&&" + "%" + "<" + ">" + "=" + ">=" + "<=" + "||" + (increment_operator) + (is_operator) + (prefix_operator) + (equality_operator) + (additive_operator) + ] @operator + +[ + "(" + ")" + "[" + "]" + "{" + "}" + "<" + ">" + ] @punctuation.bracket + +; Delimiters +; -------------------- +[ + ";" + "." + "," + ] @punctuation.delimiter + +; Types +; -------------------- +(class_definition + name: (identifier) @type) +(constructor_signature + name: (identifier) @type) +(scoped_identifier + scope: (identifier) @type) +(function_signature + name: (identifier) @function) +(getter_signature + (identifier) @function) +(setter_signature + name: (identifier) @function) +(enum_declaration + name: (identifier) @type) +(enum_constant + name: (identifier) @type) +(type_identifier) @type +(void_type) @type + +((scoped_identifier + scope: (identifier) @type + name: (identifier) @type) + (#match? @type "^[a-zA-Z]")) + +(type_identifier) @type + +; Variables +; -------------------- +; var keyword +(inferred_type) @keyword + +(const_builtin) @constant.builtin +(final_builtin) @constant.builtin + +((identifier) @type + (#match? @type "^_?[A-Z]")) + +("Function" @type) + +; properties +; TODO: add method/call_expression to grammar and +; distinguish method call from variable access +(unconditional_assignable_selector + (identifier) @property) + +; assignments +(assignment_expression + left: (assignable_expression) @variable) + +(this) @variable.builtin + +; Literals +; -------------------- +[ + (hex_integer_literal) + (decimal_integer_literal) + (decimal_floating_point_literal) + ; TODO: inaccessible nodes + ; (octal_integer_literal) + ; (hex_floating_point_literal) + ] @number + +(symbol_literal) @symbol +(string_literal) @string +(true) @boolean +(false) @boolean +(null_literal) @constant.builtin + +(documentation_comment) @comment +(comment) @comment + +; Keywords +; -------------------- +["import" "library" "export"] @keyword.include + +; Reserved words (cannot be used as identifiers) +; TODO: "rethrow" @keyword +[ + ; "assert" + (case_builtin) + "extension" + "on" + "class" + "enum" + "extends" + "in" + "is" + "new" + "return" + "super" + "with" + ] @keyword + + +; Built in identifiers: +; alone these are marked as keywords +[ + "abstract" + "as" + "async" + "async*" + "yield" + "sync*" + "await" + "covariant" + "deferred" + "dynamic" + "external" + "factory" + "get" + "implements" + "interface" + "library" + "operator" + "mixin" + "part" + "set" + "show" + "static" + "typedef" + ] @keyword + +; when used as an identifier: +((identifier) @variable.builtin + (#vim-match? @variable.builtin "^(abstract|as|covariant|deferred|dynamic|export|external|factory|Function|get|implements|import|interface|library|operator|mixin|part|set|static|typedef)$")) + +["if" "else" "switch" "default"] @keyword + +[ + "try" + "throw" + "catch" + "finally" + (break_statement) + ] @keyword + +["do" "while" "continue" "for"] @keyword diff --git a/crates/zed/src/languages/dart/indents.scm b/crates/zed/src/languages/dart/indents.scm new file mode 100644 index 0000000000..3e8210957c --- /dev/null +++ b/crates/zed/src/languages/dart/indents.scm @@ -0,0 +1,7 @@ +[ + (if_statement) + (for_statement) +] @indent + +(_ "{" "}" @end) @indent +(_ "(" ")" @end) @indent diff --git a/crates/zed/src/languages/dart/outline.scm b/crates/zed/src/languages/dart/outline.scm new file mode 100644 index 0000000000..4d6f8c1cb7 --- /dev/null +++ b/crates/zed/src/languages/dart/outline.scm @@ -0,0 +1,18 @@ +(class_definition + "class" @context + name: (_) @name) @item + +(function_signature + name: (_) @name) @item + +(getter_signature + "get" @context + name: (_) @name) @item + +(setter_signature + "set" @context + name: (_) @name) @item + +(enum_declaration + "enum" @context + name: (_) @name) @item