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::{
  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}