From 0bd41d67b94bcf93da89cf79fb7f32b7d064d0b7 Mon Sep 17 00:00:00 2001 From: Alvaro Parker <64918109+AlvaroParker@users.noreply.github.com> Date: Mon, 1 Jun 2026 02:55:52 -0400 Subject: [PATCH] editor: Add toggle breadcrumb action (#57970) Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #55576 This PR adds a new `editor: toggle breadcrumb` actions that toggles the breadcrumbs for the active item without persisting on `settings.json`. Similar to what `editor: toggle minimap` does. https://github.com/user-attachments/assets/7179a0c8-6a5e-4716-86b8-abde8aa61f68 A simple test was added to check that using this action doesn't change the settings, and that changing an unrelated setting keeps the toggled action as the source of truth for the breadcrumb visibility. Release Notes: - Added `editor: toggle breadcrumb` action to toggle breadcrumb of active item without persisting on `settings.json` --- crates/editor/src/actions.rs | 2 ++ crates/editor/src/config.rs | 25 ++++++++++++++++ crates/editor/src/editor.rs | 49 +++++++++++++++++++++++++++---- crates/editor/src/editor_tests.rs | 45 +++++++++++++++++++++++++++- crates/editor/src/element.rs | 1 + crates/editor/src/items.rs | 2 +- 6 files changed, 117 insertions(+), 7 deletions(-) diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index 827c9067e3..2ed935eb34 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -918,6 +918,8 @@ actions!( AlignSelections, /// Saves the current location to navigation history. SaveLocation, + /// Toggles breadcrumbs display. + ToggleBreadcrumb, ] ); diff --git a/crates/editor/src/config.rs b/crates/editor/src/config.rs index 02256fe87d..9b5df0b867 100644 --- a/crates/editor/src/config.rs +++ b/crates/editor/src/config.rs @@ -138,6 +138,31 @@ impl Editor { } } + pub fn breadcrumbs_visible(&self) -> bool { + self.breadcrumbs_visibility.visible() + } + + fn set_breadcrumbs_visibility( + &mut self, + breadcrumbs_visibility: BreadcrumbsVisibility, + cx: &mut Context, + ) { + if self.breadcrumbs_visibility != breadcrumbs_visibility { + self.breadcrumbs_visibility = breadcrumbs_visibility; + cx.emit(EditorEvent::BreadcrumbsChanged); + cx.notify(); + } + } + + pub fn toggle_breadcrumb( + &mut self, + _: &ToggleBreadcrumb, + _: &mut Window, + cx: &mut Context, + ) { + self.set_breadcrumbs_visibility(self.breadcrumbs_visibility.toggle_visibility(), cx); + } + pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context) { self.set_show_scrollbars(false, cx); self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 0ced11ed2e..c4cab9a8eb 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -705,6 +705,40 @@ impl MinimapVisibility { } } +#[derive(Clone, Copy, PartialEq, Eq)] +struct BreadcrumbsVisibility { + setting_configuration: bool, + toggle_override: bool, +} + +impl BreadcrumbsVisibility { + fn from_settings(cx: &App) -> Self { + Self::new(EditorSettings::get_global(cx).toolbar.breadcrumbs) + } + + fn new(setting_configuration: bool) -> Self { + Self { + setting_configuration, + toggle_override: false, + } + } + + fn settings_visibility(&self) -> bool { + self.setting_configuration + } + + fn visible(&self) -> bool { + self.setting_configuration ^ self.toggle_override + } + + fn toggle_visibility(&self) -> Self { + Self { + setting_configuration: self.setting_configuration, + toggle_override: !self.toggle_override, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BufferSerialization { All, @@ -931,7 +965,7 @@ pub struct Editor { hovered_cursors: HashMap>, pub show_local_selections: bool, mode: EditorMode, - show_breadcrumbs: bool, + breadcrumbs_visibility: BreadcrumbsVisibility, show_gutter: bool, show_scrollbars: ScrollbarAxes, minimap_visibility: MinimapVisibility, @@ -2130,7 +2164,7 @@ impl Editor { }, minimap_visibility: MinimapVisibility::for_mode(&mode, cx), offset_content: !matches!(mode, EditorMode::SingleLine), - show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs, + breadcrumbs_visibility: BreadcrumbsVisibility::from_settings(cx), show_gutter: full_mode, show_line_numbers: (!full_mode).then_some(false), use_relative_line_numbers: None, @@ -9467,12 +9501,17 @@ impl Editor { self.refresh_inline_values(cx); let old_cursor_shape = self.cursor_shape; - let old_show_breadcrumbs = self.show_breadcrumbs; + let old_breadcrumbs_visible = self.breadcrumbs_visible(); { let editor_settings = EditorSettings::get_global(cx); self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin; - self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs; + if self.breadcrumbs_visibility.settings_visibility() + != editor_settings.toolbar.breadcrumbs + { + self.breadcrumbs_visibility = + BreadcrumbsVisibility::new(editor_settings.toolbar.breadcrumbs); + } self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default(); } @@ -9480,7 +9519,7 @@ impl Editor { cx.emit(EditorEvent::CursorShapeChanged); } - if old_show_breadcrumbs != self.show_breadcrumbs { + if old_breadcrumbs_visible != self.breadcrumbs_visible() { cx.emit(EditorEvent::BreadcrumbsChanged); } diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 3eca954d6d..c90e54d0c6 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -70,7 +70,7 @@ use util::{ }; use workspace::{ CloseActiveItem, CloseAllItems, CloseOtherItems, MultiWorkspace, NavigationEntry, OpenOptions, - ViewId, + ToolbarItemLocation, ViewId, item::{FollowEvent, FollowableItem, Item, ItemHandle, SaveOptions}, register_project_item, }; @@ -917,6 +917,49 @@ fn test_clone(cx: &mut TestAppContext) { ); } +#[gpui::test] +fn test_toggle_breadcrumb_does_not_change_settings(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + update_test_editor_settings(cx, &|settings| { + settings.toolbar.get_or_insert_default().breadcrumbs = Some(true); + }); + + let editor = cx.add_window(|window, cx| { + let buffer = MultiBuffer::build_simple("hello", cx); + build_editor(buffer, window, cx) + }); + + _ = editor.update(cx, |editor, window, cx| { + assert!(EditorSettings::get_global(cx).toolbar.breadcrumbs); + assert_eq!( + editor.breadcrumb_location(cx), + ToolbarItemLocation::PrimaryLeft + ); + + editor.toggle_breadcrumb(&ToggleBreadcrumb, window, cx); + assert!(EditorSettings::get_global(cx).toolbar.breadcrumbs); + assert_eq!(editor.breadcrumb_location(cx), ToolbarItemLocation::Hidden); + }); + + // Changing unrelated settings should not affect breadcrumbs visibility. + update_test_editor_settings(cx, &|settings| { + settings.vertical_scroll_margin = Some(4.0); + }); + cx.run_until_parked(); + + _ = editor.update(cx, |editor, window, cx| { + assert!(EditorSettings::get_global(cx).toolbar.breadcrumbs); + assert_eq!(editor.breadcrumb_location(cx), ToolbarItemLocation::Hidden); + + editor.toggle_breadcrumb(&ToggleBreadcrumb, window, cx); + assert!(EditorSettings::get_global(cx).toolbar.breadcrumbs); + assert_eq!( + editor.breadcrumb_location(cx), + ToolbarItemLocation::PrimaryLeft + ); + }); +} + #[gpui::test] async fn test_navigation_history(cx: &mut TestAppContext) { init_test(cx, |_| {}); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index dbba534c6f..0ac3b2691d 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -421,6 +421,7 @@ impl EditorElement { register_action(editor, window, Editor::open_excerpts_in_split); register_action(editor, window, Editor::toggle_soft_wrap); register_action(editor, window, Editor::toggle_tab_bar); + register_action(editor, window, Editor::toggle_breadcrumb); register_action(editor, window, Editor::toggle_line_numbers); register_action(editor, window, Editor::toggle_relative_line_numbers); register_action(editor, window, Editor::toggle_indent_guides); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 89f323ab14..9d5ad821ed 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -1029,7 +1029,7 @@ impl Item for Editor { } fn breadcrumb_location(&self, cx: &App) -> ToolbarItemLocation { - if self.show_breadcrumbs && self.buffer().read(cx).is_singleton() { + if self.breadcrumbs_visible() && self.buffer().read(cx).is_singleton() { ToolbarItemLocation::PrimaryLeft } else { ToolbarItemLocation::Hidden