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}