extension_slash_command.rs

 1use std::sync::atomic::AtomicBool;
 2use std::sync::Arc;
 3
 4use anyhow::{anyhow, Result};
 5use assistant_slash_command::{SlashCommand, SlashCommandCleanup, SlashCommandInvocation};
 6use futures::channel::oneshot;
 7use futures::FutureExt;
 8use gpui::{AppContext, Task};
 9use language::LspAdapterDelegate;
10use wasmtime_wasi::WasiView;
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 requires_argument(&self) -> bool {
31        self.command.requires_argument
32    }
33
34    fn complete_argument(
35        &self,
36        _query: String,
37        _cancel: Arc<AtomicBool>,
38        _cx: &mut AppContext,
39    ) -> Task<Result<Vec<String>>> {
40        Task::ready(Ok(Vec::new()))
41    }
42
43    fn run(
44        self: Arc<Self>,
45        argument: Option<&str>,
46        delegate: Arc<dyn LspAdapterDelegate>,
47        cx: &mut AppContext,
48    ) -> SlashCommandInvocation {
49        let argument = argument.map(|arg| arg.to_string());
50
51        let output = cx.background_executor().spawn(async move {
52            let output = self
53                .extension
54                .call({
55                    let this = self.clone();
56                    move |extension, store| {
57                        async move {
58                            let resource = store.data_mut().table().push(delegate)?;
59                            let output = extension
60                                .call_run_slash_command(
61                                    store,
62                                    &this.command,
63                                    argument.as_deref(),
64                                    resource,
65                                )
66                                .await?
67                                .map_err(|e| anyhow!("{}", e))?;
68
69                            anyhow::Ok(output)
70                        }
71                        .boxed()
72                    }
73                })
74                .await?;
75
76            output.ok_or_else(|| anyhow!("no output from command: {}", self.command.name))
77        });
78
79        SlashCommandInvocation {
80            output,
81            invalidated: oneshot::channel().1,
82            cleanup: SlashCommandCleanup::default(),
83        }
84    }
85}