diff --git a/Cargo.lock b/Cargo.lock index 234e3998bd..922fed0ae4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,7 +55,7 @@ version = "0.1.0" dependencies = [ "agent_settings", "anyhow", - "assistant_context_editor", + "assistant_context", "assistant_tool", "assistant_tools", "chrono", @@ -138,7 +138,7 @@ dependencies = [ "agent", "agent_settings", "anyhow", - "assistant_context_editor", + "assistant_context", "assistant_slash_command", "assistant_slash_commands", "assistant_tool", @@ -169,6 +169,7 @@ dependencies = [ "jsonschema", "language", "language_model", + "languages", "log", "lsp", "markdown", @@ -203,7 +204,9 @@ dependencies = [ "theme", "time", "time_format", + "tree-sitter-md", "ui", + "unindent", "urlencoding", "util", "uuid", @@ -557,7 +560,7 @@ dependencies = [ ] [[package]] -name = "assistant_context_editor" +name = "assistant_context" version = "0.1.0" dependencies = [ "agent_settings", @@ -569,31 +572,23 @@ dependencies = [ "clock", "collections", "context_server", - "editor", - "feature_flags", "fs", "futures 0.3.31", "fuzzy", "gpui", - "indexed_docs", "indoc", "language", "language_model", - "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", "rpc", "serde", "serde_json", @@ -602,15 +597,12 @@ dependencies = [ "smol", "telemetry_events", "text", - "theme", - "tree-sitter-md", "ui", "unindent", "util", "uuid", "workspace", "workspace-hack", - "zed_actions", "zed_llm_client", ] @@ -3031,7 +3023,7 @@ version = "0.44.0" dependencies = [ "agent_settings", "anyhow", - "assistant_context_editor", + "assistant_context", "assistant_slash_command", "async-stripe", "async-trait", @@ -19924,7 +19916,6 @@ dependencies = [ "ashpd", "askpass", "assets", - "assistant_context_editor", "assistant_tool", "assistant_tools", "audio", diff --git a/Cargo.toml b/Cargo.toml index 55ee14485c..8de3ad9f74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ "crates/anthropic", "crates/askpass", "crates/assets", - "crates/assistant_context_editor", + "crates/assistant_context", "crates/assistant_slash_command", "crates/assistant_slash_commands", "crates/assistant_tool", @@ -221,7 +221,7 @@ ai = { path = "crates/ai" } anthropic = { path = "crates/anthropic" } askpass = { path = "crates/askpass" } assets = { path = "crates/assets" } -assistant_context_editor = { path = "crates/assistant_context_editor" } +assistant_context = { path = "crates/assistant_context" } assistant_slash_command = { path = "crates/assistant_slash_command" } assistant_slash_commands = { path = "crates/assistant_slash_commands" } assistant_tool = { path = "crates/assistant_tool" } diff --git a/crates/agent/Cargo.toml b/crates/agent/Cargo.toml index bedd5506b9..f320e58d00 100644 --- a/crates/agent/Cargo.toml +++ b/crates/agent/Cargo.toml @@ -21,7 +21,7 @@ test-support = [ [dependencies] agent_settings.workspace = true anyhow.workspace = true -assistant_context_editor.workspace = true +assistant_context.workspace = true assistant_tool.workspace = true chrono.workspace = true client.workspace = true diff --git a/crates/agent/src/context.rs b/crates/agent/src/context.rs index bfbea476f6..ddd13de491 100644 --- a/crates/agent/src/context.rs +++ b/crates/agent/src/context.rs @@ -1,5 +1,5 @@ use crate::thread::Thread; -use assistant_context_editor::AssistantContext; +use assistant_context::AssistantContext; use assistant_tool::outline; use collections::HashSet; use futures::future; diff --git a/crates/agent/src/context_store.rs b/crates/agent/src/context_store.rs index 3e43e4dd2a..60ba5527dc 100644 --- a/crates/agent/src/context_store.rs +++ b/crates/agent/src/context_store.rs @@ -8,7 +8,7 @@ use crate::{ thread_store::ThreadStore, }; use anyhow::{Context as _, Result, anyhow}; -use assistant_context_editor::AssistantContext; +use assistant_context::AssistantContext; use collections::{HashSet, IndexSet}; use futures::{self, FutureExt}; use gpui::{App, Context, Entity, EventEmitter, Image, SharedString, Task, WeakEntity}; diff --git a/crates/agent/src/history_store.rs b/crates/agent/src/history_store.rs index 47dbd894df..89f75a72bd 100644 --- a/crates/agent/src/history_store.rs +++ b/crates/agent/src/history_store.rs @@ -3,7 +3,7 @@ use crate::{ thread_store::{SerializedThreadMetadata, ThreadStore}, }; use anyhow::{Context as _, Result}; -use assistant_context_editor::SavedContextMetadata; +use assistant_context::SavedContextMetadata; use chrono::{DateTime, Utc}; use gpui::{App, AsyncApp, Entity, SharedString, Task, prelude::*}; use itertools::Itertools; @@ -62,7 +62,7 @@ enum SerializedRecentOpen { pub struct HistoryStore { thread_store: Entity, - context_store: Entity, + context_store: Entity, recently_opened_entries: VecDeque, _subscriptions: Vec, _save_recently_opened_entries_task: Task<()>, @@ -71,7 +71,7 @@ pub struct HistoryStore { impl HistoryStore { pub fn new( thread_store: Entity, - context_store: Entity, + context_store: Entity, initial_recent_entries: impl IntoIterator, cx: &mut Context, ) -> Self { diff --git a/crates/agent/src/thread_store.rs b/crates/agent/src/thread_store.rs index 625bc505ee..0582e67a5c 100644 --- a/crates/agent/src/thread_store.rs +++ b/crates/agent/src/thread_store.rs @@ -96,7 +96,7 @@ impl SharedProjectContext { } } -pub type TextThreadStore = assistant_context_editor::ContextStore; +pub type TextThreadStore = assistant_context::ContextStore; pub struct ThreadStore { project: Entity, diff --git a/crates/agent_ui/Cargo.toml b/crates/agent_ui/Cargo.toml index c8ad716bfa..070e8eb585 100644 --- a/crates/agent_ui/Cargo.toml +++ b/crates/agent_ui/Cargo.toml @@ -22,7 +22,7 @@ test-support = [ agent.workspace = true agent_settings.workspace = true anyhow.workspace = true -assistant_context_editor.workspace = true +assistant_context.workspace = true assistant_slash_command.workspace = true assistant_slash_commands.workspace = true assistant_tool.workspace = true @@ -101,7 +101,10 @@ editor = { workspace = true, features = ["test-support"] } gpui = { workspace = true, "features" = ["test-support"] } indoc.workspace = true language = { workspace = true, "features" = ["test-support"] } +languages = { workspace = true, features = ["test-support"] } language_model = { workspace = true, "features" = ["test-support"] } pretty_assertions.workspace = true project = { workspace = true, features = ["test-support"] } rand.workspace = true +tree-sitter-md.workspace = true +unindent.workspace = true diff --git a/crates/agent_ui/src/agent_model_selector.rs b/crates/agent_ui/src/agent_model_selector.rs index 708172057a..c8b628c938 100644 --- a/crates/agent_ui/src/agent_model_selector.rs +++ b/crates/agent_ui/src/agent_model_selector.rs @@ -1,13 +1,14 @@ +use crate::{ + ModelUsageContext, + language_model_selector::{ + LanguageModelSelector, ToggleModelSelector, language_model_selector, + }, +}; use agent_settings::AgentSettings; use fs::Fs; use gpui::{Entity, FocusHandle, SharedString}; -use picker::popover_menu::PickerPopoverMenu; - -use crate::ModelUsageContext; -use assistant_context_editor::language_model_selector::{ - LanguageModelSelector, ToggleModelSelector, language_model_selector, -}; use language_model::{ConfiguredModel, LanguageModelRegistry}; +use picker::popover_menu::PickerPopoverMenu; use settings::update_settings_file; use std::sync::Arc; use ui::{PopoverMenuHandle, Tooltip, prelude::*}; diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 2893ab81b7..eed50f1842 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -7,17 +7,35 @@ use std::time::Duration; use db::kvp::{Dismissable, KEY_VALUE_STORE}; use serde::{Deserialize, Serialize}; +use crate::language_model_selector::ToggleModelSelector; +use crate::{ + AddContextServer, AgentDiffPane, ContinueThread, ContinueWithBurnMode, + DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread, + NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell, + ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu, ToggleOptionsMenu, + active_thread::{self, ActiveThread, ActiveThreadEvent}, + agent_configuration::{AgentConfiguration, AssistantConfigurationEvent}, + agent_diff::AgentDiff, + message_editor::{MessageEditor, MessageEditorEvent}, + slash_command::SlashCommandCompletionProvider, + text_thread_editor::{ + AgentPanelDelegate, TextThreadEditor, humanize_token_count, make_lsp_adapter_delegate, + render_remaining_tokens, + }, + thread_history::{HistoryEntryElement, ThreadHistory}, + ui::AgentOnboardingModal, +}; +use agent::{ + Thread, ThreadError, ThreadEvent, ThreadId, ThreadSummary, TokenUsageRatio, + context_store::ContextStore, + history_store::{HistoryEntryId, HistoryStore}, + thread_store::{TextThreadStore, ThreadStore}, +}; use agent_settings::{AgentDockPosition, AgentSettings, CompletionMode, DefaultView}; use anyhow::{Result, anyhow}; -use assistant_context_editor::{ - AgentPanelDelegate, AssistantContext, ContextEditor, ContextEvent, ContextSummary, - SlashCommandCompletionProvider, humanize_token_count, make_lsp_adapter_delegate, - render_remaining_tokens, -}; +use assistant_context::{AssistantContext, ContextEvent, ContextSummary}; 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; @@ -56,25 +74,6 @@ use zed_actions::{ }; use zed_llm_client::{CompletionIntent, UsageLimit}; -use crate::{ - AddContextServer, AgentDiffPane, ContinueThread, ContinueWithBurnMode, - DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread, - NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell, - ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu, ToggleOptionsMenu, - active_thread::{self, ActiveThread, ActiveThreadEvent}, - agent_configuration::{AgentConfiguration, AssistantConfigurationEvent}, - agent_diff::AgentDiff, - message_editor::{MessageEditor, MessageEditorEvent}, - thread_history::{HistoryEntryElement, ThreadHistory}, - ui::AgentOnboardingModal, -}; -use agent::{ - Thread, ThreadError, ThreadEvent, ThreadId, ThreadSummary, TokenUsageRatio, - context_store::ContextStore, - history_store::{HistoryEntryId, HistoryStore}, - thread_store::{TextThreadStore, ThreadStore}, -}; - const AGENT_PANEL_KEY: &str = "agent_panel"; #[derive(Serialize, Deserialize)] @@ -179,7 +178,7 @@ enum ActiveView { _subscriptions: Vec, }, TextThread { - context_editor: Entity, + context_editor: Entity, title_editor: Entity, buffer_search_bar: Entity, _subscriptions: Vec, @@ -260,7 +259,7 @@ impl ActiveView { } pub fn prompt_editor( - context_editor: Entity, + context_editor: Entity, history_store: Entity, language_registry: Arc, window: &mut Window, @@ -434,7 +433,7 @@ impl AgentPanel { let context_store = workspace .update(cx, |workspace, cx| { let project = workspace.project().clone(); - assistant_context_editor::ContextStore::new( + assistant_context::ContextStore::new( project, prompt_builder.clone(), slash_commands, @@ -546,7 +545,7 @@ impl AgentPanel { context_store.update(cx, |context_store, cx| context_store.create(cx)); let lsp_adapter_delegate = make_lsp_adapter_delegate(&project.clone(), cx).unwrap(); let context_editor = cx.new(|cx| { - let mut editor = ContextEditor::for_context( + let mut editor = TextThreadEditor::for_context( context, fs.clone(), workspace.clone(), @@ -841,7 +840,7 @@ impl AgentPanel { .flatten(); let context_editor = cx.new(|cx| { - let mut editor = ContextEditor::for_context( + let mut editor = TextThreadEditor::for_context( context, self.fs.clone(), self.workspace.clone(), @@ -933,7 +932,7 @@ impl AgentPanel { .log_err() .flatten(); let editor = cx.new(|cx| { - ContextEditor::for_context( + TextThreadEditor::for_context( context, self.fs.clone(), self.workspace.clone(), @@ -1321,7 +1320,7 @@ impl AgentPanel { }); } - pub(crate) fn active_context_editor(&self) -> Option> { + pub(crate) fn active_context_editor(&self) -> Option> { match &self.active_view { ActiveView::TextThread { context_editor, .. } => Some(context_editor.clone()), _ => None, @@ -2899,7 +2898,7 @@ impl AgentPanel { fn render_prompt_editor( &self, - context_editor: &Entity, + context_editor: &Entity, buffer_search_bar: &Entity, window: &mut Window, cx: &mut Context, @@ -3026,7 +3025,7 @@ impl AgentPanel { } ActiveView::TextThread { context_editor, .. } => { context_editor.update(cx, |context_editor, cx| { - ContextEditor::insert_dragged_files( + TextThreadEditor::insert_dragged_files( context_editor, paths, added_worktrees, @@ -3205,7 +3204,7 @@ impl AgentPanelDelegate for ConcreteAssistantPanelDelegate { workspace: &mut Workspace, _window: &mut Window, cx: &mut Context, - ) -> Option> { + ) -> Option> { let panel = workspace.panel::(cx)?; panel.read(cx).active_context_editor() } @@ -3229,10 +3228,10 @@ impl AgentPanelDelegate for ConcreteAssistantPanelDelegate { fn open_remote_context( &self, _workspace: &mut Workspace, - _context_id: assistant_context_editor::ContextId, + _context_id: assistant_context::ContextId, _window: &mut Window, _cx: &mut Context, - ) -> Task>> { + ) -> Task>> { Task::ready(Err(anyhow!("opening remote context not implemented"))) } diff --git a/crates/agent_ui/src/agent_ui.rs b/crates/agent_ui/src/agent_ui.rs index 0a9649e318..a1439620b6 100644 --- a/crates/agent_ui/src/agent_ui.rs +++ b/crates/agent_ui/src/agent_ui.rs @@ -10,11 +10,16 @@ mod context_strip; mod debug; mod inline_assistant; mod inline_prompt_editor; +mod language_model_selector; +mod max_mode_tooltip; 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; mod thread_history; mod tool_compatibility; mod ui; @@ -43,6 +48,7 @@ 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; pub use ui::preview::{all_agent_previews, get_agent_preview}; actions!( @@ -140,7 +146,7 @@ pub fn init( AgentSettings::register(cx); SlashCommandSettings::register(cx); - assistant_context_editor::init(client.clone(), cx); + assistant_context::init(client.clone(), cx); rules_library::init(cx); if !is_eval { // Initializing the language model from the user settings messes with the eval, so we only initialize them when diff --git a/crates/agent_ui/src/context_picker/completion_provider.rs b/crates/agent_ui/src/context_picker/completion_provider.rs index 4c05206748..ab91ded2c8 100644 --- a/crates/agent_ui/src/context_picker/completion_provider.rs +++ b/crates/agent_ui/src/context_picker/completion_provider.rs @@ -73,7 +73,7 @@ fn search( recent_entries: Vec, prompt_store: Option>, thread_store: Option>, - text_thread_context_store: Option>, + text_thread_context_store: Option>, workspace: Entity, cx: &mut App, ) -> Task> { diff --git a/crates/agent_ui/src/inline_prompt_editor.rs b/crates/agent_ui/src/inline_prompt_editor.rs index 5d486cdd8b..7a61eef748 100644 --- a/crates/agent_ui/src/inline_prompt_editor.rs +++ b/crates/agent_ui/src/inline_prompt_editor.rs @@ -2,6 +2,7 @@ use crate::agent_model_selector::AgentModelSelector; use crate::buffer_codegen::BufferCodegen; use crate::context_picker::{ContextPicker, ContextPickerCompletionProvider}; use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind}; +use crate::language_model_selector::ToggleModelSelector; use crate::message_editor::{ContextCreasesAddon, extract_message_creases, insert_message_creases}; use crate::terminal_codegen::TerminalCodegen; use crate::{CycleNextInlineAssist, CyclePreviousInlineAssist, ModelUsageContext}; @@ -10,7 +11,6 @@ use agent::{ context_store::ContextStore, thread_store::{TextThreadStore, ThreadStore}, }; -use assistant_context_editor::language_model_selector::ToggleModelSelector; use client::ErrorExt; use collections::VecDeque; use db::kvp::Dismissable; diff --git a/crates/assistant_context_editor/src/language_model_selector.rs b/crates/agent_ui/src/language_model_selector.rs similarity index 100% rename from crates/assistant_context_editor/src/language_model_selector.rs rename to crates/agent_ui/src/language_model_selector.rs diff --git a/crates/assistant_context_editor/src/max_mode_tooltip.rs b/crates/agent_ui/src/max_mode_tooltip.rs similarity index 100% rename from crates/assistant_context_editor/src/max_mode_tooltip.rs rename to crates/agent_ui/src/max_mode_tooltip.rs diff --git a/crates/agent_ui/src/message_editor.rs b/crates/agent_ui/src/message_editor.rs index dabc98a5dd..39f83d50cb 100644 --- a/crates/agent_ui/src/message_editor.rs +++ b/crates/agent_ui/src/message_editor.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use std::sync::Arc; use crate::agent_model_selector::AgentModelSelector; +use crate::language_model_selector::ToggleModelSelector; use crate::tool_compatibility::{IncompatibleToolsState, IncompatibleToolsTooltip}; use crate::ui::{ MaxModeTooltip, @@ -13,7 +14,6 @@ use agent::{ context_store::ContextStoreEvent, }; use agent_settings::{AgentSettings, CompletionMode}; -use assistant_context_editor::language_model_selector::ToggleModelSelector; use buffer_diff::BufferDiff; use client::UserStore; use collections::{HashMap, HashSet}; diff --git a/crates/assistant_context_editor/src/slash_command.rs b/crates/agent_ui/src/slash_command.rs similarity index 98% rename from crates/assistant_context_editor/src/slash_command.rs rename to crates/agent_ui/src/slash_command.rs index 9cac5ec541..6b37c5a2d7 100644 --- a/crates/assistant_context_editor/src/slash_command.rs +++ b/crates/agent_ui/src/slash_command.rs @@ -1,4 +1,4 @@ -use crate::context_editor::ContextEditor; +use crate::text_thread_editor::TextThreadEditor; use anyhow::Result; pub use assistant_slash_command::SlashCommand; use assistant_slash_command::{AfterCompletion, SlashCommandLine, SlashCommandWorkingSet}; @@ -21,14 +21,14 @@ use workspace::Workspace; pub struct SlashCommandCompletionProvider { cancel_flag: Mutex>, slash_commands: Arc, - editor: Option>, + editor: Option>, workspace: Option>, } impl SlashCommandCompletionProvider { pub fn new( slash_commands: Arc, - editor: Option>, + editor: Option>, workspace: Option>, ) -> Self { Self { diff --git a/crates/assistant_context_editor/src/slash_command_picker.rs b/crates/agent_ui/src/slash_command_picker.rs similarity index 98% rename from crates/assistant_context_editor/src/slash_command_picker.rs rename to crates/agent_ui/src/slash_command_picker.rs index 3cafebdd74..a757a2f50a 100644 --- a/crates/assistant_context_editor/src/slash_command_picker.rs +++ b/crates/agent_ui/src/slash_command_picker.rs @@ -1,12 +1,10 @@ -use std::sync::Arc; - +use crate::text_thread_editor::TextThreadEditor; use assistant_slash_command::SlashCommandWorkingSet; use gpui::{AnyElement, AnyView, DismissEvent, SharedString, Task, WeakEntity}; use picker::{Picker, PickerDelegate, PickerEditorPosition}; +use std::sync::Arc; use ui::{ListItem, ListItemSpacing, PopoverMenu, PopoverTrigger, Tooltip, prelude::*}; -use crate::context_editor::ContextEditor; - #[derive(IntoElement)] pub(super) struct SlashCommandSelector where @@ -14,7 +12,7 @@ where TT: Fn(&mut Window, &mut App) -> AnyView + 'static, { working_set: Arc, - active_context_editor: WeakEntity, + active_context_editor: WeakEntity, trigger: T, tooltip: TT, } @@ -49,7 +47,7 @@ impl AsRef for SlashCommandEntry { pub(crate) struct SlashCommandDelegate { all_commands: Vec, filtered_commands: Vec, - active_context_editor: WeakEntity, + active_context_editor: WeakEntity, selected_index: usize, } @@ -60,7 +58,7 @@ where { pub(crate) fn new( working_set: Arc, - active_context_editor: WeakEntity, + active_context_editor: WeakEntity, trigger: T, tooltip: TT, ) -> Self { diff --git a/crates/assistant_context_editor/src/context_editor.rs b/crates/agent_ui/src/text_thread_editor.rs similarity index 98% rename from crates/assistant_context_editor/src/context_editor.rs rename to crates/agent_ui/src/text_thread_editor.rs index 57499bae6c..0a1013a6f2 100644 --- a/crates/assistant_context_editor/src/context_editor.rs +++ b/crates/agent_ui/src/text_thread_editor.rs @@ -76,14 +76,11 @@ use workspace::{ searchable::{SearchEvent, SearchableItem}, }; -use crate::{ +use crate::{slash_command::SlashCommandCompletionProvider, slash_command_picker}; +use assistant_context::{ AssistantContext, CacheStatus, Content, ContextEvent, ContextId, InvokedSlashCommandId, InvokedSlashCommandStatus, Message, MessageId, MessageMetadata, MessageStatus, - ParsedSlashCommand, PendingSlashCommandStatus, -}; -use crate::{ - ThoughtProcessOutputSection, slash_command::SlashCommandCompletionProvider, - slash_command_picker, + ParsedSlashCommand, PendingSlashCommandStatus, ThoughtProcessOutputSection, }; actions!( @@ -131,7 +128,7 @@ pub trait AgentPanelDelegate { workspace: &mut Workspace, window: &mut Window, cx: &mut Context, - ) -> Option>; + ) -> Option>; fn open_saved_context( &self, @@ -147,7 +144,7 @@ pub trait AgentPanelDelegate { context_id: ContextId, window: &mut Window, cx: &mut Context, - ) -> Task>>; + ) -> Task>>; fn quote_selection( &self, @@ -176,7 +173,7 @@ struct GlobalAssistantPanelDelegate(Arc); impl Global for GlobalAssistantPanelDelegate {} -pub struct ContextEditor { +pub struct TextThreadEditor { context: Entity, fs: Arc, slash_commands: Arc, @@ -206,10 +203,24 @@ pub struct ContextEditor { language_model_selector_menu_handle: PopoverMenuHandle, } -pub const DEFAULT_TAB_TITLE: &str = "New Chat"; const MAX_TAB_TITLE_LEN: usize = 16; -impl ContextEditor { +impl TextThreadEditor { + pub fn init(cx: &mut App) { + workspace::FollowableViewRegistry::register::(cx); + + cx.observe_new( + |workspace: &mut Workspace, _window, _cx: &mut Context| { + workspace + .register_action(TextThreadEditor::quote_selection) + .register_action(TextThreadEditor::insert_selection) + .register_action(TextThreadEditor::copy_code) + .register_action(TextThreadEditor::handle_insert_dragged_files); + }, + ) + .detach(); + } + pub fn for_context( context: Entity, fs: Arc, @@ -1279,7 +1290,7 @@ impl ContextEditor { /// Returns either the selected text, or the content of the Markdown code /// block surrounding the cursor. fn get_selection_or_code_block( - context_editor_view: &Entity, + context_editor_view: &Entity, cx: &mut Context, ) -> Option<(String, bool)> { const CODE_FENCE_DELIMITER: &'static str = "```"; @@ -2029,7 +2040,7 @@ impl ContextEditor { /// Whether or not we should allow messages to be sent. /// Will return false if the selected provided has a configuration error or /// if the user has not accepted the terms of service for this provider. - fn sending_disabled(&self, cx: &mut Context<'_, ContextEditor>) -> bool { + fn sending_disabled(&self, cx: &mut Context<'_, TextThreadEditor>) -> bool { let model_registry = LanguageModelRegistry::read_global(cx); let Some(configuration_error) = model_registry.configuration_error(model_registry.default_model(), cx) @@ -2546,10 +2557,10 @@ struct SelectedCreaseMetadata { crease: CreaseMetadata, } -impl EventEmitter for ContextEditor {} -impl EventEmitter for ContextEditor {} +impl EventEmitter for TextThreadEditor {} +impl EventEmitter for TextThreadEditor {} -impl Render for ContextEditor { +impl Render for TextThreadEditor { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let provider = LanguageModelRegistry::read_global(cx) .default_model() @@ -2568,15 +2579,15 @@ impl Render for ContextEditor { v_flex() .key_context("ContextEditor") - .capture_action(cx.listener(ContextEditor::cancel)) - .capture_action(cx.listener(ContextEditor::save)) - .capture_action(cx.listener(ContextEditor::copy)) - .capture_action(cx.listener(ContextEditor::cut)) - .capture_action(cx.listener(ContextEditor::paste)) - .capture_action(cx.listener(ContextEditor::cycle_message_role)) - .capture_action(cx.listener(ContextEditor::confirm_command)) - .on_action(cx.listener(ContextEditor::assist)) - .on_action(cx.listener(ContextEditor::split)) + .capture_action(cx.listener(TextThreadEditor::cancel)) + .capture_action(cx.listener(TextThreadEditor::save)) + .capture_action(cx.listener(TextThreadEditor::copy)) + .capture_action(cx.listener(TextThreadEditor::cut)) + .capture_action(cx.listener(TextThreadEditor::paste)) + .capture_action(cx.listener(TextThreadEditor::cycle_message_role)) + .capture_action(cx.listener(TextThreadEditor::confirm_command)) + .on_action(cx.listener(TextThreadEditor::assist)) + .on_action(cx.listener(TextThreadEditor::split)) .on_action(move |_: &ToggleModelSelector, window, cx| { language_model_selector.toggle(window, cx); }) @@ -2631,13 +2642,13 @@ impl Render for ContextEditor { } } -impl Focusable for ContextEditor { +impl Focusable for TextThreadEditor { fn focus_handle(&self, cx: &App) -> FocusHandle { self.editor.focus_handle(cx) } } -impl Item for ContextEditor { +impl Item for TextThreadEditor { type Event = editor::EditorEvent; fn tab_content_text(&self, _detail: usize, cx: &App) -> SharedString { @@ -2710,7 +2721,7 @@ impl Item for ContextEditor { } } -impl SearchableItem for ContextEditor { +impl SearchableItem for TextThreadEditor { type Match = ::Match; fn clear_matches(&mut self, window: &mut Window, cx: &mut Context) { @@ -2791,7 +2802,7 @@ impl SearchableItem for ContextEditor { } } -impl FollowableItem for ContextEditor { +impl FollowableItem for TextThreadEditor { fn remote_id(&self) -> Option { self.remote_id } @@ -2914,21 +2925,14 @@ impl FollowableItem for ContextEditor { } pub struct ContextEditorToolbarItem { - active_context_editor: Option>, + active_context_editor: Option>, model_summary_editor: Entity, } -impl ContextEditorToolbarItem { - pub fn new(model_summary_editor: Entity) -> Self { - Self { - active_context_editor: None, - model_summary_editor, - } - } -} +impl ContextEditorToolbarItem {} pub fn render_remaining_tokens( - context_editor: &Entity, + context_editor: &Entity, cx: &App, ) -> Option> { let context = &context_editor.read(cx).context; @@ -3044,7 +3048,7 @@ impl ToolbarItemView for ContextEditorToolbarItem { cx: &mut Context, ) -> ToolbarItemLocation { self.active_context_editor = active_pane_item - .and_then(|item| item.act_as::(cx)) + .and_then(|item| item.act_as::(cx)) .map(|editor| editor.downgrade()); cx.notify(); if self.active_context_editor.is_none() { @@ -3405,7 +3409,7 @@ mod tests { cx: &mut TestAppContext, ) -> ( Entity, - Entity, + Entity, VisualTestContext, ) { cx.update(init_test); @@ -3421,7 +3425,7 @@ mod tests { let context_editor = window .update(&mut cx, |_, window, cx| { cx.new(|cx| { - let editor = ContextEditor::for_context( + let editor = TextThreadEditor::for_context( context.clone(), fs, workspace.downgrade(), @@ -3454,7 +3458,7 @@ mod tests { } fn assert_copy_paste_context_editor( - context_editor: &Entity, + context_editor: &Entity, range: Range, expected_text: &str, cx: &mut VisualTestContext, diff --git a/crates/assistant_context_editor/Cargo.toml b/crates/assistant_context/Cargo.toml similarity index 77% rename from crates/assistant_context_editor/Cargo.toml rename to crates/assistant_context/Cargo.toml index 05d15a8dd9..f35dc43340 100644 --- a/crates/assistant_context_editor/Cargo.toml +++ b/crates/assistant_context/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "assistant_context_editor" +name = "assistant_context" version = "0.1.0" edition.workspace = true publish.workspace = true @@ -9,7 +9,7 @@ license = "GPL-3.0-or-later" workspace = true [lib] -path = "src/assistant_context_editor.rs" +path = "src/assistant_context.rs" [dependencies] agent_settings.workspace = true @@ -21,27 +21,20 @@ client.workspace = true 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 gpui.workspace = true -indexed_docs.workspace = true language.workspace = true language_model.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 serde.workspace = true serde_json.workspace = true @@ -50,21 +43,17 @@ smallvec.workspace = true smol.workspace = true telemetry_events.workspace = true text.workspace = true -theme.workspace = true ui.workspace = true util.workspace = true uuid.workspace = true workspace-hack.workspace = true workspace.workspace = true -zed_actions.workspace = true zed_llm_client.workspace = true [dev-dependencies] indoc.workspace = true language_model = { workspace = true, features = ["test-support"] } -languages = { workspace = true, features = ["test-support"] } pretty_assertions.workspace = true rand.workspace = true -tree-sitter-md.workspace = true unindent.workspace = true workspace = { workspace = true, features = ["test-support"] } diff --git a/crates/assistant_context_editor/LICENSE-GPL b/crates/assistant_context/LICENSE-GPL similarity index 100% rename from crates/assistant_context_editor/LICENSE-GPL rename to crates/assistant_context/LICENSE-GPL diff --git a/crates/assistant_context_editor/src/context.rs b/crates/assistant_context/src/assistant_context.rs similarity index 99% rename from crates/assistant_context_editor/src/context.rs rename to crates/assistant_context/src/assistant_context.rs index ef78d1b6e6..1444701aac 100644 --- a/crates/assistant_context_editor/src/context.rs +++ b/crates/assistant_context/src/assistant_context.rs @@ -1,5 +1,6 @@ #[cfg(test)] -mod context_tests; +mod assistant_context_tests; +mod context_store; use agent_settings::AgentSettings; use anyhow::{Context as _, Result, bail}; @@ -8,7 +9,7 @@ use assistant_slash_command::{ SlashCommandResult, SlashCommandWorkingSet, }; use assistant_slash_commands::FileCommandMetadata; -use client::{self, proto, telemetry::Telemetry}; +use client::{self, Client, proto, telemetry::Telemetry}; use clock::ReplicaId; use collections::{HashMap, HashSet}; use fs::{Fs, RenameOptions}; @@ -47,6 +48,12 @@ use util::{ResultExt, TryFutureExt, post_inc}; use uuid::Uuid; use zed_llm_client::CompletionIntent; +pub use crate::context_store::*; + +pub fn init(client: Arc, _: &mut App) { + context_store::init(&client.into()); +} + #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)] pub struct ContextId(String); diff --git a/crates/assistant_context_editor/src/context/context_tests.rs b/crates/assistant_context/src/assistant_context_tests.rs similarity index 100% rename from crates/assistant_context_editor/src/context/context_tests.rs rename to crates/assistant_context/src/assistant_context_tests.rs diff --git a/crates/assistant_context_editor/src/context_store.rs b/crates/assistant_context/src/context_store.rs similarity index 100% rename from crates/assistant_context_editor/src/context_store.rs rename to crates/assistant_context/src/context_store.rs diff --git a/crates/assistant_context_editor/src/assistant_context_editor.rs b/crates/assistant_context_editor/src/assistant_context_editor.rs deleted file mode 100644 index 44af31ae38..0000000000 --- a/crates/assistant_context_editor/src/assistant_context_editor.rs +++ /dev/null @@ -1,36 +0,0 @@ -mod context; -mod context_editor; -mod context_history; -mod context_store; -pub mod language_model_selector; -mod max_mode_tooltip; -mod slash_command; -mod slash_command_picker; - -use std::sync::Arc; - -use client::Client; -use gpui::{App, Context}; -use workspace::Workspace; - -pub use crate::context::*; -pub use crate::context_editor::*; -pub use crate::context_history::*; -pub use crate::context_store::*; -pub use crate::slash_command::*; - -pub fn init(client: Arc, cx: &mut App) { - context_store::init(&client.into()); - workspace::FollowableViewRegistry::register::(cx); - - cx.observe_new( - |workspace: &mut Workspace, _window, _cx: &mut Context| { - workspace - .register_action(ContextEditor::quote_selection) - .register_action(ContextEditor::insert_selection) - .register_action(ContextEditor::copy_code) - .register_action(ContextEditor::handle_insert_dragged_files); - }, - ) - .detach(); -} diff --git a/crates/assistant_context_editor/src/context_history.rs b/crates/assistant_context_editor/src/context_history.rs deleted file mode 100644 index 2851ba8d3a..0000000000 --- a/crates/assistant_context_editor/src/context_history.rs +++ /dev/null @@ -1,271 +0,0 @@ -use std::sync::Arc; - -use gpui::{App, Entity, EventEmitter, FocusHandle, Focusable, Subscription, Task, WeakEntity}; -use picker::{Picker, PickerDelegate}; -use project::Project; -use ui::utils::{DateTimeType, format_distance_from_now}; -use ui::{Avatar, ListItem, ListItemSpacing, prelude::*}; -use workspace::{Item, Workspace}; - -use crate::{ - AgentPanelDelegate, ContextStore, DEFAULT_TAB_TITLE, RemoteContextMetadata, - SavedContextMetadata, -}; - -#[derive(Clone)] -pub enum ContextMetadata { - Remote(RemoteContextMetadata), - Saved(SavedContextMetadata), -} - -enum SavedContextPickerEvent { - Confirmed(ContextMetadata), -} - -pub struct ContextHistory { - picker: Entity>, - _subscriptions: Vec, - workspace: WeakEntity, -} - -impl ContextHistory { - pub fn new( - project: Entity, - context_store: Entity, - workspace: WeakEntity, - window: &mut Window, - cx: &mut Context, - ) -> Self { - let picker = cx.new(|cx| { - Picker::uniform_list( - SavedContextPickerDelegate::new(project, context_store.clone()), - window, - cx, - ) - .modal(false) - .max_height(None) - }); - - let subscriptions = vec![ - cx.observe_in(&context_store, window, |this, _, window, cx| { - this.picker - .update(cx, |picker, cx| picker.refresh(window, cx)); - }), - cx.subscribe_in(&picker, window, Self::handle_picker_event), - ]; - - Self { - picker, - _subscriptions: subscriptions, - workspace, - } - } - - fn handle_picker_event( - &mut self, - _: &Entity>, - event: &SavedContextPickerEvent, - window: &mut Window, - cx: &mut Context, - ) { - let SavedContextPickerEvent::Confirmed(context) = event; - - let Some(agent_panel_delegate) = ::try_global(cx) else { - return; - }; - - self.workspace - .update(cx, |workspace, cx| match context { - ContextMetadata::Remote(metadata) => { - agent_panel_delegate - .open_remote_context(workspace, metadata.id.clone(), window, cx) - .detach_and_log_err(cx); - } - ContextMetadata::Saved(metadata) => { - agent_panel_delegate - .open_saved_context(workspace, metadata.path.clone(), window, cx) - .detach_and_log_err(cx); - } - }) - .ok(); - } -} - -impl Render for ContextHistory { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { - div().size_full().child(self.picker.clone()) - } -} - -impl Focusable for ContextHistory { - fn focus_handle(&self, cx: &App) -> FocusHandle { - self.picker.focus_handle(cx) - } -} - -impl EventEmitter<()> for ContextHistory {} - -impl Item for ContextHistory { - type Event = (); - - fn tab_content_text(&self, _detail: usize, _cx: &App) -> SharedString { - "History".into() - } -} - -struct SavedContextPickerDelegate { - store: Entity, - project: Entity, - matches: Vec, - selected_index: usize, -} - -impl EventEmitter for Picker {} - -impl SavedContextPickerDelegate { - fn new(project: Entity, store: Entity) -> Self { - Self { - project, - store, - matches: Vec::new(), - selected_index: 0, - } - } -} - -impl PickerDelegate for SavedContextPickerDelegate { - type ListItem = ListItem; - - fn match_count(&self) -> usize { - self.matches.len() - } - - fn selected_index(&self) -> usize { - self.selected_index - } - - fn set_selected_index( - &mut self, - ix: usize, - _window: &mut Window, - _cx: &mut Context>, - ) { - self.selected_index = ix; - } - - fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc { - "Search...".into() - } - - fn update_matches( - &mut self, - query: String, - _window: &mut Window, - cx: &mut Context>, - ) -> Task<()> { - let search = self.store.read(cx).search(query, cx); - cx.spawn(async move |this, cx| { - let matches = search.await; - this.update(cx, |this, cx| { - let host_contexts = this.delegate.store.read(cx).host_contexts(); - this.delegate.matches = host_contexts - .iter() - .cloned() - .map(ContextMetadata::Remote) - .chain(matches.into_iter().map(ContextMetadata::Saved)) - .collect(); - this.delegate.selected_index = 0; - cx.notify(); - }) - .ok(); - }) - } - - fn confirm(&mut self, _secondary: bool, _window: &mut Window, cx: &mut Context>) { - if let Some(metadata) = self.matches.get(self.selected_index) { - cx.emit(SavedContextPickerEvent::Confirmed(metadata.clone())); - } - } - - fn dismissed(&mut self, _window: &mut Window, _cx: &mut Context>) {} - - fn render_match( - &self, - ix: usize, - selected: bool, - _window: &mut Window, - cx: &mut Context>, - ) -> Option { - let context = self.matches.get(ix)?; - let item = match context { - ContextMetadata::Remote(context) => { - let host_user = self.project.read(cx).host().and_then(|collaborator| { - self.project - .read(cx) - .user_store() - .read(cx) - .get_cached_user(collaborator.user_id) - }); - div() - .flex() - .w_full() - .justify_between() - .gap_2() - .child( - h_flex().flex_1().overflow_x_hidden().child( - Label::new(context.summary.clone().unwrap_or(DEFAULT_TAB_TITLE.into())) - .size(LabelSize::Small), - ), - ) - .child( - h_flex() - .gap_2() - .children(if let Some(host_user) = host_user { - vec![ - Avatar::new(host_user.avatar_uri.clone()).into_any_element(), - Label::new(format!("Shared by @{}", host_user.github_login)) - .color(Color::Muted) - .size(LabelSize::Small) - .into_any_element(), - ] - } else { - vec![ - Label::new("Shared by host") - .color(Color::Muted) - .size(LabelSize::Small) - .into_any_element(), - ] - }), - ) - } - ContextMetadata::Saved(context) => div() - .flex() - .w_full() - .justify_between() - .gap_2() - .child( - h_flex() - .flex_1() - .child(Label::new(context.title.clone()).size(LabelSize::Small)) - .overflow_x_hidden(), - ) - .child( - Label::new(format_distance_from_now( - DateTimeType::Local(context.mtime), - false, - true, - true, - )) - .color(Color::Muted) - .size(LabelSize::Small), - ), - }; - Some( - ListItem::new(ix) - .inset(true) - .spacing(ListItemSpacing::Sparse) - .toggle_state(selected) - .child(item), - ) - } -} diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index a91fdac992..74eff5ec4e 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -78,7 +78,7 @@ zed_llm_client.workspace = true [dev-dependencies] agent_settings.workspace = true -assistant_context_editor.workspace = true +assistant_context.workspace = true assistant_slash_command.workspace = true async-trait.workspace = true audio.workspace = true diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index f3a5d45f65..145a31a179 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -6,7 +6,7 @@ use crate::{ }, }; use anyhow::{Result, anyhow}; -use assistant_context_editor::ContextStore; +use assistant_context::ContextStore; use assistant_slash_command::SlashCommandWorkingSet; use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus, assert_hunks}; use call::{ActiveCall, ParticipantLocation, Room, room}; diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index c133e46ecd..ab84e02b19 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/crates/collab/src/tests/test_server.rs @@ -313,7 +313,7 @@ impl TestServer { settings::KeymapFile::load_asset_allow_partial_failure(os_keymap, cx).unwrap(), ); language_model::LanguageModelRegistry::test(cx); - assistant_context_editor::init(client.clone(), cx); + assistant_context::init(client.clone(), cx); agent_settings::init(cx); }); diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 78854ea644..58db67a06e 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -26,7 +26,6 @@ agent_settings.workspace = true anyhow.workspace = true askpass.workspace = true assets.workspace = true -assistant_context_editor.workspace = true assistant_tool.workspace = true assistant_tools.workspace = true audio.workspace = true diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 52a03b0adb..4cab84678c 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -9,11 +9,10 @@ mod quick_action_bar; #[cfg(target_os = "windows")] pub(crate) mod windows_only_instance; -use agent_ui::AgentDiffToolbar; +use agent_ui::{AgentDiffToolbar, AgentPanelDelegate}; use anyhow::Context as _; pub use app_menus::*; use assets::Assets; -use assistant_context_editor::AgentPanelDelegate; use breadcrumbs::Breadcrumbs; use client::zed_urls; use collections::VecDeque;