chore: Make terminal_view own the TerminalSlashCommand (#31070)

Piotr Osiewicz created

This reduces 'touch crates/editor/src/editor.rs && cargo +nightly build'
from 8.9s to 8.5s. That same scenario used to take 8s less than a week
ago. :)
I'm measuring with nightly rustc, because it's compile times are better
than those of stable thanks to
https://github.com/rust-lang/rust/pull/138522

main (8.2s total):

![image](https://github.com/user-attachments/assets/767a2ac4-7bba-4147-bd16-9b09eed5b433)

[cargo-timing.html.zip](https://github.com/user-attachments/files/20364175/cargo-timing.html.zip)

#22be776 (7.5s total):

[cargo-timing-20250521T085303.892834Z.html.zip](https://github.com/user-attachments/files/20364391/cargo-timing-20250521T085303.892834Z.html.zip)

![image](https://github.com/user-attachments/assets/c4476df9-cb6e-4403-b0db-de00521f1fd0)


Release Notes:

- N/A

Change summary

Cargo.lock                                                      | 27 -
Cargo.toml                                                      |  2 
crates/agent/Cargo.toml                                         |  1 
crates/agent/src/agent.rs                                       |  1 
crates/agent/src/agent_model_selector.rs                        |  4 
crates/agent/src/agent_panel.rs                                 |  2 
crates/agent/src/inline_prompt_editor.rs                        |  2 
crates/agent/src/message_editor.rs                              |  2 
crates/assistant_context_editor/Cargo.toml                      |  4 
crates/assistant_context_editor/src/assistant_context_editor.rs |  1 
crates/assistant_context_editor/src/context_editor.rs           |  6 
crates/assistant_context_editor/src/language_model_selector.rs  |  0 
crates/assistant_slash_command/src/assistant_slash_command.rs   | 14 +
crates/assistant_slash_commands/Cargo.toml                      |  1 
crates/assistant_slash_commands/src/assistant_slash_commands.rs | 18 -
crates/eval/Cargo.toml                                          |  1 
crates/eval/src/eval.rs                                         |  1 
crates/language_model_selector/Cargo.toml                       | 36 ---
crates/language_model_selector/LICENSE-GPL                      |  1 
crates/terminal_view/Cargo.toml                                 |  1 
crates/terminal_view/src/terminal_slash_command.rs              |  4 
crates/terminal_view/src/terminal_view.rs                       |  5 
22 files changed, 42 insertions(+), 92 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -86,7 +86,6 @@ dependencies = [
  "jsonschema",
  "language",
  "language_model",
- "language_model_selector",
  "log",
  "lsp",
  "markdown",
@@ -492,6 +491,7 @@ dependencies = [
  "collections",
  "context_server",
  "editor",
+ "feature_flags",
  "fs",
  "futures 0.3.31",
  "fuzzy",
@@ -499,17 +499,18 @@ dependencies = [
  "indexed_docs",
  "language",
  "language_model",
- "language_model_selector",
  "languages",
  "log",
  "multi_buffer",
  "open_ai",
+ "ordered-float 2.10.1",
  "parking_lot",
  "paths",
  "picker",
  "pretty_assertions",
  "project",
  "prompt_store",
+ "proto",
  "rand 0.8.5",
  "regex",
  "rope",
@@ -611,7 +612,6 @@ dependencies = [
  "serde_json",
  "settings",
  "smol",
- "terminal_view",
  "text",
  "toml 0.8.20",
  "ui",
@@ -5019,6 +5019,7 @@ dependencies = [
  "shellexpand 2.1.2",
  "smol",
  "telemetry",
+ "terminal_view",
  "toml 0.8.20",
  "unindent",
  "util",
@@ -8771,25 +8772,6 @@ dependencies = [
  "zed_llm_client",
 ]
 
-[[package]]
-name = "language_model_selector"
-version = "0.1.0"
-dependencies = [
- "collections",
- "feature_flags",
- "futures 0.3.31",
- "fuzzy",
- "gpui",
- "language_model",
- "log",
- "ordered-float 2.10.1",
- "picker",
- "proto",
- "ui",
- "workspace-hack",
- "zed_actions",
-]
-
 [[package]]
 name = "language_models"
 version = "0.1.0"
@@ -15673,6 +15655,7 @@ name = "terminal_view"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "assistant_slash_command",
  "async-recursion 1.1.1",
  "breadcrumbs",
  "client",

Cargo.toml 🔗

@@ -80,7 +80,6 @@ members = [
     "crates/language",
     "crates/language_extension",
     "crates/language_model",
-    "crates/language_model_selector",
     "crates/language_models",
     "crates/language_selector",
     "crates/language_tools",
@@ -287,7 +286,6 @@ journal = { path = "crates/journal" }
 language = { path = "crates/language" }
 language_extension = { path = "crates/language_extension" }
 language_model = { path = "crates/language_model" }
-language_model_selector = { path = "crates/language_model_selector" }
 language_models = { path = "crates/language_models" }
 language_selector = { path = "crates/language_selector" }
 language_tools = { path = "crates/language_tools" }

crates/agent/Cargo.toml 🔗

@@ -52,7 +52,6 @@ itertools.workspace = true
 jsonschema.workspace = true
 language.workspace = true
 language_model.workspace = true
-language_model_selector.workspace = true
 log.workspace = true
 lsp.workspace = true
 markdown.workspace = true

crates/agent/src/agent.rs 🔗

@@ -217,7 +217,6 @@ fn register_slash_commands(cx: &mut App) {
     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);
-    slash_command_registry.register_command(assistant_slash_commands::TerminalSlashCommand, true);
     slash_command_registry.register_command(assistant_slash_commands::NowSlashCommand, false);
     slash_command_registry
         .register_command(assistant_slash_commands::DiagnosticsSlashCommand, true);

crates/agent/src/agent_model_selector.rs 🔗

@@ -3,10 +3,10 @@ use fs::Fs;
 use gpui::{Entity, FocusHandle, SharedString};
 
 use crate::Thread;
-use language_model::{ConfiguredModel, LanguageModelRegistry};
-use language_model_selector::{
+use assistant_context_editor::language_model_selector::{
     LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
 };
+use language_model::{ConfiguredModel, LanguageModelRegistry};
 use settings::update_settings_file;
 use std::sync::Arc;
 use ui::{PopoverMenuHandle, Tooltip, prelude::*};

crates/agent/src/agent_panel.rs 🔗

@@ -17,6 +17,7 @@ use assistant_settings::{AssistantDockPosition, AssistantSettings};
 use assistant_slash_command::SlashCommandWorkingSet;
 use assistant_tool::ToolWorkingSet;
 
+use assistant_context_editor::language_model_selector::ToggleModelSelector;
 use client::{UserStore, zed_urls};
 use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer};
 use fs::Fs;
@@ -30,7 +31,6 @@ use language::LanguageRegistry;
 use language_model::{
     LanguageModelProviderTosView, LanguageModelRegistry, RequestUsage, ZED_CLOUD_PROVIDER_ID,
 };
-use language_model_selector::ToggleModelSelector;
 use project::{Project, ProjectPath, Worktree};
 use prompt_store::{PromptBuilder, PromptStore, UserPromptId};
 use proto::Plan;

crates/agent/src/inline_prompt_editor.rs 🔗

@@ -9,6 +9,7 @@ use crate::terminal_codegen::TerminalCodegen;
 use crate::thread_store::{TextThreadStore, ThreadStore};
 use crate::{CycleNextInlineAssist, CyclePreviousInlineAssist};
 use crate::{RemoveAllContext, ToggleContextPicker};
+use assistant_context_editor::language_model_selector::ToggleModelSelector;
 use client::ErrorExt;
 use collections::VecDeque;
 use db::kvp::Dismissable;
@@ -24,7 +25,6 @@ use gpui::{
     Focusable, FontWeight, Subscription, TextStyle, WeakEntity, Window, anchored, deferred, point,
 };
 use language_model::{LanguageModel, LanguageModelRegistry};
-use language_model_selector::ToggleModelSelector;
 use parking_lot::Mutex;
 use settings::Settings;
 use std::cmp;

crates/agent/src/message_editor.rs 🔗

@@ -8,6 +8,7 @@ use crate::ui::{
     AnimatedLabel, MaxModeTooltip,
     preview::{AgentPreview, UsageCallout},
 };
+use assistant_context_editor::language_model_selector::ToggleModelSelector;
 use assistant_settings::{AssistantSettings, CompletionMode};
 use buffer_diff::BufferDiff;
 use client::UserStore;
@@ -30,7 +31,6 @@ use language_model::{
     ConfiguredModel, LanguageModelRequestMessage, MessageContent, RequestUsage,
     ZED_CLOUD_PROVIDER_ID,
 };
-use language_model_selector::ToggleModelSelector;
 use multi_buffer;
 use project::Project;
 use prompt_store::PromptStore;

crates/assistant_context_editor/Cargo.toml 🔗

@@ -22,6 +22,7 @@ clock.workspace = true
 collections.workspace = true
 context_server.workspace = true
 editor.workspace = true
+feature_flags.workspace = true
 fs.workspace = true
 futures.workspace = true
 fuzzy.workspace = true
@@ -29,15 +30,16 @@ gpui.workspace = true
 indexed_docs.workspace = true
 language.workspace = true
 language_model.workspace = true
-language_model_selector.workspace = true
 log.workspace = true
 multi_buffer.workspace = true
 open_ai.workspace = true
+ordered-float.workspace = true
 parking_lot.workspace = true
 paths.workspace = true
 picker.workspace = true
 project.workspace = true
 prompt_store.workspace = true
+proto.workspace = true
 regex.workspace = true
 rope.workspace = true
 rpc.workspace = true

crates/assistant_context_editor/src/context_editor.rs 🔗

@@ -1,3 +1,6 @@
+use crate::language_model_selector::{
+    LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
+};
 use anyhow::Result;
 use assistant_settings::AssistantSettings;
 use assistant_slash_command::{SlashCommand, SlashCommandOutputSection, SlashCommandWorkingSet};
@@ -36,9 +39,6 @@ use language_model::{
     LanguageModelImage, LanguageModelProvider, LanguageModelProviderTosView, LanguageModelRegistry,
     Role,
 };
-use language_model_selector::{
-    LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
-};
 use multi_buffer::MultiBufferRow;
 use picker::Picker;
 use project::{Project, Worktree};

crates/assistant_slash_command/src/assistant_slash_command.rs 🔗

@@ -9,6 +9,7 @@ use anyhow::Result;
 use futures::StreamExt;
 use futures::stream::{self, BoxStream};
 use gpui::{App, SharedString, Task, WeakEntity, Window};
+use language::HighlightId;
 use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate, OffsetRangeExt};
 pub use language_model::Role;
 use serde::{Deserialize, Serialize};
@@ -16,6 +17,7 @@ use std::{
     ops::Range,
     sync::{Arc, atomic::AtomicBool},
 };
+use ui::ActiveTheme;
 use workspace::{Workspace, ui::IconName};
 
 pub fn init(cx: &mut App) {
@@ -325,6 +327,18 @@ impl SlashCommandLine {
     }
 }
 
+pub fn create_label_for_command(command_name: &str, arguments: &[&str], cx: &App) -> CodeLabel {
+    let mut label = CodeLabel::default();
+    label.push_str(command_name, None);
+    label.push_str(" ", None);
+    label.push_str(
+        &arguments.join(" "),
+        cx.theme().syntax().highlight_id("comment").map(HighlightId),
+    );
+    label.filter_range = 0..command_name.len();
+    label
+}
+
 #[cfg(test)]
 mod tests {
     use pretty_assertions::assert_eq;

crates/assistant_slash_commands/Cargo.toml 🔗

@@ -35,7 +35,6 @@ rope.workspace = true
 serde.workspace = true
 serde_json.workspace = true
 smol.workspace = true
-terminal_view.workspace = true
 text.workspace = true
 toml.workspace = true
 ui.workspace = true

crates/assistant_slash_commands/src/assistant_slash_commands.rs 🔗

@@ -12,11 +12,6 @@ mod selection_command;
 mod streaming_example_command;
 mod symbols_command;
 mod tab_command;
-mod terminal_command;
-
-use gpui::App;
-use language::{CodeLabel, HighlightId};
-use ui::ActiveTheme as _;
 
 pub use crate::cargo_workspace_command::*;
 pub use crate::context_server_command::*;
@@ -32,16 +27,5 @@ pub use crate::selection_command::*;
 pub use crate::streaming_example_command::*;
 pub use crate::symbols_command::*;
 pub use crate::tab_command::*;
-pub use crate::terminal_command::*;
 
-pub fn create_label_for_command(command_name: &str, arguments: &[&str], cx: &App) -> CodeLabel {
-    let mut label = CodeLabel::default();
-    label.push_str(command_name, None);
-    label.push_str(" ", None);
-    label.push_str(
-        &arguments.join(" "),
-        cx.theme().syntax().highlight_id("comment").map(HighlightId),
-    );
-    label.filter_range = 0..command_name.len();
-    label
-}
+use assistant_slash_command::create_label_for_command;

crates/eval/Cargo.toml 🔗

@@ -61,6 +61,7 @@ settings.workspace = true
 shellexpand.workspace = true
 smol.workspace = true
 telemetry.workspace = true
+terminal_view.workspace = true
 toml.workspace = true
 unindent.workspace = true
 util.workspace = true

crates/eval/src/eval.rs 🔗

@@ -424,6 +424,7 @@ pub fn init(cx: &mut App) -> Arc<AgentAppState> {
     language_models::init(user_store.clone(), client.clone(), fs.clone(), cx);
     languages::init(languages.clone(), node_runtime.clone(), cx);
     prompt_store::init(cx);
+    terminal_view::init(cx);
     let stdout_is_a_pty = false;
     let prompt_builder = PromptBuilder::load(fs.clone(), stdout_is_a_pty, cx);
     agent::init(

crates/language_model_selector/Cargo.toml 🔗

@@ -1,36 +0,0 @@
-[package]
-name = "language_model_selector"
-version = "0.1.0"
-edition.workspace = true
-publish.workspace = true
-license = "GPL-3.0-or-later"
-
-[lints]
-workspace = true
-
-[lib]
-path = "src/language_model_selector.rs"
-
-[features]
-test-support = [
-    "gpui/test-support",
-]
-
-[dependencies]
-collections.workspace = true
-feature_flags.workspace = true
-futures.workspace = true
-fuzzy.workspace = true
-gpui.workspace = true
-language_model.workspace = true
-log.workspace = true
-ordered-float.workspace = true
-picker.workspace = true
-proto.workspace = true
-ui.workspace = true
-workspace-hack.workspace = true
-zed_actions.workspace = true
-
-[dev-dependencies]
-gpui = { workspace = true, "features" = ["test-support"] }
-language_model = { workspace = true, "features" = ["test-support"] }

crates/terminal_view/Cargo.toml 🔗

@@ -18,6 +18,7 @@ doctest = false
 [dependencies]
 anyhow.workspace = true
 async-recursion.workspace = true
+assistant_slash_command.workspace = true
 breadcrumbs.workspace = true
 collections.workspace = true
 db.workspace = true

crates/assistant_slash_commands/src/terminal_command.rs → crates/terminal_view/src/terminal_slash_command.rs 🔗

@@ -1,6 +1,7 @@
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
 
+use crate::{TerminalView, terminal_panel::TerminalPanel};
 use anyhow::Result;
 use assistant_slash_command::{
     ArgumentCompletion, SlashCommand, SlashCommandOutput, SlashCommandOutputSection,
@@ -8,11 +9,10 @@ use assistant_slash_command::{
 };
 use gpui::{App, Entity, Task, WeakEntity};
 use language::{BufferSnapshot, CodeLabel, LspAdapterDelegate};
-use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
 use ui::prelude::*;
 use workspace::{Workspace, dock::Panel};
 
-use super::create_label_for_command;
+use assistant_slash_command::create_label_for_command;
 
 pub struct TerminalSlashCommand;
 

crates/terminal_view/src/terminal_view.rs 🔗

@@ -2,8 +2,10 @@ mod persistence;
 pub mod terminal_element;
 pub mod terminal_panel;
 pub mod terminal_scrollbar;
+mod terminal_slash_command;
 pub mod terminal_tab_tooltip;
 
+use assistant_slash_command::SlashCommandRegistry;
 use editor::{Editor, EditorSettings, actions::SelectAll, scroll::ScrollbarAutoHide};
 use gpui::{
     AnyElement, App, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, KeyContext,
@@ -29,6 +31,7 @@ use terminal::{
 use terminal_element::{TerminalElement, is_blank};
 use terminal_panel::TerminalPanel;
 use terminal_scrollbar::TerminalScrollHandle;
+use terminal_slash_command::TerminalSlashCommand;
 use terminal_tab_tooltip::TerminalTooltip;
 use ui::{
     ContextMenu, Icon, IconName, Label, Scrollbar, ScrollbarState, Tooltip, h_flex, prelude::*,
@@ -78,6 +81,7 @@ actions!(terminal, [RerunTask]);
 impl_actions!(terminal, [SendText, SendKeystroke]);
 
 pub fn init(cx: &mut App) {
+    assistant_slash_command::init(cx);
     terminal_panel::init(cx);
     terminal::init(cx);
 
@@ -87,6 +91,7 @@ pub fn init(cx: &mut App) {
         workspace.register_action(TerminalView::deploy);
     })
     .detach();
+    SlashCommandRegistry::global(cx).register_command(TerminalSlashCommand, true);
 }
 
 pub struct BlockProperties {