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}