diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index df7a6c7eba..88e0717ebf 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1910,15 +1910,10 @@ impl Editor { selection.start.saturating_sub(pair.start.len()), &pair.start, ) { - // Autoclose only if the next character is a whitespace or a pair end - // (possibly a different one from the pair we are inserting). snapshot .chars_at(selection.start) .next() - .map_or(true, |ch| ch.is_whitespace()) - || language.brackets().iter().any(|pair| { - snapshot.contains_str_at(selection.start, &pair.end) - }) + .map_or(true, |c| language.should_autoclose_before(c)) } else { false } @@ -8125,6 +8120,7 @@ mod tests { newline: true, }, ], + autoclose_before: "})]".to_string(), ..Default::default() }, Some(tree_sitter_rust::language()), @@ -8152,6 +8148,7 @@ mod tests { ], cx, ); + view.handle_input(&Input("{".to_string()), cx); view.handle_input(&Input("{".to_string()), cx); view.handle_input(&Input("{".to_string()), cx); @@ -8215,6 +8212,8 @@ mod tests { .unindent() ); + // Don't autoclose if the next character isn't whitespace and isn't + // listed in the language's "autoclose_before" section. view.finalize_last_transaction(cx); view.select_display_ranges(&[DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], cx); view.handle_input(&Input("{".to_string()), cx); diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index f2e4fd1aa1..3fbc00c72d 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -49,6 +49,7 @@ lazy_static! { name: "Plain Text".into(), path_suffixes: Default::default(), brackets: Default::default(), + autoclose_before: Default::default(), line_comment: None, language_server: None, }, @@ -109,6 +110,8 @@ pub struct LanguageConfig { pub name: Arc, pub path_suffixes: Vec, pub brackets: Vec, + #[serde(default)] + pub autoclose_before: String, pub line_comment: Option, pub language_server: Option, } @@ -119,6 +122,7 @@ impl Default for LanguageConfig { name: "".into(), path_suffixes: Default::default(), brackets: Default::default(), + autoclose_before: Default::default(), line_comment: Default::default(), language_server: Default::default(), } @@ -529,6 +533,10 @@ impl Language { &self.config.brackets } + pub fn should_autoclose_before(&self, c: char) -> bool { + c.is_whitespace() || self.config.autoclose_before.contains(c) + } + pub fn set_theme(&self, theme: &SyntaxTheme) { if let Some(grammar) = self.grammar.as_ref() { *grammar.highlight_map.lock() = diff --git a/crates/zed/languages/c/config.toml b/crates/zed/languages/c/config.toml index 5f85f49475..aeee919ac6 100644 --- a/crates/zed/languages/c/config.toml +++ b/crates/zed/languages/c/config.toml @@ -1,6 +1,7 @@ name = "C" path_suffixes = ["c", "h"] line_comment = "// " +autoclose_before = ";:.,=}])>" brackets = [ { start = "{", end = "}", close = true, newline = true }, { start = "[", end = "]", close = true, newline = true }, diff --git a/crates/zed/languages/json/config.toml b/crates/zed/languages/json/config.toml index 70201e6877..27d1193b0d 100644 --- a/crates/zed/languages/json/config.toml +++ b/crates/zed/languages/json/config.toml @@ -1,5 +1,6 @@ name = "JSON" path_suffixes = ["json"] +autoclose_before = ",]}" brackets = [ { start = "{", end = "}", close = true, newline = true }, { start = "[", end = "]", close = true, newline = true }, diff --git a/crates/zed/languages/rust/config.toml b/crates/zed/languages/rust/config.toml index e4bf50a929..97fe231e0f 100644 --- a/crates/zed/languages/rust/config.toml +++ b/crates/zed/languages/rust/config.toml @@ -1,6 +1,7 @@ name = "Rust" path_suffixes = ["rs"] line_comment = "// " +autoclose_before = ";:.,=}])>" brackets = [ { start = "{", end = "}", close = true, newline = true }, { start = "[", end = "]", close = true, newline = true },