extension_slash_command.rs

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