1use std::process::ExitStatus;
2
3use anyhow::Result;
4use gpui::{AppContext, Context, Entity, Task};
5use language::Buffer;
6use project::{TaskSourceKind, WorktreeId};
7use remote::ConnectionState;
8use task::{DebugScenario, ResolvedTask, SpawnInTerminal, TaskContext, TaskTemplate};
9use ui::Window;
10
11use crate::{Toast, Workspace, notifications::NotificationId};
12
13impl Workspace {
14 pub fn schedule_task(
15 self: &mut Workspace,
16 task_source_kind: TaskSourceKind,
17 task_to_resolve: &TaskTemplate,
18 task_cx: &TaskContext,
19 omit_history: bool,
20 window: &mut Window,
21 cx: &mut Context<Self>,
22 ) {
23 let project = self.project.read(cx);
24 match project.remote_connection_state(cx) {
25 None | Some(ConnectionState::Connected) => {}
26 Some(
27 ConnectionState::Connecting
28 | ConnectionState::Disconnected
29 | ConnectionState::HeartbeatMissed
30 | ConnectionState::Reconnecting,
31 ) => {
32 log::warn!("Cannot schedule tasks when disconnected from a remote host");
33 return;
34 }
35 }
36
37 if let Some(spawn_in_terminal) = task_to_resolve.resolve_task(
38 &task_source_kind.to_id_base(),
39 &|| project.remote_client()?.read(cx).shell(),
40 task_cx,
41 ) {
42 self.schedule_resolved_task(
43 task_source_kind,
44 spawn_in_terminal,
45 omit_history,
46 window,
47 cx,
48 );
49 }
50 }
51
52 pub fn schedule_resolved_task(
53 self: &mut Workspace,
54 task_source_kind: TaskSourceKind,
55 resolved_task: ResolvedTask,
56 omit_history: bool,
57 window: &mut Window,
58 cx: &mut Context<Workspace>,
59 ) {
60 let spawn_in_terminal = resolved_task.resolved.clone();
61 if !omit_history {
62 if let Some(debugger_provider) = self.debugger_provider.as_ref() {
63 debugger_provider.task_scheduled(cx);
64 }
65
66 self.project().update(cx, |project, cx| {
67 if let Some(task_inventory) =
68 project.task_store().read(cx).task_inventory().cloned()
69 {
70 task_inventory.update(cx, |inventory, _| {
71 inventory.task_scheduled(task_source_kind, resolved_task);
72 })
73 }
74 });
75 }
76
77 if let Some(terminal_provider) = self.terminal_provider.as_ref() {
78 let task_status = terminal_provider.spawn(spawn_in_terminal, window, cx);
79
80 let task = cx.spawn(async |w, cx| {
81 let res = cx.background_spawn(task_status).await;
82 match res {
83 Some(Ok(status)) => {
84 if status.success() {
85 log::debug!("Task spawn succeeded");
86 } else {
87 log::debug!("Task spawn failed, code: {:?}", status.code());
88 }
89 }
90 Some(Err(e)) => {
91 log::error!("Task spawn failed: {e:#}");
92 _ = w.update(cx, |w, cx| {
93 let id = NotificationId::unique::<ResolvedTask>();
94 w.show_toast(Toast::new(id, format!("Task spawn failed: {e}")), cx);
95 })
96 }
97 None => log::debug!("Task spawn got cancelled"),
98 };
99 });
100 self.scheduled_tasks.push(task);
101 }
102 }
103
104 pub fn start_debug_session(
105 &mut self,
106 scenario: DebugScenario,
107 task_context: TaskContext,
108 active_buffer: Option<Entity<Buffer>>,
109 worktree_id: Option<WorktreeId>,
110 window: &mut Window,
111 cx: &mut Context<Self>,
112 ) {
113 if let Some(provider) = self.debugger_provider.as_mut() {
114 provider.start_session(
115 scenario,
116 task_context,
117 active_buffer,
118 worktree_id,
119 window,
120 cx,
121 )
122 }
123 }
124
125 pub fn spawn_in_terminal(
126 self: &mut Workspace,
127 spawn_in_terminal: SpawnInTerminal,
128 window: &mut Window,
129 cx: &mut Context<Workspace>,
130 ) -> Task<Option<Result<ExitStatus>>> {
131 if let Some(terminal_provider) = self.terminal_provider.as_ref() {
132 terminal_provider.spawn(spawn_in_terminal, window, cx)
133 } else {
134 Task::ready(None)
135 }
136 }
137}