Start work on ERB language support

Max Brunsfeld created

Change summary

Cargo.lock                                  | 11 ++++++++
crates/language/src/language.rs             | 30 ++++++++++++++++------
crates/language/src/syntax_map.rs           |  2 
crates/zed/Cargo.toml                       |  1 
crates/zed/src/languages.rs                 |  1 
crates/zed/src/languages/erb/config.toml    |  8 ++++++
crates/zed/src/languages/erb/injections.scm |  7 +++++
7 files changed, 50 insertions(+), 10 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -6426,6 +6426,16 @@ dependencies = [
  "tree-sitter",
 ]
 
+[[package]]
+name = "tree-sitter-embedded-template"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33817ade928c73a32d4f904a602321e09de9fc24b71d106f3b4b3f8ab30dcc38"
+dependencies = [
+ "cc",
+ "tree-sitter",
+]
+
 [[package]]
 name = "tree-sitter-go"
 version = "0.19.1"
@@ -7719,6 +7729,7 @@ dependencies = [
  "tree-sitter-cpp",
  "tree-sitter-css",
  "tree-sitter-elixir",
+ "tree-sitter-embedded-template",
  "tree-sitter-go",
  "tree-sitter-html",
  "tree-sitter-json 0.20.0",

crates/language/src/language.rs 🔗

@@ -326,7 +326,13 @@ struct InjectionConfig {
     query: Query,
     content_capture_ix: u32,
     language_capture_ix: Option<u32>,
-    languages_by_pattern_ix: Vec<Option<Box<str>>>,
+    patterns: Vec<InjectionPatternConfig>,
+}
+
+#[derive(Default, Clone)]
+struct InjectionPatternConfig {
+    language: Option<Box<str>>,
+    combined: bool,
 }
 
 struct BracketConfig {
@@ -730,15 +736,21 @@ impl Language {
                 ("content", &mut content_capture_ix),
             ],
         );
-        let languages_by_pattern_ix = (0..query.pattern_count())
+        let patterns = (0..query.pattern_count())
             .map(|ix| {
-                query.property_settings(ix).iter().find_map(|setting| {
-                    if setting.key.as_ref() == "language" {
-                        return setting.value.clone();
-                    } else {
-                        None
+                let mut config = InjectionPatternConfig::default();
+                for setting in query.property_settings(ix) {
+                    match setting.key.as_ref() {
+                        "language" => {
+                            config.language = setting.value.clone();
+                        }
+                        "combined" => {
+                            config.combined = true;
+                        }
+                        _ => {}
                     }
-                })
+                }
+                config
             })
             .collect();
         if let Some(content_capture_ix) = content_capture_ix {
@@ -746,7 +758,7 @@ impl Language {
                 query,
                 language_capture_ix,
                 content_capture_ix,
-                languages_by_pattern_ix,
+                patterns,
             });
         }
         Ok(self)

crates/language/src/syntax_map.rs 🔗

@@ -961,7 +961,7 @@ fn get_injections(
             }
             prev_match = Some((mat.pattern_index, content_range.clone()));
 
-            let language_name = config.languages_by_pattern_ix[mat.pattern_index]
+            let language_name = config.patterns[mat.pattern_index].language
                 .as_ref()
                 .map(|s| Cow::Borrowed(s.as_ref()))
                 .or_else(|| {

crates/zed/Cargo.toml 🔗

@@ -95,6 +95,7 @@ tree-sitter-c = "0.20.1"
 tree-sitter-cpp = "0.20.0"
 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 = "05e3631c6a0701c1fa518b0fee7be95a2ceef5e2" }
+tree-sitter-embedded-template = "0.20.0"
 tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "aeb2f33b366fd78d5789ff104956ce23508b85db" }
 tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "137e1ce6a02698fc246cdb9c6b886ed1de9a1ed8" }
 tree-sitter-rust = "0.20.3"

crates/zed/src/languages.rs 🔗

@@ -117,6 +117,7 @@ pub async fn init(languages: Arc<LanguageRegistry>, _executor: Arc<Background>)
             Some(CachedLspAdapter::new(html::HtmlLspAdapter).await),
         ),
         ("ruby", tree_sitter_ruby::language(), None),
+        ("erb", tree_sitter_embedded_template::language(), None),
     ] {
         languages.add(language(name, grammar, lsp_adapter));
     }

crates/zed/src/languages/erb/config.toml 🔗

@@ -0,0 +1,8 @@
+name = "ERB"
+path_suffixes = ["erb"]
+autoclose_before = ">})"
+brackets = [
+    { start = "<", end = ">", close = true, newline = true },
+]
+
+block_comment = ["<%#", "%>"]