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