lib.rs

 1use std::path::PathBuf;
 2
 3use gpui::{AppContext, ViewContext, WindowContext};
 4use modal::RunnablesModal;
 5pub use oneshot_source::OneshotSource;
 6use runnable::Runnable;
 7use util::ResultExt;
 8use workspace::Workspace;
 9
10mod modal;
11mod oneshot_source;
12
13pub fn init(cx: &mut AppContext) {
14    cx.observe_new_views(
15        |workspace: &mut Workspace, _: &mut ViewContext<Workspace>| {
16            workspace
17                .register_action(|workspace, _: &modal::Spawn, cx| {
18                    let inventory = workspace.project().read(cx).runnable_inventory().clone();
19                    let workspace_handle = workspace.weak_handle();
20                    workspace.toggle_modal(cx, |cx| {
21                        RunnablesModal::new(inventory, workspace_handle, cx)
22                    })
23                })
24                .register_action(move |workspace, _: &modal::Rerun, cx| {
25                    if let Some(runnable) = workspace.project().update(cx, |project, cx| {
26                        project
27                            .runnable_inventory()
28                            .update(cx, |inventory, cx| inventory.last_scheduled_runnable(cx))
29                    }) {
30                        schedule_runnable(workspace, runnable.as_ref(), cx)
31                    };
32                });
33        },
34    )
35    .detach();
36}
37
38fn schedule_runnable(
39    workspace: &Workspace,
40    runnable: &dyn Runnable,
41    cx: &mut ViewContext<'_, Workspace>,
42) {
43    let cwd = match runnable.cwd() {
44        Some(cwd) => Some(cwd.to_path_buf()),
45        None => runnable_cwd(workspace, cx).log_err().flatten(),
46    };
47    let spawn_in_terminal = runnable.exec(cwd);
48    if let Some(spawn_in_terminal) = spawn_in_terminal {
49        workspace.project().update(cx, |project, cx| {
50            project.runnable_inventory().update(cx, |inventory, _| {
51                inventory.last_scheduled_runnable = Some(runnable.id().clone());
52            })
53        });
54        cx.emit(workspace::Event::SpawnRunnable(spawn_in_terminal));
55    }
56}
57
58fn runnable_cwd(workspace: &Workspace, cx: &mut WindowContext) -> anyhow::Result<Option<PathBuf>> {
59    let project = workspace.project().read(cx);
60    let available_worktrees = project
61        .worktrees()
62        .filter(|worktree| {
63            let worktree = worktree.read(cx);
64            worktree.is_visible()
65                && worktree.is_local()
66                && worktree.root_entry().map_or(false, |e| e.is_dir())
67        })
68        .collect::<Vec<_>>();
69    let cwd = match available_worktrees.len() {
70        0 => None,
71        1 => Some(available_worktrees[0].read(cx).abs_path()),
72        _ => {
73            let cwd_for_active_entry = project.active_entry().and_then(|entry_id| {
74                available_worktrees.into_iter().find_map(|worktree| {
75                    let worktree = worktree.read(cx);
76                    if worktree.contains_entry(entry_id) {
77                        Some(worktree.abs_path())
78                    } else {
79                        None
80                    }
81                })
82            });
83            anyhow::ensure!(
84                cwd_for_active_entry.is_some(),
85                "Cannot determine runnable cwd for multiple worktrees"
86            );
87            cwd_for_active_entry
88        }
89    };
90    Ok(cwd.map(|path| path.to_path_buf()))
91}