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: Arc<Self>,
 40        query: String,
 41        _cancel: Arc<AtomicBool>,
 42        _workspace: Option<WeakView<Workspace>>,
 43        cx: &mut AppContext,
 44    ) -> Task<Result<Vec<String>>> {
 45        cx.background_executor().spawn(async move {
 46            self.extension
 47                .call({
 48                    let this = self.clone();
 49                    move |extension, store| {
 50                        async move {
 51                            let completions = extension
 52                                .call_complete_slash_command_argument(
 53                                    store,
 54                                    &this.command,
 55                                    query.as_ref(),
 56                                )
 57                                .await?
 58                                .map_err(|e| anyhow!("{}", e))?;
 59
 60                            anyhow::Ok(completions)
 61                        }
 62                        .boxed()
 63                    }
 64                })
 65                .await
 66        })
 67    }
 68
 69    fn run(
 70        self: Arc<Self>,
 71        argument: Option<&str>,
 72        _workspace: WeakView<Workspace>,
 73        delegate: Arc<dyn LspAdapterDelegate>,
 74        cx: &mut WindowContext,
 75    ) -> Task<Result<SlashCommandOutput>> {
 76        let argument = argument.map(|arg| arg.to_string());
 77        let output = cx.background_executor().spawn(async move {
 78            self.extension
 79                .call({
 80                    let this = self.clone();
 81                    move |extension, store| {
 82                        async move {
 83                            let resource = store.data_mut().table().push(delegate)?;
 84                            let output = extension
 85                                .call_run_slash_command(
 86                                    store,
 87                                    &this.command,
 88                                    argument.as_deref(),
 89                                    resource,
 90                                )
 91                                .await?
 92                                .map_err(|e| anyhow!("{}", e))?;
 93
 94                            anyhow::Ok(output)
 95                        }
 96                        .boxed()
 97                    }
 98                })
 99                .await
100        });
101        cx.foreground_executor().spawn(async move {
102            let output = output.await?;
103            Ok(SlashCommandOutput {
104                text: output.text,
105                sections: output
106                    .sections
107                    .into_iter()
108                    .map(|section| SlashCommandOutputSection {
109                        range: section.range.into(),
110                        icon: IconName::Code,
111                        label: section.label.into(),
112                    })
113                    .collect(),
114                run_commands_in_text: false,
115            })
116        })
117    }
118}