From 30e562c8c2323c0b1cfd424d2bbb60e12ab2462f Mon Sep 17 00:00:00 2001 From: Lionel DARNIS Date: Sat, 25 Jul 2026 22:53:11 +0200 Subject: [PATCH] fix: nav_context_menu must produce one submenu per nav item The segmented_button widget asserts that context_menu children count matches model length. The yoda fork was building a single flat menu for the clicked item instead of iterating over all nav_model items like upstream, causing an assertion panic on right-click in the sidebar (trash, folders, etc.). Align with upstream: iterate self.nav_model.iter() and use menu::nav_context() instead of menu::items(). --- src/app.rs | 169 +++++++++++++++++++++++++++-------------------------- 1 file changed, 87 insertions(+), 82 deletions(-) diff --git a/src/app.rs b/src/app.rs index 0e572a0..ebd32d9 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2833,94 +2833,99 @@ impl Application for App { fn nav_context_menu( &self, ) -> Option>>> { - let entity = self.nav_bar_context_id; - let favorite_index_opt = self.nav_model.data::(entity); - let location_opt = self.nav_model.data::(entity); + let items = self.nav_model.iter().map(|entity| { + let favorite_index_opt = self.nav_model.data::(entity); + let location_opt = self.nav_model.data::(entity); - let mut items = Vec::with_capacity(7); + let mut items = Vec::with_capacity(7); - if location_opt - .and_then(Location::path_opt) - .is_some_and(|x| x.is_file()) - { - items.push(cosmic::widget::menu::Item::Button( - fl!("open"), - None, - NavMenuAction::Open(entity), - )); - items.push(cosmic::widget::menu::Item::Button( - fl!("menu-open-with"), - None, - NavMenuAction::OpenWith(entity), - )); - } else { - items.push(cosmic::widget::menu::Item::Button( - fl!("open-in-new-tab"), - None, - NavMenuAction::OpenInNewTab(entity), - )); - items.push(cosmic::widget::menu::Item::Button( - fl!("open-in-new-window"), - None, - NavMenuAction::OpenInNewWindow(entity), - )); - } - if let Some(path) = location_opt.and_then(Location::path_opt) { - let selected_dir = usize::from(path.is_dir()); - let action_items: Vec<_> = self - .config - .context_actions - .iter() - .enumerate() - .filter(|(_, action)| action.matches_selection(1, selected_dir)) - .map(|(i, action)| { - cosmic::widget::menu::Item::Button( - action.name.clone(), - None, - NavMenuAction::RunContextAction(entity, i), - ) - }) - .collect(); - - if !action_items.is_empty() { - items.push(cosmic::widget::menu::Item::Divider); - items.extend(action_items); + if location_opt + .and_then(Location::path_opt) + .is_some_and(|x| x.is_file()) + { + items.push(cosmic::widget::menu::Item::Button( + fl!("open"), + None, + NavMenuAction::Open(entity), + )); + items.push(cosmic::widget::menu::Item::Button( + fl!("menu-open-with"), + None, + NavMenuAction::OpenWith(entity), + )); + } else { + items.push(cosmic::widget::menu::Item::Button( + fl!("open-in-new-tab"), + None, + NavMenuAction::OpenInNewTab(entity), + )); + items.push(cosmic::widget::menu::Item::Button( + fl!("open-in-new-window"), + None, + NavMenuAction::OpenInNewWindow(entity), + )); } - } - items.push(cosmic::widget::menu::Item::Divider); - if matches!(location_opt, Some(Location::Path(..))) { - items.push(cosmic::widget::menu::Item::Button( - fl!("show-details"), - None, - NavMenuAction::Preview(entity), - )); - } - items.push(cosmic::widget::menu::Item::Divider); - if favorite_index_opt.is_some() { - items.push(cosmic::widget::menu::Item::Button( - fl!("remove-from-sidebar"), - None, - NavMenuAction::RemoveFromSidebar(entity), - )); - } + if let Some(path) = location_opt.and_then(Location::path_opt) { + let selected_dir = usize::from(path.is_dir()); + let action_items: Vec<_> = self + .config + .context_actions + .iter() + .enumerate() + .filter(|(_, action)| action.matches_selection(1, selected_dir)) + .map(|(i, action)| { + cosmic::widget::menu::Item::Button( + action.name.clone(), + None, + NavMenuAction::RunContextAction(entity, i), + ) + }) + .collect(); - if matches!(location_opt, Some(Location::Recents)) && tab::has_recents() { - items.push(cosmic::widget::menu::Item::Button( - fl!("clear-recents-history"), - None, - NavMenuAction::ClearRecents, - )); - } + if !action_items.is_empty() { + items.push(cosmic::widget::menu::Item::Divider); + items.extend(action_items); + } + } + items.push(cosmic::widget::menu::Item::Divider); + if matches!(location_opt, Some(Location::Path(..))) { + items.push(cosmic::widget::menu::Item::Button( + fl!("show-details"), + None, + NavMenuAction::Preview(entity), + )); + } + items.push(cosmic::widget::menu::Item::Divider); + if favorite_index_opt.is_some() { + items.push(cosmic::widget::menu::Item::Button( + fl!("remove-from-sidebar"), + None, + NavMenuAction::RemoveFromSidebar(entity), + )); + } - if matches!(location_opt, Some(Location::Trash)) && !Trash::is_empty() { - items.push(cosmic::widget::menu::Item::Button( - fl!("empty-trash"), - None, - NavMenuAction::EmptyTrash, - )); - } + if matches!(location_opt, Some(Location::Recents)) && tab::has_recents() { + items.push(cosmic::widget::menu::Item::Button( + fl!("clear-recents-history"), + None, + NavMenuAction::ClearRecents, + )); + } - Some(cosmic::widget::menu::items(&HashMap::new(), items)) + if matches!(location_opt, Some(Location::Trash)) && !Trash::is_empty() { + items.push(cosmic::widget::menu::Item::Button( + fl!("empty-trash"), + None, + NavMenuAction::EmptyTrash, + )); + } + items + }); + + Some(cosmic::widget::menu::nav_context( + &HashMap::new(), + items.collect(), + )) } fn nav_model(&self) -> Option<&segmented_button::SingleSelectModel> {