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