tasks.rs

  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}