extension_slash_command.rs

 1use std::sync::{atomic::AtomicBool, Arc};
 2
 3use anyhow::{anyhow, Result};
 4use assistant_slash_command::{SlashCommand, SlashCommandOutput, SlashCommandOutputSection};
 5use futures::FutureExt;
 6use gpui::{AppContext, Task, WeakView, WindowContext};
 7use language::LspAdapterDelegate;
 8use ui::prelude::*;
 9use wasmtime_wasi::WasiView;
10use workspace::Workspace;
11
12use crate::wasm_host::{WasmExtension, WasmHost};
13
14pub struct ExtensionSlashCommand {
15    pub(crate) extension: WasmExtension,
16    #[allow(unused)]
17    pub(crate) host: Arc<WasmHost>,
18    pub(crate) command: crate::wit::SlashCommand,
19}
20
21impl SlashCommand for ExtensionSlashCommand {
22    fn name(&self) -> String {
23        self.command.name.clone()
24    }
25
26    fn description(&self) -> String {
27        self.command.description.clone()
28    }
29
30    fn menu_text(&self) -> String {
31        self.command.tooltip_text.clone()
32    }
33
34    fn requires_argument(&self) -> bool {
35        self.command.requires_argument
36    }
37
38    fn complete_argument(
39        &self,
40        _query: String,
41        _cancel: Arc<AtomicBool>,
42        _workspace: Option<WeakView<Workspace>>,
43        _cx: &mut AppContext,
44    ) -> Task<Result<Vec<String>>> {
45        Task::ready(Ok(Vec::new()))
46    }
47
48    fn run(
49        self: Arc<Self>,
50        argument: Option<&str>,
51        _workspace: WeakView<Workspace>,
52        delegate: Arc<dyn LspAdapterDelegate>,
53        cx: &mut WindowContext,
54    ) -> Task<Result<SlashCommandOutput>> {
55        let command_name = SharedString::from(self.command.name.clone());
56        let argument = argument.map(|arg| arg.to_string());
57        let text = cx.background_executor().spawn(async move {
58            let output = self
59                .extension
60                .call({
61                    let this = self.clone();
62                    move |extension, store| {
63                        async move {
64                            let resource = store.data_mut().table().push(delegate)?;
65                            let output = extension
66                                .call_run_slash_command(
67                                    store,
68                                    &this.command,
69                                    argument.as_deref(),
70                                    resource,
71                                )
72                                .await?
73                                .map_err(|e| anyhow!("{}", e))?;
74
75                            anyhow::Ok(output)
76                        }
77                        .boxed()
78                    }
79                })
80                .await?;
81            output.ok_or_else(|| anyhow!("no output from command: {}", self.command.name))
82        });
83        cx.foreground_executor().spawn(async move {
84            let text = text.await?;
85            let range = 0..text.len();
86            Ok(SlashCommandOutput {
87                text,
88                sections: vec![SlashCommandOutputSection {
89                    range,
90                    icon: IconName::Code,
91                    label: command_name,
92                }],
93                run_commands_in_text: false,
94            })
95        })
96    }
97}