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