Merge pull request #2055 from zed-industries/language-config-overrides

Max Brunsfeld created

Language config overrides

Change summary

crates/editor/src/editor.rs                       |   9 
crates/editor/src/multi_buffer.rs                 |  11 +
crates/language/src/buffer.rs                     |  23 ++
crates/language/src/buffer_tests.rs               |  83 +++++++++++
crates/language/src/language.rs                   | 128 +++++++++++++++-
crates/language/src/syntax_map.rs                 |  35 ++++
crates/zed/src/languages.rs                       |   8 +
crates/zed/src/languages/c/config.toml            |  15 +
crates/zed/src/languages/c/overrides.scm          |   2 
crates/zed/src/languages/cpp/config.toml          |  15 +
crates/zed/src/languages/cpp/overrides.scm        |   2 
crates/zed/src/languages/css/config.toml          |  17 ++
crates/zed/src/languages/css/overrides.scm        |   2 
crates/zed/src/languages/elixir/config.toml       |  17 ++
crates/zed/src/languages/elixir/overrides.scm     |   2 
crates/zed/src/languages/erb/config.toml          |   3 
crates/zed/src/languages/go/config.toml           |  15 +
crates/zed/src/languages/go/overrides.scm         |   6 
crates/zed/src/languages/html/config.toml         |  16 +
crates/zed/src/languages/html/overrides.scm       |   2 
crates/zed/src/languages/javascript/config.toml   |  18 ++
crates/zed/src/languages/javascript/contexts.scm  |   0 
crates/zed/src/languages/javascript/overrides.scm |   9 +
crates/zed/src/languages/json/config.toml         |   6 
crates/zed/src/languages/json/overrides.scm       |   1 
crates/zed/src/languages/python/config.toml       |  16 +
crates/zed/src/languages/python/overrides.scm     |   2 
crates/zed/src/languages/ruby/config.toml         |  18 ++
crates/zed/src/languages/ruby/overrides.scm       |   2 
crates/zed/src/languages/rust/config.toml         |  16 ++
crates/zed/src/languages/rust/overrides.scm       |   8 +
crates/zed/src/languages/scheme/config.toml       |  12 +
crates/zed/src/languages/scheme/overrides.scm     |   6 
crates/zed/src/languages/toml/config.toml         |  13 +
crates/zed/src/languages/toml/overrides.scm       |   2 
crates/zed/src/languages/tsx/config.toml          |   9 +
crates/zed/src/languages/tsx/overrides.scm        |   7 
crates/zed/src/languages/typescript/config.toml   |  14 +
crates/zed/src/languages/typescript/overrides.scm |   2 
39 files changed, 542 insertions(+), 30 deletions(-)

Detailed changes

crates/editor/src/editor.rs 🔗

