Extract `ContextHistory` to `assistant_context_editor` (#23437)

Marshall Bowers created

This PR extracts the `ContextHistory` to the `assistant_context_editor`
crate.

Release Notes:

- N/A

Change summary

Cargo.lock                                                      |  1 
crates/assistant/Cargo.toml                                     |  1 
crates/assistant/src/assistant.rs                               |  1 
crates/assistant/src/assistant_panel.rs                         | 23 +
crates/assistant_context_editor/src/assistant_context_editor.rs |  2 
crates/assistant_context_editor/src/context_editor.rs           |  7 
crates/assistant_context_editor/src/context_history.rs          | 37 +-
7 files changed, 47 insertions(+), 25 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -403,7 +403,6 @@ dependencies = [
  "multi_buffer",
  "parking_lot",
  "paths",
- "picker",
  "pretty_assertions",
  "project",
  "prompt_library",

crates/assistant/Cargo.toml 🔗

@@ -50,7 +50,6 @@ menu.workspace = true
 multi_buffer.workspace = true
 parking_lot.workspace = true
 paths.workspace = true
-picker.workspace = true
 project.workspace = true
 prompt_library.workspace = true
 proto.workspace = true

crates/assistant/src/assistant.rs 🔗

@@ -1,7 +1,6 @@
 #![cfg_attr(target_os = "windows", allow(unused, dead_code))]
 
 pub mod assistant_panel;
-mod context_history;
 mod inline_assistant;
 pub mod slash_command_settings;
 mod terminal_inline_assistant;

crates/assistant/src/assistant_panel.rs 🔗

@@ -1,4 +1,3 @@
-use crate::context_history::ContextHistory;
 use crate::{
     terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, DeployPromptLibrary,
     InlineAssistant, NewContext, ToggleFocus,
@@ -6,9 +5,9 @@ use crate::{
 use anyhow::{anyhow, Result};
 use assistant_context_editor::{
     make_lsp_adapter_delegate, AssistantPanelDelegate, Context, ContextEditor,
-    ContextEditorToolbarItem, ContextEditorToolbarItemEvent, ContextId, ContextStore,
-    ContextStoreEvent, InsertDraggedFiles, SlashCommandCompletionProvider, ToggleModelSelector,
-    DEFAULT_TAB_TITLE,
+    ContextEditorToolbarItem, ContextEditorToolbarItemEvent, ContextHistory, ContextId,
+    ContextStore, ContextStoreEvent, InsertDraggedFiles, SlashCommandCompletionProvider,
+    ToggleModelSelector, DEFAULT_TAB_TITLE,
 };
 use assistant_settings::{AssistantDockPosition, AssistantSettings};
 use assistant_slash_command::SlashCommandWorkingSet;
@@ -966,12 +965,11 @@ impl AssistantPanel {
                 pane.activate_item(history_item_ix, true, true, cx);
             });
         } else {
-            let assistant_panel = cx.view().downgrade();
             let history = cx.new_view(|cx| {
                 ContextHistory::new(
                     self.project.clone(),
                     self.context_store.clone(),
-                    assistant_panel,
+                    self.workspace.clone(),
                     cx,
                 )
             });
@@ -1308,6 +1306,19 @@ impl AssistantPanelDelegate for ConcreteAssistantPanelDelegate {
         panel.read(cx).active_context_editor(cx)
     }
 
+    fn open_saved_context(
+        &self,
+        workspace: &mut Workspace,
+        path: PathBuf,
+        cx: &mut ViewContext<Workspace>,
+    ) -> Task<Result<()>> {
+        let Some(panel) = workspace.panel::<AssistantPanel>(cx) else {
+            return Task::ready(Err(anyhow!("no Assistant panel found")));
+        };
+
+        panel.update(cx, |panel, cx| panel.open_saved_context(path, cx))
+    }
+
     fn open_remote_context(
         &self,
         workspace: &mut Workspace,

crates/assistant_context_editor/src/assistant_context_editor.rs 🔗

@@ -1,5 +1,6 @@
 mod context;
 mod context_editor;
+mod context_history;
 mod context_store;
 mod patch;
 mod slash_command;
@@ -12,6 +13,7 @@ use gpui::AppContext;
 
 pub use crate::context::*;
 pub use crate::context_editor::*;
+pub use crate::context_history::*;
 pub use crate::context_store::*;
 pub use crate::patch::*;
 pub use crate::slash_command::*;

crates/assistant_context_editor/src/context_editor.rs 🔗

@@ -121,6 +121,13 @@ pub trait AssistantPanelDelegate {
         cx: &mut ViewContext<Workspace>,
     ) -> Option<View<ContextEditor>>;
 
+    fn open_saved_context(
+        &self,
+        workspace: &mut Workspace,
+        path: PathBuf,
+        cx: &mut ViewContext<Workspace>,
+    ) -> Task<Result<()>>;
+
     fn open_remote_context(
         &self,
         workspace: &mut Workspace,

crates/assistant/src/context_history.rs → crates/assistant_context_editor/src/context_history.rs 🔗

@@ -1,8 +1,5 @@
 use std::sync::Arc;
 
-use assistant_context_editor::{
-    ContextStore, RemoteContextMetadata, SavedContextMetadata, DEFAULT_TAB_TITLE,
-};
 use gpui::{
     AppContext, EventEmitter, FocusHandle, FocusableView, Model, Subscription, Task, View, WeakView,
 };
@@ -10,9 +7,12 @@ use picker::{Picker, PickerDelegate};
 use project::Project;
 use ui::utils::{format_distance_from_now, DateTimeType};
 use ui::{prelude::*, Avatar, ListItem, ListItemSpacing};
-use workspace::Item;
+use workspace::{Item, Workspace};
 
-use crate::AssistantPanel;
+use crate::{
+    AssistantPanelDelegate, ContextStore, RemoteContextMetadata, SavedContextMetadata,
+    DEFAULT_TAB_TITLE,
+};
 
 #[derive(Clone)]
 pub enum ContextMetadata {
@@ -27,14 +27,14 @@ enum SavedContextPickerEvent {
 pub struct ContextHistory {
     picker: View<Picker<SavedContextPickerDelegate>>,
     _subscriptions: Vec<Subscription>,
-    assistant_panel: WeakView<AssistantPanel>,
+    workspace: WeakView<Workspace>,
 }
 
 impl ContextHistory {
     pub fn new(
         project: Model<Project>,
         context_store: Model<ContextStore>,
-        assistant_panel: WeakView<AssistantPanel>,
+        workspace: WeakView<Workspace>,
         cx: &mut ViewContext<Self>,
     ) -> Self {
         let picker = cx.new_view(|cx| {
@@ -46,7 +46,7 @@ impl ContextHistory {
             .max_height(None)
         });
 
-        let _subscriptions = vec![
+        let subscriptions = vec![
             cx.observe(&context_store, |this, _, cx| {
                 this.picker.update(cx, |picker, cx| picker.refresh(cx));
             }),
@@ -55,8 +55,8 @@ impl ContextHistory {
 
         Self {
             picker,
-            _subscriptions,
-            assistant_panel,
+            _subscriptions: subscriptions,
+            workspace,
         }
     }
 
@@ -67,16 +67,21 @@ impl ContextHistory {
         cx: &mut ViewContext<Self>,
     ) {
         let SavedContextPickerEvent::Confirmed(context) = event;
-        self.assistant_panel
-            .update(cx, |assistant_panel, cx| match context {
+
+        let Some(assistant_panel_delegate) = <dyn AssistantPanelDelegate>::try_global(cx) else {
+            return;
+        };
+
+        self.workspace
+            .update(cx, |workspace, cx| match context {
                 ContextMetadata::Remote(metadata) => {
-                    assistant_panel
-                        .open_remote_context(metadata.id.clone(), cx)
+                    assistant_panel_delegate
+                        .open_remote_context(workspace, metadata.id.clone(), cx)
                         .detach_and_log_err(cx);
                 }
                 ContextMetadata::Saved(metadata) => {
-                    assistant_panel
-                        .open_saved_context(metadata.path.clone(), cx)
+                    assistant_panel_delegate
+                        .open_saved_context(workspace, metadata.path.clone(), cx)
                         .detach_and_log_err(cx);
                 }
             })