assistant_slash_command.rs

 1mod slash_command_registry;
 2
 3use std::sync::atomic::AtomicBool;
 4use std::sync::Arc;
 5
 6use anyhow::Result;
 7use futures::channel::oneshot;
 8use gpui::{AppContext, Task};
 9use language::LspAdapterDelegate;
10
11pub use slash_command_registry::*;
12
13pub fn init(cx: &mut AppContext) {
14    SlashCommandRegistry::default_global(cx);
15}
16
17pub trait SlashCommand: 'static + Send + Sync {
18    fn name(&self) -> String;
19    fn description(&self) -> String;
20    fn complete_argument(
21        &self,
22        query: String,
23        cancel: Arc<AtomicBool>,
24        cx: &mut AppContext,
25    ) -> Task<Result<Vec<String>>>;
26    fn requires_argument(&self) -> bool;
27    fn run(
28        self: Arc<Self>,
29        argument: Option<&str>,
30        // TODO: We're just using the `LspAdapterDelegate` here because that is
31        // what the extension API is already expecting.
32        //
33        // It may be that `LspAdapterDelegate` needs a more general name, or
34        // perhaps another kind of delegate is needed here.
35        delegate: Arc<dyn LspAdapterDelegate>,
36        cx: &mut AppContext,
37    ) -> SlashCommandInvocation;
38}
39
40pub struct SlashCommandInvocation {
41    pub output: Task<Result<String>>,
42    pub invalidated: oneshot::Receiver<()>,
43    pub cleanup: SlashCommandCleanup,
44}
45
46#[derive(Default)]
47pub struct SlashCommandCleanup(Option<Box<dyn FnOnce()>>);
48
49impl SlashCommandCleanup {
50    pub fn new(cleanup: impl FnOnce() + 'static) -> Self {
51        Self(Some(Box::new(cleanup)))
52    }
53}
54
55impl Drop for SlashCommandCleanup {
56    fn drop(&mut self) {
57        if let Some(cleanup) = self.0.take() {
58            cleanup();
59        }
60    }
61}