@@ -1737,7 +1737,7 @@ impl Editor {
         for (selection, autoclose_region) in
             self.selections_with_autoclose_regions(selections, &snapshot)
         {
-            if let Some(language) = snapshot.language_at(selection.head()) {
+            if let Some(language) = snapshot.language_scope_at(selection.head()) {
                 // Determine if the inserted text matches the opening or closing
                 // bracket of any of this language's bracket pairs.
                 let mut bracket_pair = None;
@@ -1898,7 +1898,7 @@ impl Editor {
                         let end = selection.end;
 
                         let mut insert_extra_newline = false;
-                        if let Some(language) = buffer.language_at(start) {
+                        if let Some(language) = buffer.language_scope_at(start) {
                             let leading_whitespace_len = buffer
                                 .reversed_chars_at(start)
                                 .take_while(|c| c.is_whitespace() && *c != '\n')
@@ -4533,7 +4533,10 @@ impl Editor {
 
             // TODO: Handle selections that cross excerpts
             for selection in &mut selections {
-                let language = if let Some(language) = snapshot.language_at(selection.start) {
+                let start_column = snapshot.indent_size_for_line(selection.start.row).len;
+                let language = if let Some(language) =
+                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
+                {
                     language
                 } else {
                     continue;

crates/editor/src/multi_buffer.rs 🔗

@@ -10,9 +10,9 @@ use gpui::{AppContext, Entity, ModelContext, ModelHandle, Task};
 pub use language::Completion;
 use language::{
     char_kind, AutoindentMode, Buffer, BufferChunks, BufferSnapshot, CharKind, Chunk, CursorShape,
-    DiagnosticEntry, IndentSize, Language, OffsetRangeExt, OffsetUtf16, Outline, OutlineItem,
-    Point, PointUtf16, Selection, TextDimension, ToOffset as _, ToOffsetUtf16 as _, ToPoint as _,
-    ToPointUtf16 as _, TransactionId, Unclipped,
+    DiagnosticEntry, IndentSize, Language, LanguageScope, OffsetRangeExt, OffsetUtf16, Outline,
+    OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _, ToOffsetUtf16 as _,
+    ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped,
 };
 use std::{
     borrow::Cow,
@@ -2691,6 +2691,11 @@ impl MultiBufferSnapshot {
             .and_then(|(buffer, offset)| buffer.language_at(offset))
     }
 
+    pub fn language_scope_at<'a, T: ToOffset>(&'a self, point: T) -> Option<LanguageScope> {
+        self.point_to_buffer_offset(point)
+            .and_then(|(buffer, offset)| buffer.language_scope_at(offset))
+    }
+
     pub fn is_dirty(&self) -> bool {
         self.is_dirty
     }

crates/language/src/buffer.rs 🔗

@@ -9,7 +9,7 @@ use crate::{
     syntax_map::{
         SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxSnapshot, ToTreeSitterPoint,
     },
-    CodeLabel, Outline,
+    CodeLabel, LanguageScope, Outline,
 };
 use anyhow::{anyhow, Result};
 use clock::ReplicaId;
@@ -2015,6 +2015,27 @@ impl BufferSnapshot {
             .or(self.language.as_ref())
     }
 
+    pub fn language_scope_at<D: ToOffset>(&self, position: D) -> Option<LanguageScope> {
+        let offset = position.to_offset(self);
+
+        if let Some(layer_info) = self
+            .syntax
+            .layers_for_range(offset..offset, &self.text)
+            .filter(|l| l.node.end_byte() > offset)
+            .last()
+        {
+            Some(LanguageScope {
+                language: layer_info.language.clone(),
+                override_id: layer_info.override_id(offset, &self.text),
+            })
+        } else {
+            self.language.clone().map(|language| LanguageScope {
+                language,
+                override_id: None,
+            })
+        }
+    }
+
     pub fn surrounding_word<T: ToOffset>(&self, start: T) -> (Range<usize>, Option<CharKind>) {
         let mut start = start.to_offset(self);
         let mut end = start;

crates/language/src/buffer_tests.rs 🔗

@@ -1369,6 +1369,89 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut MutableAppContext) {
     });
 }
 
+#[gpui::test]
+fn test_language_config_at(cx: &mut MutableAppContext) {
+    cx.set_global(Settings::test(cx));
+    cx.add_model(|cx| {
+        let language = Language::new(
+            LanguageConfig {
+                name: "JavaScript".into(),
+                line_comment: Some("// ".into()),
+                brackets: vec![
+                    BracketPair {
+                        start: "{".into(),
+                        end: "}".into(),
+                        close: true,
+                        newline: false,
+                    },
+                    BracketPair {
+                        start: "'".into(),
+                        end: "'".into(),
+                        close: true,
+                        newline: false,
+                    },
+                ],
+                overrides: [
+                    (
+                        "element".into(),
+                        LanguageConfigOverride {
+                            line_comment: Override::Remove { remove: true },
+                            block_comment: Override::Set(("{/*".into(), "*/}".into())),
+                            ..Default::default()
+                        },
+                    ),
+                    (
+                        "string".into(),
+                        LanguageConfigOverride {
+                            brackets: Override::Set(vec![BracketPair {
+                                start: "{".into(),
+                                end: "}".into(),
+                                close: true,
+                                newline: false,
+                            }]),
+                            ..Default::default()
+                        },
+                    ),
+                ]
+                .into_iter()
+                .collect(),
+                ..Default::default()
+            },
+            Some(tree_sitter_javascript::language()),
+        )
+        .with_override_query(
+            r#"
+                (jsx_element) @element
+                (string) @string
+            "#,
+        )
+        .unwrap();
+
+        let text = r#"a["b"] = <C d="e"></C>;"#;
+
+        let buffer = Buffer::new(0, text, cx).with_language(Arc::new(language), cx);
+        let snapshot = buffer.snapshot();
+
+        let config = snapshot.language_scope_at(0).unwrap();
+        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
+        assert_eq!(config.brackets().len(), 2);
+
+        let string_config = snapshot.language_scope_at(3).unwrap();
+        assert_eq!(config.line_comment_prefix().unwrap().as_ref(), "// ");
+        assert_eq!(string_config.brackets().len(), 1);
+
+        let element_config = snapshot.language_scope_at(10).unwrap();
+        assert_eq!(element_config.line_comment_prefix(), None);
+        assert_eq!(
+            element_config.block_comment_delimiters(),
+            Some((&"{/*".into(), &"*/}".into()))
+        );
+        assert_eq!(element_config.brackets().len(), 2);
+
+        buffer
+    });
+}
+
 #[gpui::test]
 fn test_serialization(cx: &mut gpui::MutableAppContext) {
     let mut now = Instant::now();

crates/language/src/language.rs 🔗

@@ -243,6 +243,47 @@ pub struct LanguageConfig {
     pub line_comment: Option<Arc<str>>,
     #[serde(default)]
     pub block_comment: Option<(Arc<str>, Arc<str>)>,
+    #[serde(default)]
+    pub overrides: HashMap<String, LanguageConfigOverride>,
+}
+
+#[derive(Clone)]
+pub struct LanguageScope {
+    language: Arc<Language>,
+    override_id: Option<u32>,
+}
+
+#[derive(Deserialize, Default, Debug)]
+pub struct LanguageConfigOverride {
+    #[serde(default)]
+    pub line_comment: Override<Arc<str>>,
+    #[serde(default)]
+    pub block_comment: Override<(Arc<str>, Arc<str>)>,
+    #[serde(default)]
+    pub brackets: Override<Vec<BracketPair>>,
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(untagged)]
+pub enum Override<T> {
+    Remove { remove: bool },
+    Set(T),
+}
+
+impl<T> Default for Override<T> {
+    fn default() -> Self {
+        Override::Remove { remove: false }
+    }
+}
+
+impl<T> Override<T> {
+    fn as_option<'a>(this: Option<&'a Self>, original: Option<&'a T>) -> Option<&'a T> {
+        match this {
+            Some(Self::Set(value)) => Some(value),
+            Some(Self::Remove { remove: true }) => None,
+            Some(Self::Remove { remove: false }) | None => original,
+        }
+    }
 }
 
 impl Default for LanguageConfig {
@@ -257,6 +298,7 @@ impl Default for LanguageConfig {
             autoclose_before: Default::default(),
             line_comment: Default::default(),
             block_comment: Default::default(),
+            overrides: Default::default(),
         }
     }
 }
@@ -311,6 +353,7 @@ pub struct Grammar {
     pub(crate) indents_config: Option<IndentConfig>,
     pub(crate) outline_config: Option<OutlineConfig>,
     pub(crate) injection_config: Option<InjectionConfig>,
+    pub(crate) override_config: Option<OverrideConfig>,
     pub(crate) highlight_map: Mutex<HighlightMap>,
 }
 
@@ -336,6 +379,11 @@ struct InjectionConfig {
     patterns: Vec<InjectionPatternConfig>,
 }
 
+struct OverrideConfig {
+    query: Query,
+    values: HashMap<u32, LanguageConfigOverride>,
+}
+
 #[derive(Default, Clone)]
 struct InjectionPatternConfig {
     language: Option<Box<str>>,
@@ -635,6 +683,7 @@ impl Language {
                     outline_config: None,
                     indents_config: None,
                     injection_config: None,
+                    override_config: None,
                     ts_language,
                     highlight_map: Default::default(),
                 })
@@ -775,6 +824,34 @@ impl Language {
         Ok(self)
     }
 
+    pub fn with_override_query(mut self, source: &str) -> Result<Self> {
+        let query = Query::new(self.grammar_mut().ts_language, source)?;
+
+        let mut values = HashMap::default();
+        for (ix, name) in query.capture_names().iter().enumerate() {
+            if !name.starts_with('_') {
+                let value = self.config.overrides.remove(name).ok_or_else(|| {
+                    anyhow!(
+                        "language {:?} has override in query but not in config: {name:?}",
+                        self.config.name
+                    )
+                })?;
+                values.insert(ix as u32, value);
+            }
+        }
+
+        if !self.config.overrides.is_empty() {
+            let keys = self.config.overrides.keys().collect::<Vec<_>>();
+            Err(anyhow!(
+                "language {:?} has overrides in config not in query: {keys:?}",
+                self.config.name
+            ))?;
+        }
+
+        self.grammar_mut().override_config = Some(OverrideConfig { query, values });
+        Ok(self)
+    }
+
     fn grammar_mut(&mut self) -> &mut Grammar {
         Arc::get_mut(self.grammar.as_mut().unwrap()).unwrap()
     }
@@ -800,17 +877,6 @@ impl Language {
         self.config.name.clone()
     }
 
-    pub fn line_comment_prefix(&self) -> Option<&Arc<str>> {
-        self.config.line_comment.as_ref()
-    }
-
-    pub fn block_comment_delimiters(&self) -> Option<(&Arc<str>, &Arc<str>)> {
-        self.config
-            .block_comment
-            .as_ref()
-            .map(|(start, end)| (start, end))
-    }
-
     pub async fn disk_based_diagnostic_sources(&self) -> &[String] {
         match self.adapter.as_ref() {
             Some(adapter) => &adapter.disk_based_diagnostic_sources,
@@ -886,10 +952,6 @@ impl Language {
         result
     }
 
-    pub fn brackets(&self) -> &[BracketPair] {
-        &self.config.brackets
-    }
-
     pub fn path_suffixes(&self) -> &[String] {
         &self.config.path_suffixes
     }
@@ -912,6 +974,42 @@ impl Language {
     }
 }
 
+impl LanguageScope {
+    pub fn line_comment_prefix(&self) -> Option<&Arc<str>> {
+        Override::as_option(
+            self.config_override().map(|o| &o.line_comment),
+            self.language.config.line_comment.as_ref(),
+        )
+    }
+
+    pub fn block_comment_delimiters(&self) -> Option<(&Arc<str>, &Arc<str>)> {
+        Override::as_option(
+            self.config_override().map(|o| &o.block_comment),
+            self.language.config.block_comment.as_ref(),
+        )
+        .map(|e| (&e.0, &e.1))
+    }
+
+    pub fn brackets(&self) -> &[BracketPair] {
+        Override::as_option(
+            self.config_override().map(|o| &o.brackets),
+            Some(&self.language.config.brackets),
+        )
+        .map_or(&[], Vec::as_slice)
+    }
+
+    pub fn should_autoclose_before(&self, c: char) -> bool {
+        c.is_whitespace() || self.language.config.autoclose_before.contains(c)
+    }
+
+    fn config_override(&self) -> Option<&LanguageConfigOverride> {
+        let id = self.override_id?;
+        let grammar = self.language.grammar.as_ref()?;
+        let override_config = grammar.override_config.as_ref()?;
+        override_config.values.get(&id)
+    }
+}
+
 impl Hash for Language {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         self.id().hash(state)

crates/language/src/syntax_map.rs 🔗

@@ -1127,6 +1127,41 @@ fn splice_included_ranges(
     ranges
 }
 
+impl<'a> SyntaxLayerInfo<'a> {
+    pub(crate) fn override_id(&self, offset: usize, text: &text::BufferSnapshot) -> Option<u32> {
+        let text = TextProvider(text.as_rope());
+        let config = self.language.grammar.as_ref()?.override_config.as_ref()?;
+
+        let mut query_cursor = QueryCursorHandle::new();
+        query_cursor.set_byte_range(offset..offset);
+
+        let mut smallest_match: Option<(u32, Range<usize>)> = None;
+        for mat in query_cursor.matches(&config.query, self.node, text) {
+            for capture in mat.captures {
+                if !config.values.contains_key(&capture.index) {
+                    continue;
+                }
+
+                let range = capture.node.byte_range();
+                if offset <= range.start || offset >= range.end {
+                    continue;
+                }
+
+                if let Some((_, smallest_range)) = &smallest_match {
+                    if range.len() < smallest_range.len() {
+                        smallest_match = Some((capture.index, range))
+                    }
+                    continue;
+                }
+
+                smallest_match = Some((capture.index, range));
+            }
+        }
+
+        smallest_match.map(|(index, _)| index)
+    }
+}
+
 impl std::ops::Deref for SyntaxMap {
     type Target = SyntaxSnapshot;
 

crates/zed/src/languages.rs 🔗

@@ -1,3 +1,4 @@
+use anyhow::Context;
 use gpui::executor::Background;
 pub use language::*;
 use lazy_static::lazy_static;
@@ -145,7 +146,9 @@ pub(crate) fn language(
             .unwrap()
             .data,
     )
+    .with_context(|| format!("failed to load config.toml for language {name:?}"))
     .unwrap();
+
     let mut language = Language::new(config, Some(grammar));
 
     if let Some(query) = load_query(name, "/highlights") {
@@ -173,6 +176,11 @@ pub(crate) fn language(
             .with_injection_query(query.as_ref())
             .expect("failed to load injection query");
     }
+    if let Some(query) = load_query(name, "/overrides") {
+        language = language
+            .with_override_query(query.as_ref())
+            .expect("failed to load override query");
+    }
     if let Some(lsp_adapter) = lsp_adapter {
         language = language.with_lsp_adapter(lsp_adapter)
     }

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

@@ -7,5 +7,20 @@ brackets = [
     { start = "[", end = "]", close = true, newline = true },
     { start = "(", end = ")", close = true, newline = true },
     { start = "\"", end = "\"", close = true, newline = false },
+    { start = "'", end = "'", close = true, newline = false },
     { start = "/*", end = " */", close = true, newline = false },
 ]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]

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

@@ -7,5 +7,20 @@ brackets = [
     { start = "[", end = "]", close = true, newline = true },
     { start = "(", end = ")", close = true, newline = true },
     { start = "\"", end = "\"", close = true, newline = false },
+    { start = "'", end = "'", close = true, newline = false },
     { start = "/*", end = " */", close = true, newline = false },
 ]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]

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

@@ -5,5 +5,20 @@ 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 },
+    { start = "'", end = "'", close = true, newline = false },
+]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
 ]

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

@@ -6,5 +6,20 @@ 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 },
+    { start = "'", end = "'", close = true, newline = false },
+]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
 ]

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

@@ -4,5 +4,4 @@ autoclose_before = ">})"
 brackets = [
     { start = "<", end = ">", close = true, newline = true },
 ]
-
-block_comment = ["<%#", "%>"]
+block_comment = ["<%#", "%>"]

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

@@ -7,5 +7,20 @@ brackets = [
     { start = "[", end = "]", close = true, newline = true },
     { start = "(", end = ")", close = true, newline = true },
     { start = "\"", end = "\"", close = true, newline = false },
+    { start = "'", end = "'", close = true, newline = false },
     { start = "/*", end = " */", close = true, newline = false },
 ]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]

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

@@ -9,4 +9,18 @@ brackets = [
     { start = "!--", end = " --", close = true, newline = false },
 ]
 
-block_comment = ["<!-- ", " -->"]
+block_comment = ["<!-- ", " -->"]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]

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

@@ -12,3 +12,21 @@ brackets = [
     { start = "`", end = "`", close = true, newline = false },
     { start = "/*", end = " */", close = true, newline = false },
 ]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.element]
+line_comment = { remove = true }
+block_comment = ["{/* ", " */}"]

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

@@ -7,3 +7,9 @@ brackets = [
     { start = "[", end = "]", close = true, newline = true },
     { start = "\"", end = "\"", close = true, newline = false },
 ]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+]

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

@@ -12,4 +12,18 @@ brackets = [
 
 auto_indent_using_last_non_empty_line = false
 increase_indent_pattern = ":$"
-decrease_indent_pattern = "^\\s*(else|elif|except|finally)\\b.*:"
+decrease_indent_pattern = "^\\s*(else|elif|except|finally)\\b.*:"
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]

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

@@ -7,5 +7,19 @@ brackets = [
   { start = "[", end = "]", close = true, newline = true },
   { start = "(", end = ")", close = true, newline = true },
   { start = "\"", end = "\"", close = true, newline = false },
-  { start = "'", end = "'", close = false, newline = false },
-]
+  { start = "'", end = "'", close = true, newline = false },
+]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]

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

