diff --git a/assets/settings/default.json b/assets/settings/default.json index 007eba7d17..1648237d2d 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -400,6 +400,19 @@ "model": "gpt-4o" } }, + // The settings for slash commands. + "slash_commands": { + // Settings for the `/docs` slash command. + "docs": { + // Whether `/docs` is enabled. + "enabled": false + }, + // Settings for the `/project` slash command. + "project": { + // Whether `/project` is enabled. + "enabled": false + } + }, // Whether the screen sharing icon is shown in the os status bar. "show_call_status_icon": true, // Whether to use language servers to provide code intelligence. diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index 34b0e5cfd4..3e4bcac69d 100644 --- a/crates/assistant/src/assistant.rs +++ b/crates/assistant/src/assistant.rs @@ -10,6 +10,7 @@ mod model_selector; mod prompt_library; mod prompts; mod slash_command; +pub mod slash_command_settings; mod streaming_diff; mod terminal_inline_assistant; @@ -43,6 +44,8 @@ use std::sync::Arc; pub(crate) use streaming_diff::*; use util::ResultExt; +use crate::slash_command_settings::SlashCommandSettings; + actions!( assistant, [ @@ -177,6 +180,7 @@ pub fn init( ) -> Arc { cx.set_global(Assistant::default()); AssistantSettings::register(cx); + SlashCommandSettings::register(cx); // TODO: remove this when 0.148.0 is released. if AssistantSettings::get_global(cx).using_outdated_settings_version { @@ -290,6 +294,7 @@ fn register_slash_commands(prompt_builder: Option>, cx: &mut slash_command_registry.register_command(terminal_command::TerminalSlashCommand, true); slash_command_registry.register_command(now_command::NowSlashCommand, false); slash_command_registry.register_command(diagnostics_command::DiagnosticsSlashCommand, true); + if let Some(prompt_builder) = prompt_builder { slash_command_registry.register_command( workflow_command::WorkflowSlashCommand::new(prompt_builder), @@ -298,15 +303,10 @@ fn register_slash_commands(prompt_builder: Option>, cx: &mut } slash_command_registry.register_command(fetch_command::FetchSlashCommand, false); - cx.observe_flag::({ - let slash_command_registry = slash_command_registry.clone(); - move |is_enabled, _cx| { - if is_enabled { - slash_command_registry.register_command(docs_command::DocsSlashCommand, true); - } - } - }) - .detach(); + update_slash_commands_from_settings(cx); + cx.observe_global::(update_slash_commands_from_settings) + .detach(); + cx.observe_flag::({ let slash_command_registry = slash_command_registry.clone(); move |is_enabled, _cx| { @@ -318,6 +318,23 @@ fn register_slash_commands(prompt_builder: Option>, cx: &mut .detach(); } +fn update_slash_commands_from_settings(cx: &mut AppContext) { + let slash_command_registry = SlashCommandRegistry::global(cx); + let settings = SlashCommandSettings::get_global(cx); + + if settings.docs.enabled { + slash_command_registry.register_command(docs_command::DocsSlashCommand, true); + } else { + slash_command_registry.unregister_command(docs_command::DocsSlashCommand); + } + + if settings.project.enabled { + slash_command_registry.register_command(project_command::ProjectSlashCommand, true); + } else { + slash_command_registry.unregister_command(project_command::ProjectSlashCommand); + } +} + pub fn humanize_token_count(count: usize) -> String { match count { 0..=999 => count.to_string(), diff --git a/crates/assistant/src/slash_command/docs_command.rs b/crates/assistant/src/slash_command/docs_command.rs index f13842b834..fc959a05ac 100644 --- a/crates/assistant/src/slash_command/docs_command.rs +++ b/crates/assistant/src/slash_command/docs_command.rs @@ -7,7 +7,6 @@ use anyhow::{anyhow, bail, Result}; use assistant_slash_command::{ ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection, }; -use feature_flags::FeatureFlag; use gpui::{AppContext, BackgroundExecutor, Model, Task, WeakView}; use indexed_docs::{ DocsDotRsProvider, IndexedDocsRegistry, IndexedDocsStore, LocalRustdocProvider, PackageName, @@ -19,12 +18,6 @@ use ui::prelude::*; use util::{maybe, ResultExt}; use workspace::Workspace; -pub(crate) struct DocsSlashCommandFeatureFlag; - -impl FeatureFlag for DocsSlashCommandFeatureFlag { - const NAME: &'static str = "docs-slash-command"; -} - pub(crate) struct DocsSlashCommand; impl DocsSlashCommand { diff --git a/crates/assistant/src/slash_command_settings.rs b/crates/assistant/src/slash_command_settings.rs new file mode 100644 index 0000000000..eda950b6a2 --- /dev/null +++ b/crates/assistant/src/slash_command_settings.rs @@ -0,0 +1,44 @@ +use anyhow::Result; +use gpui::AppContext; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use settings::{Settings, SettingsSources}; + +/// Settings for slash commands. +#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)] +pub struct SlashCommandSettings { + /// Settings for the `/docs` slash command. + #[serde(default)] + pub docs: DocsCommandSettings, + /// Settings for the `/project` slash command. + #[serde(default)] + pub project: ProjectCommandSettings, +} + +/// Settings for the `/docs` slash command. +#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)] +pub struct DocsCommandSettings { + /// Whether `/docs` is enabled. + #[serde(default)] + pub enabled: bool, +} + +/// Settings for the `/project` slash command. +#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)] +pub struct ProjectCommandSettings { + /// Whether `/project` is enabled. + #[serde(default)] + pub enabled: bool, +} + +impl Settings for SlashCommandSettings { + const KEY: Option<&'static str> = Some("slash_commands"); + + type FileContent = Self; + + fn load(sources: SettingsSources, _cx: &mut AppContext) -> Result { + SettingsSources::::json_merge_with( + [sources.default].into_iter().chain(sources.user), + ) + } +} diff --git a/crates/assistant_slash_command/src/slash_command_registry.rs b/crates/assistant_slash_command/src/slash_command_registry.rs index 070e60bc6b..f0afc60234 100644 --- a/crates/assistant_slash_command/src/slash_command_registry.rs +++ b/crates/assistant_slash_command/src/slash_command_registry.rs @@ -56,6 +56,14 @@ impl SlashCommandRegistry { state.commands.insert(command_name, Arc::new(command)); } + /// Unregisters the provided [`SlashCommand`]. + pub fn unregister_command(&self, command: impl SlashCommand) { + let mut state = self.state.write(); + let command_name: Arc = command.name().into(); + state.featured_commands.remove(&command_name); + state.commands.remove(&command_name); + } + /// Returns the names of registered [`SlashCommand`]s. pub fn command_names(&self) -> Vec> { self.state.read().commands.keys().cloned().collect()