183 lines · 5.8 KB · Rust
RawDownload
use anyhow::anyhow;use gpui::{    list, AnyElement, Empty, Entity, FocusHandle, Focusable, ListState, Subscription, WeakEntity,};use project::{    debugger::session::{Session, SessionEvent},    ProjectItem as _, ProjectPath,};use std::{path::Path, sync::Arc};use ui::prelude::*;use util::maybe;use workspace::Workspace; pub struct ModuleList {    list: ListState,    invalidate: bool,    session: Entity<Session>,    workspace: WeakEntity<Workspace>,    focus_handle: FocusHandle,    _subscription: Subscription,} impl ModuleList {    pub fn new(        session: Entity<Session>,        workspace: WeakEntity<Workspace>,        cx: &mut Context<Self>,    ) -> Self {        let weak_entity = cx.weak_entity();        let focus_handle = cx.focus_handle();         let list = ListState::new(            0,            gpui::ListAlignment::Top,            px(1000.),            move |ix, _window, cx| {                weak_entity                    .upgrade()                    .map(|module_list| module_list.update(cx, |this, cx| this.render_entry(ix, cx)))                    .unwrap_or(div().into_any())            },        );         let _subscription = cx.subscribe(&session, |this, _, event, cx| match event {            SessionEvent::Stopped(_) | SessionEvent::Modules => {                this.invalidate = true;                cx.notify();            }            _ => {}        });         Self {            list,            session,            workspace,            focus_handle,            _subscription,            invalidate: true,        }    }     fn open_module(&mut self, path: Arc<Path>, window: &mut Window, cx: &mut Context<Self>) {        cx.spawn_in(window, async move |this, cx| {            let (worktree, relative_path) = this                .update(cx, |this, cx| {                    this.workspace.update(cx, |workspace, cx| {                        workspace.project().update(cx, |this, cx| {                            this.find_or_create_worktree(&path, false, cx)                        })                    })                })??                .await?;             let buffer = this                .update(cx, |this, cx| {                    this.workspace.update(cx, |this, cx| {                        this.project().update(cx, |this, cx| {                            let worktree_id = worktree.read(cx).id();                            this.open_buffer(                                ProjectPath {                                    worktree_id,                                    path: relative_path.into(),                                },                                cx,                            )                        })                    })                })??                .await?;             this.update_in(cx, |this, window, cx| {                this.workspace.update(cx, |workspace, cx| {                    let project_path = buffer.read(cx).project_path(cx).ok_or_else(|| {                        anyhow!("Could not select a stack frame for unnamed buffer")                    })?;                    anyhow::Ok(workspace.open_path_preview(                        project_path,                        None,                        false,                        true,                        true,                        window,                        cx,                    ))                })            })???            .await?;             anyhow::Ok(())        })        .detach_and_log_err(cx);    }     fn render_entry(&mut self, ix: usize, cx: &mut Context<Self>) -> AnyElement {        let Some(module) = maybe!({            self.session                .update(cx, |state, cx| state.modules(cx).get(ix).cloned())        }) else {            return Empty.into_any();        };         v_flex()            .rounded_md()            .w_full()            .group("")            .id(("module-list", ix))            .when(module.path.is_some(), |this| {                this.on_click({                    let path = module.path.as_deref().map(|path| Arc::<Path>::from(Path::new(path)));                    cx.listener(move |this, _, window, cx| {                        if let Some(path) = path.as_ref() {                            this.open_module(path.clone(), window, cx);                        } else {                            log::error!("Wasn't able to find module path, but was still able to click on module list entry");                        }                    })                })            })            .p_1()            .hover(|s| s.bg(cx.theme().colors().element_hover))            .child(h_flex().gap_0p5().text_ui_sm(cx).child(module.name.clone()))            .child(                h_flex()                    .text_ui_xs(cx)                    .text_color(cx.theme().colors().text_muted)                    .when_some(module.path.clone(), |this, path| this.child(path)),            )            .into_any()    }} #[cfg(any(test, feature = "test-support"))]impl ModuleList {    pub fn modules(&self, cx: &mut Context<Self>) -> Vec<dap::Module> {        self.session            .update(cx, |session, cx| session.modules(cx).to_vec())    }} impl Focusable for ModuleList {    fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle {        self.focus_handle.clone()    }} impl Render for ModuleList {    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {        if self.invalidate {            let len = self                .session                .update(cx, |session, cx| session.modules(cx).len());            self.list.reset(len);            self.invalidate = false;            cx.notify();        }         div()            .track_focus(&self.focus_handle)            .size_full()            .p_1()            .child(list(self.list.clone()).size_full())    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t