1use gpui::{AnyElement, Empty, Entity, FocusHandle, Focusable, ListState, Subscription, list};
2use project::debugger::session::{Session, SessionEvent};
3use ui::prelude::*;
4use util::maybe;
5
6pub(crate) struct LoadedSourceList {
7 list: ListState,
8 invalidate: bool,
9 focus_handle: FocusHandle,
10 _subscription: Subscription,
11 session: Entity<Session>,
12}
13
14impl LoadedSourceList {
15 pub fn new(session: Entity<Session>, cx: &mut Context<Self>) -> Self {
16 let focus_handle = cx.focus_handle();
17 let list = ListState::new(0, gpui::ListAlignment::Top, px(1000.));
18
19 let _subscription = cx.subscribe(&session, |this, _, event, cx| match event {
20 SessionEvent::Stopped(_) | SessionEvent::LoadedSources => {
21 this.invalidate = true;
22 cx.notify();
23 }
24 _ => {}
25 });
26
27 Self {
28 list,
29 session,
30 focus_handle,
31 _subscription,
32 invalidate: true,
33 }
34 }
35
36 fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
37 let Some(source) = maybe!({
38 self.session
39 .update(cx, |state, cx| state.loaded_sources(cx).get(ix).cloned())
40 }) else {
41 return Empty.into_any();
42 };
43
44 v_flex()
45 .rounded_md()
46 .w_full()
47 .group("")
48 .p_1()
49 .hover(|s| s.bg(cx.theme().colors().element_hover))
50 .child(
51 h_flex()
52 .gap_0p5()
53 .text_ui_sm(cx)
54 .when_some(source.name.clone(), |this, name| this.child(name)),
55 )
56 .child(
57 h_flex()
58 .text_ui_xs(cx)
59 .text_color(cx.theme().colors().text_muted)
60 .when_some(source.path, |this, path| this.child(path)),
61 )
62 .into_any()
63 }
64}
65
66impl Focusable for LoadedSourceList {
67 fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle {
68 self.focus_handle.clone()
69 }
70}
71
72impl Render for LoadedSourceList {
73 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
74 if self.invalidate {
75 let len = self
76 .session
77 .update(cx, |session, cx| session.loaded_sources(cx).len());
78 self.list.reset(len);
79 self.invalidate = false;
80 cx.notify();
81 }
82
83 div()
84 .track_focus(&self.focus_handle)
85 .size_full()
86 .p_1()
87 .child(
88 list(
89 self.list.clone(),
90 cx.processor(|this, ix, _window, cx| this.render_entry(ix, cx)),
91 )
92 .size_full(),
93 )
94 }
95}