Remove `/cargo-workspace` slash command (#38354)

Marshall Bowers created

This PR removes the `/cargo-workspace` slash command.

We never fully shipped this—with it requiring explicit opt-in via a
setting—and it doesn't seem like the feature is needed in an agentic
world.

Release Notes:

- Removed the `/cargo-workspace` slash command.

Change summary

Cargo.lock                                                      |   2 
assets/settings/default.json                                    |   8 
crates/agent_ui/src/agent_ui.rs                                 |  22 
crates/agent_ui/src/slash_command_settings.rs                   |  37 
crates/assistant_slash_commands/Cargo.toml                      |   2 
crates/assistant_slash_commands/src/assistant_slash_commands.rs |   2 
crates/assistant_slash_commands/src/cargo_workspace_command.rs  | 158 ---
7 files changed, 231 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -901,7 +901,6 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "assistant_slash_command",
- "cargo_toml",
  "chrono",
  "collections",
  "context_server",
@@ -924,7 +923,6 @@ dependencies = [
  "settings",
  "smol",
  "text",
- "toml 0.8.20",
  "ui",
  "util",
  "workspace",

assets/settings/default.json 🔗

@@ -920,14 +920,6 @@
     // Default: 4
     "message_editor_min_lines": 4
   },
-  // The settings for slash commands.
-  "slash_commands": {
-    // 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.

crates/agent_ui/src/agent_ui.rs 🔗

@@ -14,7 +14,6 @@ mod message_editor;
 mod profile_selector;
 mod slash_command;
 mod slash_command_picker;
-mod slash_command_settings;
 mod terminal_codegen;
 mod terminal_inline_assistant;
 mod text_thread_editor;
@@ -46,7 +45,6 @@ use std::any::TypeId;
 use crate::agent_configuration::{ConfigureContextServerModal, ManageProfilesModal};
 pub use crate::agent_panel::{AgentPanel, ConcreteAssistantPanelDelegate};
 pub use crate::inline_assistant::InlineAssistant;
-use crate::slash_command_settings::SlashCommandSettings;
 pub use agent_diff::{AgentDiffPane, AgentDiffToolbar};
 pub use text_thread_editor::{AgentPanelDelegate, TextThreadEditor};
 use zed_actions;
@@ -257,7 +255,6 @@ pub fn init(
     cx: &mut App,
 ) {
     AgentSettings::register(cx);
-    SlashCommandSettings::register(cx);
 
     assistant_context::init(client.clone(), cx);
     rules_library::init(cx);
@@ -413,8 +410,6 @@ fn register_slash_commands(cx: &mut App) {
     slash_command_registry.register_command(assistant_slash_commands::DeltaSlashCommand, true);
     slash_command_registry.register_command(assistant_slash_commands::OutlineSlashCommand, true);
     slash_command_registry.register_command(assistant_slash_commands::TabSlashCommand, true);
-    slash_command_registry
-        .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
     slash_command_registry.register_command(assistant_slash_commands::PromptSlashCommand, true);
     slash_command_registry.register_command(assistant_slash_commands::SelectionCommand, true);
     slash_command_registry.register_command(assistant_slash_commands::DefaultSlashCommand, false);
@@ -434,21 +429,4 @@ fn register_slash_commands(cx: &mut App) {
         }
     })
     .detach();
-
-    update_slash_commands_from_settings(cx);
-    cx.observe_global::<SettingsStore>(update_slash_commands_from_settings)
-        .detach();
-}
-
-fn update_slash_commands_from_settings(cx: &mut App) {
-    let slash_command_registry = SlashCommandRegistry::global(cx);
-    let settings = SlashCommandSettings::get_global(cx);
-
-    if settings.cargo_workspace.enabled {
-        slash_command_registry
-            .register_command(assistant_slash_commands::CargoWorkspaceSlashCommand, true);
-    } else {
-        slash_command_registry
-            .unregister_command(assistant_slash_commands::CargoWorkspaceSlashCommand);
-    }
 }

crates/agent_ui/src/slash_command_settings.rs 🔗

@@ -1,37 +0,0 @@
-use anyhow::Result;
-use gpui::App;
-use schemars::JsonSchema;
-use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
-
-/// Settings for slash commands.
-#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema, SettingsUi, SettingsKey)]
-#[settings_key(key = "slash_commands")]
-pub struct SlashCommandSettings {
-    /// Settings for the `/cargo-workspace` slash command.
-    #[serde(default)]
-    pub cargo_workspace: CargoWorkspaceCommandSettings,
-}
-
-/// Settings for the `/cargo-workspace` slash command.
-#[derive(Deserialize, Serialize, Debug, Default, Clone, JsonSchema)]
-pub struct CargoWorkspaceCommandSettings {
-    /// Whether `/cargo-workspace` is enabled.
-    #[serde(default)]
-    pub enabled: bool,
-}
-
-impl Settings for SlashCommandSettings {
-    type FileContent = Self;
-
-    fn load(sources: SettingsSources<Self::FileContent>, _cx: &mut App) -> Result<Self> {
-        SettingsSources::<Self::FileContent>::json_merge_with(
-            [sources.default]
-                .into_iter()
-                .chain(sources.user)
-                .chain(sources.server),
-        )
-    }
-
-    fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
-}

crates/assistant_slash_commands/Cargo.toml 🔗

@@ -14,7 +14,6 @@ path = "src/assistant_slash_commands.rs"
 [dependencies]
 anyhow.workspace = true
 assistant_slash_command.workspace = true
-cargo_toml.workspace = true
 chrono.workspace = true
 collections.workspace = true
 context_server.workspace = true
@@ -35,7 +34,6 @@ serde.workspace = true
 serde_json.workspace = true
 smol.workspace = true
 text.workspace = true
-toml.workspace = true
 ui.workspace = true
 util.workspace = true
 workspace.workspace = true

crates/assistant_slash_commands/src/assistant_slash_commands.rs 🔗

@@ -1,4 +1,3 @@
-mod cargo_workspace_command;
 mod context_server_command;
 mod default_command;
 mod delta_command;
@@ -12,7 +11,6 @@ mod streaming_example_command;
 mod symbols_command;
 mod tab_command;
 
-pub use crate::cargo_workspace_command::*;
 pub use crate::context_server_command::*;
 pub use crate::default_command::*;
 pub use crate::delta_command::*;

crates/assistant_slash_commands/src/cargo_workspace_command.rs 🔗

@@ -1,158 +0,0 @@
-use anyhow::{Context as _, Result, anyhow};
-use assistant_slash_command::{
-    ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection,
-    SlashCommandResult,
-};
-use fs::Fs;
-use gpui::{App, Entity, Task, WeakEntity};
-use language::{BufferSnapshot, LspAdapterDelegate};
-use project::{Project, ProjectPath};
-use std::{
-    fmt::Write,
-    path::Path,
-    sync::{Arc, atomic::AtomicBool},
-};
-use ui::prelude::*;
-use workspace::Workspace;
-
-pub struct CargoWorkspaceSlashCommand;
-
-impl CargoWorkspaceSlashCommand {
-    async fn build_message(fs: Arc<dyn Fs>, path_to_cargo_toml: &Path) -> Result<String> {
-        let buffer = fs.load(path_to_cargo_toml).await?;
-        let cargo_toml: cargo_toml::Manifest = toml::from_str(&buffer)?;
-
-        let mut message = String::new();
-        writeln!(message, "You are in a Rust project.")?;
-
-        if let Some(workspace) = cargo_toml.workspace {
-            writeln!(
-                message,
-                "The project is a Cargo workspace with the following members:"
-            )?;
-            for member in workspace.members {
-                writeln!(message, "- {member}")?;
-            }
-
-            if !workspace.default_members.is_empty() {
-                writeln!(message, "The default members are:")?;
-                for member in workspace.default_members {
-                    writeln!(message, "- {member}")?;
-                }
-            }
-
-            if !workspace.dependencies.is_empty() {
-                writeln!(
-                    message,
-                    "The following workspace dependencies are installed:"
-                )?;
-                for dependency in workspace.dependencies.keys() {
-                    writeln!(message, "- {dependency}")?;
-                }
-            }
-        } else if let Some(package) = cargo_toml.package {
-            writeln!(
-                message,
-                "The project name is \"{name}\".",
-                name = package.name
-            )?;
-
-            let description = package
-                .description
-                .as_ref()
-                .and_then(|description| description.get().ok().cloned());
-            if let Some(description) = description.as_ref() {
-                writeln!(message, "It describes itself as \"{description}\".")?;
-            }
-
-            if !cargo_toml.dependencies.is_empty() {
-                writeln!(message, "The following dependencies are installed:")?;
-                for dependency in cargo_toml.dependencies.keys() {
-                    writeln!(message, "- {dependency}")?;
-                }
-            }
-        }
-
-        Ok(message)
-    }
-
-    fn path_to_cargo_toml(project: Entity<Project>, cx: &mut App) -> Option<Arc<Path>> {
-        let worktree = project.read(cx).worktrees(cx).next()?;
-        let worktree = worktree.read(cx);
-        let entry = worktree.entry_for_path("Cargo.toml")?;
-        let path = ProjectPath {
-            worktree_id: worktree.id(),
-            path: entry.path.clone(),
-        };
-        Some(Arc::from(
-            project.read(cx).absolute_path(&path, cx)?.as_path(),
-        ))
-    }
-}
-
-impl SlashCommand for CargoWorkspaceSlashCommand {
-    fn name(&self) -> String {
-        "cargo-workspace".into()
-    }
-
-    fn description(&self) -> String {
-        "insert project workspace metadata".into()
-    }
-
-    fn menu_text(&self) -> String {
-        "Insert Project Workspace Metadata".into()
-    }
-
-    fn complete_argument(
-        self: Arc<Self>,
-        _arguments: &[String],
-        _cancel: Arc<AtomicBool>,
-        _workspace: Option<WeakEntity<Workspace>>,
-        _window: &mut Window,
-        _cx: &mut App,
-    ) -> Task<Result<Vec<ArgumentCompletion>>> {
-        Task::ready(Err(anyhow!("this command does not require argument")))
-    }
-
-    fn requires_argument(&self) -> bool {
-        false
-    }
-
-    fn run(
-        self: Arc<Self>,
-        _arguments: &[String],
-        _context_slash_command_output_sections: &[SlashCommandOutputSection<language::Anchor>],
-        _context_buffer: BufferSnapshot,
-        workspace: WeakEntity<Workspace>,
-        _delegate: Option<Arc<dyn LspAdapterDelegate>>,
-        _window: &mut Window,
-        cx: &mut App,
-    ) -> Task<SlashCommandResult> {
-        let output = workspace.update(cx, |workspace, cx| {
-            let project = workspace.project().clone();
-            let fs = workspace.project().read(cx).fs().clone();
-            let path = Self::path_to_cargo_toml(project, cx);
-            let output = cx.background_spawn(async move {
-                let path = path.with_context(|| "Cargo.toml not found")?;
-                Self::build_message(fs, &path).await
-            });
-
-            cx.foreground_executor().spawn(async move {
-                let text = output.await?;
-                let range = 0..text.len();
-                Ok(SlashCommandOutput {
-                    text,
-                    sections: vec![SlashCommandOutputSection {
-                        range,
-                        icon: IconName::FileTree,
-                        label: "Project".into(),
-                        metadata: None,
-                    }],
-                    run_commands_in_text: false,
-                }
-                .into_event_stream())
-            })
-        });
-        output.unwrap_or_else(|error| Task::ready(Err(error)))
-    }
-}