1use std::process::ExitStatus;
2
3use anyhow::{Result, anyhow};
4use gpui::{Context, Task};
5use project::TaskSourceKind;
6use remote::ConnectionState;
7use task::{DebugTaskDefinition, ResolvedTask, SpawnInTerminal, TaskContext, TaskTemplate};
8use ui::Window;
9
10use crate::Workspace;
11
12impl Workspace {
13 pub fn schedule_task(
14 self: &mut Workspace,
15 task_source_kind: TaskSourceKind,
16 task_to_resolve: &TaskTemplate,
17 task_cx: &TaskContext,
18 omit_history: bool,
19 window: &mut Window,
20 cx: &mut Context<Self>,
21 ) {
22 match self.project.read(cx).ssh_connection_state(cx) {
23 None | Some(ConnectionState::Connected) => {}
24 Some(
25 ConnectionState::Connecting
26 | ConnectionState::Disconnected
27 | ConnectionState::HeartbeatMissed
28 | ConnectionState::Reconnecting,
29 ) => {
30 log::warn!("Cannot schedule tasks when disconnected from a remote host");
31 return;
32 }
33 }
34
35 if let Some(spawn_in_terminal) =
36 task_to_resolve.resolve_task(&task_source_kind.to_id_base(), task_cx)
37 {
38 self.schedule_resolved_task(
39 task_source_kind,
40 spawn_in_terminal,
41 omit_history,
42 window,
43 cx,
44 );
45 }
46 }
47
48 pub fn schedule_resolved_task(
49 self: &mut Workspace,
50 task_source_kind: TaskSourceKind,
51 mut resolved_task: ResolvedTask,
52 omit_history: bool,
53 window: &mut Window,
54 cx: &mut Context<Workspace>,
55 ) {
56 if let Some(spawn_in_terminal) = resolved_task.resolved.take() {
57 if !omit_history {
58 resolved_task.resolved = Some(spawn_in_terminal.clone());
59 self.project().update(cx, |project, cx| {
60 if let Some(task_inventory) =
61 project.task_store().read(cx).task_inventory().cloned()
62 {
63 task_inventory.update(cx, |inventory, _| {
64 inventory.task_scheduled(task_source_kind, resolved_task);
65 })
66 }
67 });
68 }
69
70 if let Some(terminal_provider) = self.terminal_provider.as_ref() {
71 terminal_provider
72 .spawn(spawn_in_terminal, window, cx)
73 .detach_and_log_err(cx);
74 }
75 }
76 }
77
78 pub fn schedule_debug_task(
79 &mut self,
80 task: ResolvedTask,
81 window: &mut Window,
82 cx: &mut Context<Workspace>,
83 ) {
84 let Some(debug_config) = task.resolved_debug_adapter_config() else {
85 log::error!("Debug task has no debug adapter config");
86 return;
87 };
88
89 let project = self.project().clone();
90 cx.spawn_in(window, async move |workspace, cx| {
91 let config = if debug_config.locator.is_some() {
92 let task = workspace.update_in(cx, |workspace, window, cx| {
93 workspace.spawn_in_terminal(task.resolved.unwrap(), window, cx)
94 })?;
95
96 let exit_code = task.await?;
97 if !exit_code.success() {
98 return anyhow::Ok(());
99 }
100 let ret = project
101 .update(cx, |project, cx| {
102 project.dap_store().update(cx, |dap_store, cx| {
103 dap_store.run_debug_locator(debug_config, cx)
104 })
105 })?
106 .await?;
107 ret
108 } else {
109 debug_config.definition
110 };
111
112 workspace.update_in(cx, |workspace, window, cx| {
113 workspace.start_debug_session(config, window, cx);
114 })?;
115
116 anyhow::Ok(())
117 })
118 .detach_and_log_err(cx);
119 }
120
121 pub fn start_debug_session(
122 &mut self,
123 definition: DebugTaskDefinition,
124 window: &mut Window,
125 cx: &mut Context<Self>,
126 ) {
127 if let Some(provider) = self.debugger_provider.as_mut() {
128 provider.start_session(definition, window, cx)
129 }
130 }
131
132 pub fn spawn_in_terminal(
133 self: &mut Workspace,
134 spawn_in_terminal: SpawnInTerminal,
135 window: &mut Window,
136 cx: &mut Context<Workspace>,
137 ) -> Task<Result<ExitStatus>> {
138 if let Some(terminal_provider) = self.terminal_provider.as_ref() {
139 terminal_provider.spawn(spawn_in_terminal, window, cx)
140 } else {
141 Task::ready(Err(anyhow!("No terminal provider")))
142 }
143 }
144}