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