slash_command_working_set.rs

 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}