From 3630ac923874c4b0689be15a0070f02bc1de3ece Mon Sep 17 00:00:00 2001 From: Om Chillure Date: Mon, 2 Mar 2026 21:54:39 +0530 Subject: [PATCH] Fix renaming with `.` in JSX tags (#50373) Fixes #50245 ### Summary : This PR fixes linked tag renaming when typing . in tag names like .... Previously, linked editing treated . as punctuation (unless a language explicitly configured it as a linked-edit character), so renaming could stop syncing at the dot and produce mismatched closing tags. ### What changed Updated linked-edit input handling to preserve linked edits when the typed input is exactly ".", even if the active language does not explicitly include dot in linked_edit_characters. Added a regression test covering dot typing in linked edits without language override. Kept existing punctuation behavior (e.g. >) unchanged. ### Files changed [editor.rs] [editor_tests.rs] ### Why this approach Minimal, targeted fix in shared linked-edit path. Works for .svelte and similar markup contexts where dot-separated component names are valid in practice. Avoids requiring every language/extension to add dot config individually. ### Validation Manual repro confirmed: opening tag rename with dot now keeps closing tag synced. Added test: test_linked_edits_on_typing_dot_without_language_override. Existing related test remains relevant: test_linked_edits_on_typing_punctuation. --- crates/editor/src/editor.rs | 4 ++- crates/editor/src/editor_tests.rs | 42 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 93d87885babf6265ff4b12c9da2c4c0cc07ec9a9..eb8601d59e1c9970f367177f3f365f4feb30811e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -4898,8 +4898,10 @@ impl Editor { .scope_context(Some(CharScopeContext::LinkedEdit)); classifier.is_word(char) }); + let is_dot = text.as_ref() == "."; + let should_apply_linked_edit = is_word_char || is_dot; - if is_word_char { + if should_apply_linked_edit { let anchor_range = start_anchor.text_anchor..anchor.text_anchor; linked_edits.push(&self, anchor_range, text.clone(), cx); } else { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 88be32d6d73d967ab34b287534308164b8623679..142668e6555bcb23370387aab655b0d6b82fa5fe 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -26623,6 +26623,48 @@ async fn test_linked_edits_on_typing_punctuation(cx: &mut TestAppContext) { cx.assert_editor_state(""); } +#[gpui::test] +async fn test_linked_edits_on_typing_dot_without_language_override(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let mut cx = EditorTestContext::new(cx).await; + let language = Arc::new(Language::new( + LanguageConfig { + name: "HTML".into(), + matcher: LanguageMatcher { + path_suffixes: vec!["html".to_string()], + ..LanguageMatcher::default() + }, + brackets: BracketPairConfig { + pairs: vec![BracketPair { + start: "<".into(), + end: ">".into(), + close: true, + ..Default::default() + }], + ..Default::default() + }, + ..Default::default() + }, + Some(tree_sitter_html::LANGUAGE.into()), + )); + cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx)); + + cx.set_state(""); + cx.update_editor(|editor, _, cx| { + set_linked_edit_ranges( + (Point::new(0, 1), Point::new(0, 6)), + (Point::new(0, 9), Point::new(0, 14)), + editor, + cx, + ); + }); + cx.update_editor(|editor, window, cx| { + editor.handle_input(".", window, cx); + }); + cx.assert_editor_state(""); +} + #[gpui::test] async fn test_invisible_worktree_servers(cx: &mut TestAppContext) { init_test(cx, |_| {});