1use std::sync::Arc;
2
3use collections::HashMap;
4use gpui::App;
5use parking_lot::Mutex;
6
7use crate::{SlashCommand, SlashCommandRegistry};
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Default)]
10pub struct SlashCommandId(usize);
11
12/// A working set of slash commands for use in one instance of the Assistant Panel.
13#[derive(Default)]
14pub struct SlashCommandWorkingSet {
15 state: Mutex<WorkingSetState>,
16}
17
18#[derive(Default)]
19struct WorkingSetState {
20 context_server_commands_by_id: HashMap<SlashCommandId, Arc<dyn SlashCommand>>,
21 context_server_commands_by_name: HashMap<Arc<str>, Arc<dyn SlashCommand>>,
22 next_command_id: SlashCommandId,
23}
24
25impl SlashCommandWorkingSet {
26 pub fn command(&self, name: &str, cx: &App) -> Option<Arc<dyn SlashCommand>> {
27 self.state
28 .lock()
29 .context_server_commands_by_name
30 .get(name)
31 .cloned()
32 .or_else(|| SlashCommandRegistry::global(cx).command(name))
33 }
34
35 pub fn command_names(&self, cx: &App) -> Vec<Arc<str>> {
36 let mut command_names = SlashCommandRegistry::global(cx).command_names();
37 command_names.extend(
38 self.state
39 .lock()
40 .context_server_commands_by_name
41 .keys()
42 .cloned(),
43 );
44
45 command_names
46 }
47
48 pub fn featured_command_names(&self, cx: &App) -> Vec<Arc<str>> {
49 SlashCommandRegistry::global(cx).featured_command_names()
50 }
51
52 pub fn insert(&self, command: Arc<dyn SlashCommand>) -> SlashCommandId {
53 let mut state = self.state.lock();
54 let command_id = state.next_command_id;
55 state.next_command_id.0 += 1;
56 state
57 .context_server_commands_by_id
58 .insert(command_id, command.clone());
59 state.slash_commands_changed();
60 command_id
61 }
62
63 pub fn remove(&self, command_ids_to_remove: &[SlashCommandId]) {
64 let mut state = self.state.lock();
65 state
66 .context_server_commands_by_id
67 .retain(|id, _| !command_ids_to_remove.contains(id));
68 state.slash_commands_changed();
69 }
70}
71
72impl WorkingSetState {
73 fn slash_commands_changed(&mut self) {
74 self.context_server_commands_by_name.clear();
75 self.context_server_commands_by_name.extend(
76 self.context_server_commands_by_id
77 .values()
78 .map(|command| (command.name().into(), command.clone())),
79 );
80 }
81}