1use std::sync::Arc;
2
3use collections::HashMap;
4use derive_more::{Deref, DerefMut};
5use gpui::Global;
6use gpui::{AppContext, ReadGlobal};
7use parking_lot::RwLock;
8
9use crate::SlashCommand;
10
11#[derive(Default, Deref, DerefMut)]
12struct GlobalSlashCommandRegistry(Arc<SlashCommandRegistry>);
13
14impl Global for GlobalSlashCommandRegistry {}
15
16#[derive(Default)]
17struct SlashCommandRegistryState {
18 commands: HashMap<Arc<str>, Arc<dyn SlashCommand>>,
19}
20
21#[derive(Default)]
22pub struct SlashCommandRegistry {
23 state: RwLock<SlashCommandRegistryState>,
24}
25
26impl SlashCommandRegistry {
27 /// Returns the global [`SlashCommandRegistry`].
28 pub fn global(cx: &AppContext) -> Arc<Self> {
29 GlobalSlashCommandRegistry::global(cx).0.clone()
30 }
31
32 /// Returns the global [`SlashCommandRegistry`].
33 ///
34 /// Inserts a default [`SlashCommandRegistry`] if one does not yet exist.
35 pub fn default_global(cx: &mut AppContext) -> Arc<Self> {
36 cx.default_global::<GlobalSlashCommandRegistry>().0.clone()
37 }
38
39 pub fn new() -> Arc<Self> {
40 Arc::new(Self {
41 state: RwLock::new(SlashCommandRegistryState {
42 commands: HashMap::default(),
43 }),
44 })
45 }
46
47 /// Registers the provided [`SlashCommand`].
48 pub fn register_command(&self, command: impl SlashCommand) {
49 self.state
50 .write()
51 .commands
52 .insert(command.name().into(), Arc::new(command));
53 }
54
55 /// Returns the names of registered [`SlashCommand`]s.
56 pub fn command_names(&self) -> Vec<Arc<str>> {
57 self.state.read().commands.keys().cloned().collect()
58 }
59
60 /// Returns the [`SlashCommand`] with the given name.
61 pub fn command(&self, name: &str) -> Option<Arc<dyn SlashCommand>> {
62 self.state.read().commands.get(name).cloned()
63 }
64}