breadcrumbs.rs

  1use editor::render_breadcrumb_text;
  2use gpui::{Context, EventEmitter, IntoElement, Render, Subscription, Window};
  3use theme::ActiveTheme;
  4use ui::prelude::*;
  5use workspace::{
  6    ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView,
  7    item::{ItemEvent, ItemHandle},
  8};
  9
 10pub struct Breadcrumbs {
 11    pane_focused: bool,
 12    active_item: Option<Box<dyn ItemHandle>>,
 13    subscription: Option<Subscription>,
 14}
 15
 16impl Default for Breadcrumbs {
 17    fn default() -> Self {
 18        Self::new()
 19    }
 20}
 21
 22impl Breadcrumbs {
 23    pub fn new() -> Self {
 24        Self {
 25            pane_focused: false,
 26            active_item: Default::default(),
 27            subscription: Default::default(),
 28        }
 29    }
 30}
 31
 32impl EventEmitter<ToolbarItemEvent> for Breadcrumbs {}
 33
 34impl Render for Breadcrumbs {
 35    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 36        let element = h_flex()
 37            .id("breadcrumb-container")
 38            .flex_grow()
 39            .h_8()
 40            .overflow_x_scroll()
 41            .text_ui(cx);
 42        let Some(active_item) = self.active_item.as_ref() else {
 43            return element.into_any_element();
 44        };
 45
 46        let Some(segments) = active_item.breadcrumbs(cx.theme(), cx) else {
 47            return element.into_any_element();
 48        };
 49        let prefix_element = active_item.breadcrumb_prefix(window, cx);
 50        render_breadcrumb_text(
 51            segments,
 52            prefix_element,
 53            Box::new(active_item.as_ref()),
 54            window,
 55            cx,
 56        )
 57        .into_any_element()
 58    }
 59}
 60
 61impl ToolbarItemView for Breadcrumbs {
 62    fn set_active_pane_item(
 63        &mut self,
 64        active_pane_item: Option<&dyn ItemHandle>,
 65        window: &mut Window,
 66        cx: &mut Context<Self>,
 67    ) -> ToolbarItemLocation {
 68        cx.notify();
 69        self.active_item = None;
 70
 71        let Some(item) = active_pane_item else {
 72            return ToolbarItemLocation::Hidden;
 73        };
 74
 75        let this = cx.entity().downgrade();
 76        self.subscription = Some(item.subscribe_to_item_events(
 77            window,
 78            cx,
 79            Box::new(move |event, _, cx| {
 80                if let ItemEvent::UpdateBreadcrumbs = event {
 81                    this.update(cx, |this, cx| {
 82                        cx.notify();
 83                        if let Some(active_item) = this.active_item.as_ref() {
 84                            cx.emit(ToolbarItemEvent::ChangeLocation(
 85                                active_item.breadcrumb_location(cx),
 86                            ))
 87                        }
 88                    })
 89                    .ok();
 90                }
 91            }),
 92        ));
 93        self.active_item = Some(item.boxed_clone());
 94        item.breadcrumb_location(cx)
 95    }
 96
 97    fn pane_focus_update(
 98        &mut self,
 99        pane_focused: bool,
100        _window: &mut Window,
101        _: &mut Context<Self>,
102    ) {
103        self.pane_focused = pane_focused;
104    }
105}