loaded_source_list.rs

 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(_)
21            | SessionEvent::HistoricSnapshotSelected
22            | SessionEvent::LoadedSources => {
23                this.invalidate = true;
24                cx.notify();
25            }
26            _ => {}
27        });
28
29        Self {
30            list,
31            session,
32            focus_handle,
33            _subscription,
34            invalidate: true,
35        }
36    }
37
38    fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
39        let Some(source) = maybe!({
40            self.session
41                .update(cx, |state, cx| state.loaded_sources(cx).get(ix).cloned())
42        }) else {
43            return Empty.into_any();
44        };
45
46        v_flex()
47            .rounded_md()
48            .w_full()
49            .group("")
50            .p_1()
51            .hover(|s| s.bg(cx.theme().colors().element_hover))
52            .child(
53                h_flex()
54                    .gap_0p5()
55                    .text_ui_sm(cx)
56                    .when_some(source.name.clone(), |this, name| this.child(name)),
57            )
58            .child(
59                h_flex()
60                    .text_ui_xs(cx)
61                    .text_color(cx.theme().colors().text_muted)
62                    .when_some(source.path, |this, path| this.child(path)),
63            )
64            .into_any()
65    }
66}
67
68impl Focusable for LoadedSourceList {
69    fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle {
70        self.focus_handle.clone()
71    }
72}
73
74impl Render for LoadedSourceList {
75    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
76        if self.invalidate {
77            let len = self
78                .session
79                .update(cx, |session, cx| session.loaded_sources(cx).len());
80            self.list.reset(len);
81            self.invalidate = false;
82            cx.notify();
83        }
84
85        div()
86            .track_focus(&self.focus_handle)
87            .size_full()
88            .p_1()
89            .child(
90                list(
91                    self.list.clone(),
92                    cx.processor(|this, ix, _window, cx| this.render_entry(ix, cx)),
93                )
94                .size_full(),
95            )
96    }
97}