extension_slash_command.rs

  1use std::sync::{atomic::AtomicBool, Arc};
  2
  3use anyhow::{anyhow, Result};
  4use assistant_slash_command::{
  5    ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection,
  6};
  7use futures::FutureExt;
  8use gpui::{Task, WeakView, WindowContext};
  9use language::LspAdapterDelegate;
 10use ui::prelude::*;
 11use wasmtime_wasi::WasiView;
 12use workspace::Workspace;
 13
 14use crate::wasm_host::{WasmExtension, WasmHost};
 15
 16pub struct ExtensionSlashCommand {
 17    pub(crate) extension: WasmExtension,
 18    #[allow(unused)]
 19    pub(crate) host: Arc<WasmHost>,
 20    pub(crate) command: crate::wit::SlashCommand,
 21}
 22
 23impl SlashCommand for ExtensionSlashCommand {
 24    fn name(&self) -> String {
 25        self.command.name.clone()
 26    }
 27
 28    fn description(&self) -> String {
 29        self.command.description.clone()
 30    }
 31
 32    fn menu_text(&self) -> String {
 33        self.command.tooltip_text.clone()
 34    }
 35
 36    fn requires_argument(&self) -> bool {
 37        self.command.requires_argument
 38    }
 39
 40    fn complete_argument(
 41        self: Arc<Self>,
 42        arguments: &[String],
 43        _cancel: Arc<AtomicBool>,
 44        _workspace: Option<WeakView<Workspace>>,
 45        cx: &mut WindowContext,
 46    ) -> Task<Result<Vec<ArgumentCompletion>>> {
 47        let arguments = arguments.to_owned();
 48        cx.background_executor().spawn(async move {
 49            self.extension
 50                .call({
 51                    let this = self.clone();
 52                    move |extension, store| {
 53                        async move {
 54                            let completions = extension
 55                                .call_complete_slash_command_argument(
 56                                    store,
 57                                    &this.command,
 58                                    &arguments,
 59                                )
 60                                .await?
 61                                .map_err(|e| anyhow!("{}", e))?;
 62
 63                            anyhow::Ok(
 64                                completions
 65                                    .into_iter()
 66                                    .map(|completion| ArgumentCompletion {
 67                                        label: completion.label.into(),
 68                                        new_text: completion.new_text,
 69                                        run_command: completion.run_command,
 70                                    })
 71                                    .collect(),
 72                            )
 73                        }
 74                        .boxed()
 75                    }
 76                })
 77                .await
 78        })
 79    }
 80
 81    fn run(
 82        self: Arc<Self>,
 83        arguments: &[String],
 84        _workspace: WeakView<Workspace>,
 85        delegate: Option<Arc<dyn LspAdapterDelegate>>,
 86        cx: &mut WindowContext,
 87    ) -> Task<Result<SlashCommandOutput>> {
 88        let arguments = arguments.to_owned();
 89        let output = cx.background_executor().spawn(async move {
 90            self.extension
 91                .call({
 92                    let this = self.clone();
 93                    move |extension, store| {
 94                        async move {
 95                            let resource = if let Some(delegate) = delegate {
 96                                Some(store.data_mut().table().push(delegate)?)
 97                            } else {
 98                                None
 99                            };
100                            let output = extension
101                                .call_run_slash_command(store, &this.command, &arguments, resource)
102                                .await?
103                                .map_err(|e| anyhow!("{}", e))?;
104
105                            anyhow::Ok(output)
106                        }
107                        .boxed()
108                    }
109                })
110                .await
111        });
112        cx.foreground_executor().spawn(async move {
113            let output = output.await?;
114            Ok(SlashCommandOutput {
115                text: output.text,
116                sections: output
117                    .sections
118                    .into_iter()
119                    .map(|section| SlashCommandOutputSection {
120                        range: section.range.into(),
121                        icon: IconName::Code,
122                        label: section.label.into(),
123                    })
124                    .collect(),
125                run_commands_in_text: false,
126            })
127        })
128    }
129}