From 04c607bd55829c4ae5538511d60d1eb7f6ecc73b Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sat, 8 Aug 2026 18:41:14 +0700 Subject: [PATCH] fix(rename): stop a rename box turning typing into prepending MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename Tab, Rename Workspace and the switcher's rename all opened with the current name in the box and the caret at offset 0, so the first thing you typed landed in front of it: renaming "tty7" to "build" got you "buildtty7" until you noticed and went back. Only the file-tree rename had it right, because it happens to fill the box with `set_value` rather than `default_value` — and `set_value` puts the caret at the end of a single-line input. All three now go through one helper that does the same, with a test holding the caret where it belongs. Selecting the name outright is what the platform does and would be better still, but `InputState::select_all` is `pub(super)` in the UI crate; that one wants a change over there. --- src/ui/app.rs | 60 ++++++++++++++++++++++++++++++++++++++++++---- src/ui/switcher.rs | 3 +-- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/ui/app.rs b/src/ui/app.rs index 31a8dbdb..22abd2ad 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -3346,6 +3346,27 @@ impl Tty7App { cx.notify(); } + /// Fills a rename box with the current name and puts the caret after it. + /// + /// `default_value` leaves the caret at offset 0, which turns typing into + /// prepending — renaming "tty7" reached "buildtty7" before it reached + /// "build". `set_value` lands the caret at the end of a single-line input, + /// which is where it belongs and what the file-tree rename box already + /// did. (Selecting the name outright would be better still, and is what + /// the platform does, but `InputState::select_all` is not public.) + pub(crate) fn rename_box( + current: String, + window: &mut Window, + cx: &mut Context, + ) -> Entity { + let input = cx.new(|cx| InputState::new(window, cx)); + input.update(cx, |state, cx| { + state.set_value(current, window, cx); + state.focus(window, cx); + }); + input + } + pub(crate) fn start_rename( &mut self, index: usize, @@ -3356,8 +3377,7 @@ impl Tty7App { return; } let current = self.tab_label(&self.tabs[index], index, Some(&*window), cx); - let input = cx.new(|cx| InputState::new(window, cx).default_value(current)); - input.update(cx, |state, cx| state.focus(window, cx)); + let input = Self::rename_box(current, window, cx); let subs = vec![cx.subscribe_in( &input, window, @@ -3377,8 +3397,7 @@ impl Tty7App { pub(crate) fn start_workspace_rename(&mut self, window: &mut Window, cx: &mut Context) { let current = crate::ui::machine_mirror::display_name_for(cx, self.workspace).unwrap_or_default(); - let input = cx.new(|cx| InputState::new(window, cx).default_value(current)); - input.update(cx, |state, cx| state.focus(window, cx)); + let input = Self::rename_box(current, window, cx); let subs = vec![cx.subscribe_in( &input, window, @@ -7317,3 +7336,36 @@ mod shell_menu_gpui_tests { }); } } + +#[cfg(test)] +mod rename_gpui_tests { + use gpui::TestAppContext; + + use crate::ui::app::test_window::harness_with_tabs; + + #[gpui::test] + fn a_rename_box_opens_with_the_caret_after_the_name(cx: &mut TestAppContext) { + let (app, mut vcx, _streams) = harness_with_tabs(cx, 1); + + app.update_in(&mut vcx, |app, window, cx| app.start_rename(0, window, cx)); + vcx.background_executor.run_until_parked(); + + app.update(&mut vcx, |app, cx| { + let input = app + .renaming + .as_ref() + .expect("the rename box is up") + .input + .clone(); + let state = input.read(cx); + let value = state.value().to_string(); + assert!(!value.is_empty(), "the box starts on the current name"); + let end = value.len(); + assert_eq!( + state.selected_range(), + end..end, + "typing has to continue {value:?}, not land in front of it" + ); + }); + } +} diff --git a/src/ui/switcher.rs b/src/ui/switcher.rs index 61aa4c47..c5d8f291 100644 --- a/src/ui/switcher.rs +++ b/src/ui/switcher.rs @@ -768,8 +768,7 @@ impl Tty7App { fn switcher_rename(&mut self, id: WorkspaceId, window: &mut Window, cx: &mut Context) { let current = crate::ui::machine_mirror::display_name_for(cx, id).unwrap_or_default(); - let input = cx.new(|cx| InputState::new(window, cx).default_value(current)); - input.update(cx, |state, cx| state.focus(window, cx)); + let input = Self::rename_box(current, window, cx); let sub = cx.subscribe_in( &input, window,