slash_command_working_set.rs

 1use assistant_slash_command::{SlashCommand, SlashCommandRegistry};
 2use collections::HashMap;
 3use gpui::AppContext;
 4use parking_lot::Mutex;
 5use std::sync::Arc;
 6
 7#[derive(Debug, 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<Arc<str>, 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 command_names(&self, cx: &AppContext) -> Vec<Arc<str>> {
34        let mut command_names = SlashCommandRegistry::global(cx).command_names();
35        command_names.extend(
36            self.state
37                .lock()
38                .context_server_commands_by_name
39                .keys()
40                .cloned(),
41        );
42
43        command_names
44    }
45
46    pub fn featured_command_names(&self, cx: &AppContext) -> Vec<Arc<str>> {
47        SlashCommandRegistry::global(cx).featured_command_names()
48    }
49
50    pub fn insert(&self, command: Arc<dyn SlashCommand>) -> SlashCommandId {
51        let mut state = self.state.lock();
52        let command_id = state.next_command_id;
53        state.next_command_id.0 += 1;
54        state
55            .context_server_commands_by_id
56            .insert(command_id, command.clone());
57        state.slash_commands_changed();
58        command_id
59    }
60
61    pub fn remove(&self, command_ids_to_remove: &[SlashCommandId]) {
62        let mut state = self.state.lock();
63        state
64            .context_server_commands_by_id
65            .retain(|id, _| !command_ids_to_remove.contains(id));
66        state.slash_commands_changed();
67    }
68}
69
70impl WorkingSetState {
71    fn slash_commands_changed(&mut self) {
72        self.context_server_commands_by_name.clear();
73        self.context_server_commands_by_name.extend(
74            self.context_server_commands_by_id
75                .values()
76                .map(|command| (command.name().into(), command.clone())),
77        );
78    }
79}