From 5e10e17cd5f73270850258fba1ea45a4b203de7d Mon Sep 17 00:00:00 2001 From: clover caruso Date: Fri, 2 Oct 2026 20:59:10 -0700 Subject: [PATCH] fix: Rename on a section tab's menu edits the tab in place As a double click on the tab does, rather than opening the sidebar on the section's row. A menu counts as the tab's when it opened over the tab row. Assisted-by: claude-opus-5.5 --- crates/snowbound/src/menus.rs | 30 +++++++++++++++++++++++++++++- crates/snowbound/tests/replay.rs | 13 ++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/crates/snowbound/src/menus.rs b/crates/snowbound/src/menus.rs index 3face8fe9d207b91999ce2aac19ec2b32bfa586d..aa19fdf425bb59f0a9874a67a994a86c53d8a5c5 100644 --- a/crates/snowbound/src/menus.rs +++ b/crates/snowbound/src/menus.rs @@ -376,12 +376,40 @@ impl State { } (Some(action), _) => { self.menu = None; - self.act_on(target, action); + match target { + // From its tab, as a double click there renames it. + Target::Section { library, path } + if action == Action::Rename && self.on_tab(&library, &path, point) => + { + self.rename(crate::rename::Target::Entry { + library, + path, + in_tab: true, + }); + } + target => self.act_on(target, action), + } } (None, _) => {} } } + /// Whether `point`, where a context menu opened, is on the tab of section `path`. + fn on_tab(&self, library: &Arc, path: &str, point: [f32; 2]) -> bool { + let shown = self.session.as_ref().is_some_and(|session| { + Arc::ptr_eq(&session.library, library) + && session.tabs.iter().any(|tab| tab.path == path) + }); + let [x, y] = point; + shown + && self + .ui + .rect(crate::sections()) + .is_some_and(|[left, top, right, bottom]| { + x >= left && x < right && y >= top && y < bottom + }) + } + /// What can be done to `target`, in its context menu's order, as each shows there. pub(crate) fn actions(&self, target: &Target) -> Vec<(Action, Item<'static>)> { // An action, its label, whether it is disabled, and whether a rule starts its group. diff --git a/crates/snowbound/tests/replay.rs b/crates/snowbound/tests/replay.rs index c7ad6fd3810cafe6d8171fc6f74ffdfc3211bbc2..9556dc2797f3410c8fdf7dab753779ce04b125ea 100644 --- a/crates/snowbound/tests/replay.rs +++ b/crates/snowbound/tests/replay.rs @@ -564,23 +564,26 @@ fn a_version_copied_into_its_section_is_listed_and_found() { assert!(!search_results(&found).is_empty(), "{found}"); } -/// Rename on a section tab's menu opens the shut sidebar on a field that takes what is -/// typed over the old name at once. +/// Rename on a section tab's menu opens the field on the tab, as a double click there does, +/// which takes what is typed over the old name at once; the shut sidebar stays shut. #[test] -fn renaming_a_section_from_its_tab_types_into_the_sidebar_at_once() { - let scratch = Scratch::new("rename-shut-sidebar"); +fn renaming_a_section_from_its_tab_types_into_the_tab_at_once() { + let scratch = Scratch::new("rename-tab"); let notebook = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../corpus/cross-container/candidate"); let mut steps = vec!["move 110 53", "press right", "release right", "settle"]; steps.extend(["key Down", "key Enter", "settle"]); steps.extend(["type Renamed", "accessibility typed"]); - let [typed] = replay(&scratch, Some(¬ebook), &steps) + steps.extend(["key Enter", "settle", "accessibility renamed"]); + let [typed, renamed] = replay(&scratch, Some(¬ebook), &steps) .try_into() .unwrap(); assert!( typed.contains(r#"TextInput "Name" = "Renamed" [focused]"#), "{typed}" ); + assert!(notebooks(&typed).is_empty(), "the sidebar opened:\n{typed}"); + assert!(renamed.contains(r#"Tab "Renamed""#), "{renamed}"); } /// Finding on the page leaves the query room beside the match count: a press just past -- 2.54.0