1//! A source of tasks, based on ad-hoc user command prompt input.
2
3use std::sync::Arc;
4
5use crate::{SpawnInTerminal, Task, TaskContext, TaskId, TaskSource};
6use gpui::{AppContext, Context, Model};
7
8/// A storage and source of tasks generated out of user command prompt inputs.
9pub struct OneshotSource {
10 tasks: Vec<Arc<dyn Task>>,
11}
12
13#[derive(Clone)]
14struct OneshotTask {
15 id: TaskId,
16}
17
18impl OneshotTask {
19 fn new(prompt: String) -> Self {
20 Self { id: TaskId(prompt) }
21 }
22}
23
24impl Task for OneshotTask {
25 fn id(&self) -> &TaskId {
26 &self.id
27 }
28
29 fn name(&self) -> &str {
30 &self.id.0
31 }
32
33 fn cwd(&self) -> Option<&str> {
34 None
35 }
36
37 fn exec(&self, cx: TaskContext) -> Option<SpawnInTerminal> {
38 if self.id().0.is_empty() {
39 return None;
40 }
41 let TaskContext { cwd, env } = cx;
42 Some(SpawnInTerminal {
43 id: self.id().clone(),
44 label: self.name().to_owned(),
45 command: self.id().0.clone(),
46 args: vec![],
47 cwd,
48 env,
49 use_new_terminal: Default::default(),
50 allow_concurrent_runs: Default::default(),
51 })
52 }
53}
54
55impl OneshotSource {
56 /// Initializes the oneshot source, preparing to store user prompts.
57 pub fn new(cx: &mut AppContext) -> Model<Box<dyn TaskSource>> {
58 cx.new_model(|_| Box::new(Self { tasks: Vec::new() }) as Box<dyn TaskSource>)
59 }
60
61 /// Spawns a certain task based on the user prompt.
62 pub fn spawn(&mut self, prompt: String) -> Arc<dyn Task> {
63 let ret = Arc::new(OneshotTask::new(prompt));
64 self.tasks.push(ret.clone());
65 ret
66 }
67}
68
69impl TaskSource for OneshotSource {
70 fn as_any(&mut self) -> &mut dyn std::any::Any {
71 self
72 }
73
74 fn tasks_for_path(
75 &mut self,
76 _path: Option<&std::path::Path>,
77 _cx: &mut gpui::ModelContext<Box<dyn TaskSource>>,
78 ) -> Vec<Arc<dyn Task>> {
79 self.tasks.clone()
80 }
81}