diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 699b442a5d..769c03d6ff 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6001,6 +6001,10 @@ impl Editor { } impl EditorSnapshot { + pub fn language_at(&self, position: T) -> Option<&Arc> { + self.display_snapshot.buffer_snapshot.language_at(position) + } + pub fn is_focused(&self) -> bool { self.is_focused } @@ -9788,13 +9792,24 @@ mod tests { Language::new( LanguageConfig { name: "HTML".into(), - brackets: vec![BracketPair { - start: "<".to_string(), - end: ">".to_string(), - close: true, - newline: true, - }], - autoclose_before: "})]".to_string(), + brackets: vec![ + BracketPair { + start: "<".into(), + end: ">".into(), + ..Default::default() + }, + BracketPair { + start: "{".into(), + end: "}".into(), + ..Default::default() + }, + BracketPair { + start: "(".into(), + end: ")".into(), + ..Default::default() + }, + ], + autoclose_before: "})]>".into(), ..Default::default() }, Some(tree_sitter_html::language()), @@ -9812,13 +9827,24 @@ mod tests { let javascript_language = Arc::new(Language::new( LanguageConfig { name: "JavaScript".into(), - brackets: vec![BracketPair { - start: "/*".to_string(), - end: "*/".to_string(), - close: true, - newline: true, - }], - autoclose_before: "})]".to_string(), + brackets: vec![ + BracketPair { + start: "/*".into(), + end: " */".into(), + ..Default::default() + }, + BracketPair { + start: "{".into(), + end: "}".into(), + ..Default::default() + }, + BracketPair { + start: "(".into(), + end: ")".into(), + ..Default::default() + }, + ], + autoclose_before: "})]>".into(), ..Default::default() }, Some(tree_sitter_javascript::language()), @@ -9839,31 +9865,145 @@ mod tests { - + ˇ "# .unindent(), ); - let cursors = cx.update_editor(|editor, cx| editor.selections.ranges::(cx)); - cx.update_buffer(|buffer, _| { - let snapshot = buffer.snapshot(); + // Precondition: different languages are active at different locations. + cx.update_editor(|editor, cx| { + let snapshot = editor.snapshot(cx); + let cursors = editor.selections.ranges::(cx); + let languages = cursors + .iter() + .map(|c| snapshot.language_at(c.start).unwrap().name()) + .collect::>(); assert_eq!( - snapshot - .language_at(cursors[0].start) - .unwrap() - .name() - .as_ref(), - "HTML" - ); - assert_eq!( - snapshot - .language_at(cursors[1].start) - .unwrap() - .name() - .as_ref(), - "JavaScript" + languages, + &["HTML".into(), "JavaScript".into(), "HTML".into()] ); }); + + // Angle brackets autoclose in HTML, but not JavaScript. + cx.update_editor(|editor, cx| { + editor.handle_input("<", cx); + editor.handle_input("a", cx); + }); + cx.assert_editor_state( + &r#" + + + + "# + .unindent(), + ); + + // Curly braces and parens autoclose in both HTML and JavaScript. + cx.update_editor(|editor, cx| { + editor.handle_input(" b=", cx); + editor.handle_input("{", cx); + editor.handle_input("c", cx); + editor.handle_input("(", cx); + }); + cx.assert_editor_state( + &r#" + + + + "# + .unindent(), + ); + + // Brackets that were already autoclosed are skipped. + cx.update_editor(|editor, cx| { + editor.handle_input(")", cx); + editor.handle_input("d", cx); + editor.handle_input("}", cx); + }); + cx.assert_editor_state( + &r#" + + + + "# + .unindent(), + ); + cx.update_editor(|editor, cx| { + editor.handle_input(">", cx); + }); + cx.assert_editor_state( + &r#" + ˇ + + ˇ + "# + .unindent(), + ); + + // Reset + cx.set_state( + &r#" + ˇ + + ˇ + "# + .unindent(), + ); + + cx.update_editor(|editor, cx| { + editor.handle_input("<", cx); + }); + cx.assert_editor_state( + &r#" + <ˇ> + + <ˇ> + "# + .unindent(), + ); + + // When backspacing, the closing angle brackets are removed. + cx.update_editor(|editor, cx| { + editor.backspace(&Backspace, cx); + }); + cx.assert_editor_state( + &r#" + ˇ + + ˇ + "# + .unindent(), + ); + + // Block comments autoclose in JavaScript, but not HTML. + cx.update_editor(|editor, cx| { + editor.handle_input("/", cx); + editor.handle_input("*", cx); + }); + cx.assert_editor_state( + &r#" + /*ˇ + + /*ˇ + "# + .unindent(), + ); } #[gpui::test] diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index b8d4ca309f..59da0909c6 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -271,7 +271,7 @@ pub struct FakeLspAdapter { pub disk_based_diagnostics_sources: Vec, } -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Default, Deserialize)] pub struct BracketPair { pub start: String, pub end: String,