@@ -11,3 +11,19 @@ brackets = [
     { start = "'", end = "'", close = false, newline = false },
     { start = "/*", end = " */", close = true, newline = false },
 ]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+    { start = "<", end = ">", close = false, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+    { start = "<", end = ">", close = false, newline = true },
+]

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

@@ -7,3 +7,15 @@ brackets = [
     { start = "(", end = ")", close = true, newline = false },
     { start = "\"", end = "\"", close = true, newline = false },
 ]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+]

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

@@ -6,4 +6,17 @@ brackets = [
     { start = "{", end = "}", close = true, newline = true },
     { start = "[", end = "]", close = true, newline = true },
     { start = "\"", end = "\"", close = true, newline = false },
+    { start = "'", end = "'", close = true, newline = false },
+]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
 ]

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

@@ -12,3 +12,12 @@ brackets = [
     { start = "`", end = "`", close = true, newline = false },
     { start = "/*", end = " */", close = true, newline = false },
 ]
+
+[overrides.element]
+line_comment = { remove = true }
+block_comment = ["{/* ", " */}"]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+]

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

@@ -12,3 +12,17 @@ brackets = [
     { start = "`", end = "`", close = true, newline = false },
     { start = "/*", end = " */", close = true, newline = false },
 ]
+
+[overrides.comment]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]
+
+[overrides.string]
+brackets = [
+    { start = "{", end = "}", close = true, newline = true },
+    { start = "[", end = "]", close = true, newline = true },
+    { start = "(", end = ")", close = true, newline = true },
+]