use editor::Editor; use gpui::{ Div, Element, EventEmitter, IntoElement, ParentElement, Render, StyledText, Subscription, ViewContext, }; use itertools::Itertools; use theme::ActiveTheme; use ui::{prelude::*, ButtonLike, ButtonStyle, Label, Tooltip}; use workspace::{ item::{ItemEvent, ItemHandle}, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, }; pub enum Event { UpdateLocation, } pub struct Breadcrumbs { pane_focused: bool, active_item: Option>, subscription: Option, } impl Breadcrumbs { pub fn new() -> Self { Self { pane_focused: false, active_item: Default::default(), subscription: Default::default(), } } } impl EventEmitter for Breadcrumbs {} impl EventEmitter for Breadcrumbs {} impl Render for Breadcrumbs { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let element = h_stack().text_ui(); let Some(active_item) = &self .active_item .as_ref() .filter(|item| item.downcast::().is_some()) else { return element; }; let Some(segments) = active_item.breadcrumbs(cx.theme(), cx) else { return element; }; let highlighted_segments = segments.into_iter().map(|segment| { StyledText::new(segment.text) .with_highlights(&cx.text_style(), segment.highlights.unwrap_or_default()) .into_any() }); let breadcrumbs = Itertools::intersperse_with(highlighted_segments, || { Label::new("›").into_any_element() }); let editor = active_item .downcast::() .map(|editor| editor.downgrade()); element.child( ButtonLike::new("toggle outline view") .style(ButtonStyle::Subtle) .child(h_stack().gap_1().children(breadcrumbs)) .on_click(move |_, cx| { if let Some(editor) = editor.as_ref().and_then(|editor| editor.upgrade()) { outline::toggle(editor, &outline::Toggle, cx) } }) .tooltip(|cx| Tooltip::for_action("Show symbol outline", &outline::Toggle, cx)), ) } } impl ToolbarItemView for Breadcrumbs { fn set_active_pane_item( &mut self, active_pane_item: Option<&dyn ItemHandle>, cx: &mut ViewContext, ) -> ToolbarItemLocation { cx.notify(); self.active_item = None; if let Some(item) = active_pane_item { let this = cx.view().downgrade(); self.subscription = Some(item.subscribe_to_item_events( cx, Box::new(move |event, cx| { if let ItemEvent::UpdateBreadcrumbs = event { this.update(cx, |_, cx| { cx.emit(Event::UpdateLocation); cx.notify(); }) .ok(); } }), )); self.active_item = Some(item.boxed_clone()); item.breadcrumb_location(cx) } else { ToolbarItemLocation::Hidden } } // fn location_for_event( // &self, // _: &Event, // current_location: ToolbarItemLocation, // cx: &AppContext, // ) -> ToolbarItemLocation { // if let Some(active_item) = self.active_item.as_ref() { // active_item.breadcrumb_location(cx) // } else { // current_location // } // } fn pane_focus_update(&mut self, pane_focused: bool, _: &mut ViewContext) { self.pane_focused = pane_focused; } }