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
 43        let Some(active_item) = self.active_item.as_ref() else {
 44            return element.into_any_element();
 45        };
 46
 47        let Some(segments) = active_item.breadcrumbs(cx.theme(), cx) else {
 48            return element.into_any_element();
 49        };
 50
 51        let prefix_element = active_item.breadcrumb_prefix(window, cx);
 52
 53        render_breadcrumb_text(
 54            segments,
 55            prefix_element,
 56            active_item.as_ref(),
 57            false,
 58            window,
 59            cx,
 60        )
 61        .into_any_element()
 62    }
 63}
 64
 65impl ToolbarItemView for Breadcrumbs {
 66    fn set_active_pane_item(
 67        &mut self,
 68        active_pane_item: Option<&dyn ItemHandle>,
 69        window: &mut Window,
 70        cx: &mut Context<Self>,
 71    ) -> ToolbarItemLocation {
 72        cx.notify();
 73        self.active_item = None;
 74
 75        let Some(item) = active_pane_item else {
 76            return ToolbarItemLocation::Hidden;
 77        };
 78
 79        let this = cx.entity().downgrade();
 80        self.subscription = Some(item.subscribe_to_item_events(
 81            window,
 82            cx,
 83            Box::new(move |event, _, cx| {
 84                if let ItemEvent::UpdateBreadcrumbs = event {
 85                    this.update(cx, |this, cx| {
 86                        cx.notify();
 87                        if let Some(active_item) = this.active_item.as_ref() {
 88                            cx.emit(ToolbarItemEvent::ChangeLocation(
 89                                active_item.breadcrumb_location(cx),
 90                            ))
 91                        }
 92                    })
 93                    .ok();
 94                }
 95            }),
 96        ));
 97        self.active_item = Some(item.boxed_clone());
 98        item.breadcrumb_location(cx)
 99    }
100
101    fn pane_focus_update(
102        &mut self,
103        pane_focused: bool,
104        _window: &mut Window,
105        _: &mut Context<Self>,
106    ) {
107        self.pane_focused = pane_focused;
108    }
109}