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