1use std::process::ExitStatus;
2
3use anyhow::{Context as _, Result};
4use gpui::{AppContext, 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 let task_status = terminal_provider.spawn(spawn_in_terminal, window, cx);
72 cx.background_spawn(async move {
73 match task_status.await {
74 Some(Ok(status)) => {
75 if status.success() {
76 log::debug!("Task spawn succeeded");
77 } else {
78 log::debug!("Task spawn failed, code: {:?}", status.code());
79 }
80 }
81 Some(Err(e)) => log::error!("Task spawn failed: {e}"),
82 None => log::debug!("Task spawn got cancelled"),
83 }
84 })
85 .detach();
86 }
87 }
88 }
89
90 pub fn schedule_debug_task(
91 &mut self,
92 task: ResolvedTask,
93 window: &mut Window,
94 cx: &mut Context<Workspace>,
95 ) {
96 let Some(debug_config) = task.resolved_debug_adapter_config() else {
97 log::error!("Debug task has no debug adapter config");
98 return;
99 };
100
101 let project = self.project().clone();
102 cx.spawn_in(window, async move |workspace, cx| {
103 let config = if debug_config.locator.is_some() {
104 let task = workspace.update_in(cx, |workspace, window, cx| {
105 workspace.spawn_in_terminal(task.resolved.unwrap(), window, cx)
106 })?;
107
108 let exit_code = task.await.transpose()?.context("task cancelled")?;
109 if !exit_code.success() {
110 return anyhow::Ok(());
111 }
112 let ret = project
113 .update(cx, |project, cx| {
114 project.dap_store().update(cx, |dap_store, cx| {
115 dap_store.run_debug_locator(debug_config, cx)
116 })
117 })?
118 .await?;
119 ret
120 } else {
121 debug_config.definition
122 };
123
124 workspace.update_in(cx, |workspace, window, cx| {
125 workspace.start_debug_session(config, window, cx);
126 })?;
127
128 anyhow::Ok(())
129 })
130 .detach_and_log_err(cx);
131 }
132
133 pub fn start_debug_session(
134 &mut self,
135 definition: DebugTaskDefinition,
136 window: &mut Window,
137 cx: &mut Context<Self>,
138 ) {
139 if let Some(provider) = self.debugger_provider.as_mut() {
140 provider.start_session(definition, window, cx)
141 }
142 }
143
144 pub fn spawn_in_terminal(
145 self: &mut Workspace,
146 spawn_in_terminal: SpawnInTerminal,
147 window: &mut Window,
148 cx: &mut Context<Workspace>,
149 ) -> Task<Option<Result<ExitStatus>>> {
150 if let Some(terminal_provider) = self.terminal_provider.as_ref() {
151 terminal_provider.spawn(spawn_in_terminal, window, cx)
152 } else {
153 Task::ready(None)
154 }
155 }
156}