From f62d76159bc4a623a921792cc214387039f0b72b Mon Sep 17 00:00:00 2001 From: Julia Ryan Date: Thu, 5 Jun 2025 18:10:22 -0700 Subject: [PATCH] Fix matching braces in jsx/tsx tags (#32196) Closes #27998 Also fixed an issue where jumping back from closing to opening tags didn't work in javascript due to missing brackets in our tree-sitter query. Release Notes: - N/A --------- Co-authored-by: Conrad Irwin --- crates/languages/src/javascript/brackets.scm | 2 ++ crates/vim/src/motion.rs | 34 +++++++++++++++++++ .../src/test/neovim_backed_test_context.rs | 24 +++++++++++++ .../test_matching_braces_in_tag.json | 3 ++ 4 files changed, 63 insertions(+) create mode 100644 crates/vim/test_data/test_matching_braces_in_tag.json diff --git a/crates/languages/src/javascript/brackets.scm b/crates/languages/src/javascript/brackets.scm index 48afefeef07e9950cf6c8eba40b79def50c09c71..66bf14f137794b8a620b203c102ca3e3390fea20 100644 --- a/crates/languages/src/javascript/brackets.scm +++ b/crates/languages/src/javascript/brackets.scm @@ -2,6 +2,8 @@ ("[" @open "]" @close) ("{" @open "}" @close) ("<" @open ">" @close) +("<" @open "/>" @close) +("" @close) ("\"" @open "\"" @close) ("'" @open "'" @close) ("`" @open "`" @close) diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index 080f051db5e66c48e5335bb9753d4d319ba840b4..29ed528a5e4d0c468c7e892d44b52d0cfc5ba500 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -2279,6 +2279,17 @@ fn matching(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint line_end = map.max_point().to_point(map); } + if let Some((opening_range, closing_range)) = map + .buffer_snapshot + .innermost_enclosing_bracket_ranges(offset..offset, None) + { + if opening_range.contains(&offset) { + return closing_range.start.to_display_point(map); + } else if closing_range.contains(&offset) { + return opening_range.start.to_display_point(map); + } + } + let line_range = map.prev_line_boundary(point).0..line_end; let visible_line_range = line_range.start..Point::new(line_range.end.row, line_range.end.column.saturating_sub(1)); @@ -3242,6 +3253,29 @@ mod test { "#}); } + #[gpui::test] + async fn test_matching_braces_in_tag(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new_typescript(cx).await; + + // test brackets within tags + cx.set_shared_state(indoc! {r"function f() { + return ( +
+

test

+
+ ); + }"}) + .await; + cx.simulate_shared_keystrokes("%").await; + cx.shared_state().await.assert_eq(indoc! {r"function f() { + return ( +
+

test

+
+ ); + }"}); + } + #[gpui::test] async fn test_comma_semicolon(cx: &mut gpui::TestAppContext) { let mut cx = NeovimBackedTestContext::new(cx).await; diff --git a/crates/vim/src/test/neovim_backed_test_context.rs b/crates/vim/src/test/neovim_backed_test_context.rs index 053e1e587e1b71e8caa7104f14071592c4027a2f..505cdaa9100fcfad0d96bc6a55afe6ff4dc945ea 100644 --- a/crates/vim/src/test/neovim_backed_test_context.rs +++ b/crates/vim/src/test/neovim_backed_test_context.rs @@ -183,6 +183,30 @@ impl NeovimBackedTestContext { } } + pub async fn new_typescript(cx: &mut gpui::TestAppContext) -> NeovimBackedTestContext { + #[cfg(feature = "neovim")] + cx.executor().allow_parking(); + // rust stores the name of the test on the current thread. + // We use this to automatically name a file that will store + // the neovim connection's requests/responses so that we can + // run without neovim on CI. + let thread = thread::current(); + let test_name = thread + .name() + .expect("thread is not named") + .split(':') + .next_back() + .unwrap() + .to_string(); + Self { + cx: VimTestContext::new_typescript(cx).await, + neovim: NeovimConnection::new(test_name).await, + + last_set_state: None, + recent_keystrokes: Default::default(), + } + } + pub async fn set_shared_state(&mut self, marked_text: &str) { let mode = if marked_text.contains('»') { Mode::Visual diff --git a/crates/vim/test_data/test_matching_braces_in_tag.json b/crates/vim/test_data/test_matching_braces_in_tag.json new file mode 100644 index 0000000000000000000000000000000000000000..44201548a706789bd1a2bde15da8542945ab2e62 --- /dev/null +++ b/crates/vim/test_data/test_matching_braces_in_tag.json @@ -0,0 +1,3 @@ +{"Put":{"state":"function f() {\n return (\n
\n

test

\n
\n );\n}"}} +{"Key":"%"} +{"Get":{"state":"function f() {\n return (\n
\n

test

\n
\n );\n}","mode":"Normal"}}