From 36d7511cdecbdef0b483411b76e24fa0c24c16d2 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Mon, 30 Dec 2024 21:32:14 -0300 Subject: [PATCH 1/7] Show active file as suggested context --- crates/assistant2/src/assistant_panel.rs | 19 ++++++++- crates/assistant2/src/context_strip.rs | 53 +++++++++++++++++++++++- crates/assistant2/src/message_editor.rs | 6 +++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index 522d2b4eea60d..0e239ca05a70f 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -26,7 +26,7 @@ use crate::{NewThread, OpenHistory, ToggleFocus}; pub fn init(cx: &mut AppContext) { cx.observe_new_views( - |workspace: &mut Workspace, _cx: &mut ViewContext| { + |workspace: &mut Workspace, cx: &mut ViewContext| { workspace .register_action(|workspace, _: &ToggleFocus, cx| { workspace.toggle_panel_focus::(cx); @@ -43,6 +43,23 @@ pub fn init(cx: &mut AppContext) { panel.update(cx, |panel, cx| panel.open_history(cx)); } }); + + cx.subscribe( + &cx.view().clone(), + move |workspace, _, event, cx| match event { + workspace::Event::ActiveItemChanged => { + if let Some(panel) = workspace.panel::(cx) { + panel.update(cx, |panel, cx| { + panel.message_editor.update(cx, |editor, cx| { + editor.update_suggested_context(&workspace, cx) + }) + }); + } + } + _ => {} + }, + ) + .detach(); }, ) .detach(); diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index 7d7bda8b3570f..10e80d2a32ec5 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/crates/assistant2/src/context_strip.rs @@ -1,6 +1,8 @@ use std::rc::Rc; +use editor::Editor; use gpui::{FocusHandle, Model, View, WeakModel, WeakView}; +use language::Buffer; use ui::{prelude::*, PopoverMenu, PopoverMenuHandle, Tooltip}; use workspace::Workspace; @@ -16,6 +18,13 @@ pub struct ContextStrip { context_picker: View, context_picker_menu_handle: PopoverMenuHandle, focus_handle: FocusHandle, + suggested_context: Option, +} + +#[derive(Clone)] +pub struct SuggestedContext { + title: SharedString, + buffer: WeakModel, } impl ContextStrip { @@ -40,8 +49,36 @@ impl ContextStrip { }), context_picker_menu_handle, focus_handle, + suggested_context: None, } } + + pub fn update_suggested_context(&mut self, workspace: &Workspace, cx: &WindowContext) { + if let Some(active_buffer) = self.get_active_buffer(workspace, cx) { + let buffer = active_buffer.read(cx); + + let title: SharedString = match buffer.file() { + Some(file) => file.path().to_string_lossy().into_owned().into(), + None => "untitled".into(), + }; + + self.suggested_context = Some(SuggestedContext { + title, + buffer: active_buffer.downgrade(), + }); + } else { + self.suggested_context = None; + } + } + + fn get_active_buffer( + &self, + workspace: &Workspace, + cx: &WindowContext, + ) -> Option> { + let editor = workspace.active_item_as::(cx)?.read(cx); + editor.buffer().read(cx).as_singleton() + } } impl Render for ContextStrip { @@ -77,7 +114,7 @@ impl Render for ContextStrip { }) .with_handle(self.context_picker_menu_handle.clone()), ) - .when(context.is_empty(), { + .when(context.is_empty() && self.suggested_context.is_none(), { |parent| { parent.child( h_flex() @@ -112,6 +149,20 @@ impl Render for ContextStrip { })) }) })) + .when_some(self.suggested_context.clone(), |el, suggested| { + el.child( + Button::new("add-suggested-context", suggested.title) + .icon(IconName::Plus) + .icon_position(IconPosition::Start) + .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) + .label_size(LabelSize::Small) + .style(ButtonStyle::Filled) + .tooltip(|cx| { + Tooltip::with_meta("Suggested Context", None, "Click to add it", cx) + }), + ) + }) .when(!context.is_empty(), { move |parent| { parent.child( diff --git a/crates/assistant2/src/message_editor.rs b/crates/assistant2/src/message_editor.rs index 3f31552e46313..de7a63bdb7256 100644 --- a/crates/assistant2/src/message_editor.rs +++ b/crates/assistant2/src/message_editor.rs @@ -194,6 +194,12 @@ impl MessageEditor { let editor_focus_handle = self.editor.focus_handle(cx); cx.focus(&editor_focus_handle); } + + pub fn update_suggested_context(&mut self, workspace: &Workspace, cx: &mut ViewContext) { + self.context_strip.update(cx, |context_strip, cx| { + context_strip.update_suggested_context(workspace, cx); + }); + } } impl FocusableView for MessageEditor { From 7d4087b876f5238bfc610411022ab8a216b02153 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 31 Dec 2024 10:46:20 -0300 Subject: [PATCH 2/7] Add suggested context on click --- crates/assistant2/src/context_strip.rs | 43 ++++++++++++++++++++------ 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index 10e80d2a32ec5..4e823d5e17631 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/crates/assistant2/src/context_strip.rs @@ -97,13 +97,17 @@ impl Render for ContextStrip { IconButton::new("add-context", IconName::Plus) .icon_size(IconSize::Small) .style(ui::ButtonStyle::Filled) - .tooltip(move |cx| { - Tooltip::for_action_in( - "Add Context", - &ToggleContextPicker, - &focus_handle, - cx, - ) + .tooltip({ + let focus_handle = focus_handle.clone(); + + move |cx| { + Tooltip::for_action_in( + "Add Context", + &ToggleContextPicker, + &focus_handle, + cx, + ) + } }), ) .attach(gpui::Corner::TopLeft) @@ -128,7 +132,7 @@ impl Render for ContextStrip { .children( ui::KeyBinding::for_action_in( &ToggleContextPicker, - &self.focus_handle, + &focus_handle, cx, ) .map(|binding| binding.into_any_element()), @@ -151,7 +155,28 @@ impl Render for ContextStrip { })) .when_some(self.suggested_context.clone(), |el, suggested| { el.child( - Button::new("add-suggested-context", suggested.title) + Button::new("add-suggested-context", suggested.title.clone()) + .on_click({ + let context_store = self.context_store.clone(); + + cx.listener(move |_this, _event, cx| { + let Some(buffer) = suggested.buffer.upgrade() else { + return; + }; + + let title = suggested.title.clone(); + let text = buffer.read(cx).text(); + + context_store.update(cx, move |context_store, _cx| { + context_store.insert_context( + crate::context::ContextKind::File, + title, + text, + ); + }); + cx.notify(); + }) + }) .icon(IconName::Plus) .icon_position(IconPosition::Start) .icon_size(IconSize::XSmall) From 5f5c005f2c6114dd0ca18c761654abdf4296b8b4 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 31 Dec 2024 10:48:20 -0300 Subject: [PATCH 3/7] Update suggested context on workspace creation --- crates/assistant2/src/assistant_panel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index 0e239ca05a70f..fd53900fa1d6d 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -47,7 +47,7 @@ pub fn init(cx: &mut AppContext) { cx.subscribe( &cx.view().clone(), move |workspace, _, event, cx| match event { - workspace::Event::ActiveItemChanged => { + workspace::Event::WorkspaceCreated(_) | workspace::Event::ActiveItemChanged => { if let Some(panel) = workspace.panel::(cx) { panel.update(cx, |panel, cx| { panel.message_editor.update(cx, |editor, cx| { From 70a099cce21101d6e179677465fff0757dacc5ed Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 31 Dec 2024 12:08:05 -0300 Subject: [PATCH 4/7] Do not suggest current file if already in the store --- crates/assistant2/src/context.rs | 5 +- crates/assistant2/src/context_picker.rs | 27 ++++++---- .../src/context_picker/file_context_picker.rs | 17 ++++-- crates/assistant2/src/context_store.rs | 10 ++++ crates/assistant2/src/context_strip.rs | 54 +++++++++++-------- crates/assistant2/src/ui/context_pill.rs | 2 +- 6 files changed, 76 insertions(+), 39 deletions(-) diff --git a/crates/assistant2/src/context.rs b/crates/assistant2/src/context.rs index 1a5a2eed95c7b..d08c96b0eef75 100644 --- a/crates/assistant2/src/context.rs +++ b/crates/assistant2/src/context.rs @@ -1,5 +1,6 @@ use gpui::SharedString; use language_model::{LanguageModelRequestMessage, MessageContent}; +use project::ProjectEntryId; use serde::{Deserialize, Serialize}; use util::post_inc; @@ -23,7 +24,7 @@ pub struct Context { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ContextKind { - File, + File(ProjectEntryId), Directory, FetchedUrl, Thread, @@ -40,7 +41,7 @@ pub fn attach_context_to_message( for context in context.into_iter() { match context.kind { - ContextKind::File => { + ContextKind::File(_) => { file_context.push_str(&context.text); file_context.push('\n'); } diff --git a/crates/assistant2/src/context_picker.rs b/crates/assistant2/src/context_picker.rs index 5b590ac47ac4a..ec3421d63f732 100644 --- a/crates/assistant2/src/context_picker.rs +++ b/crates/assistant2/src/context_picker.rs @@ -15,7 +15,6 @@ use ui::{prelude::*, ListItem, ListItemSpacing}; use util::ResultExt; use workspace::Workspace; -use crate::context::ContextKind; use crate::context_picker::directory_context_picker::DirectoryContextPicker; use crate::context_picker::fetch_context_picker::FetchContextPicker; use crate::context_picker::file_context_picker::FileContextPicker; @@ -54,7 +53,7 @@ impl ContextPicker { let mut entries = Vec::new(); entries.push(ContextPickerEntry { name: "File".into(), - kind: ContextKind::File, + kind: ContextPickerEntryKind::File, icon: IconName::File, }); let release_channel = ReleaseChannel::global(cx); @@ -63,20 +62,20 @@ impl ContextPicker { if release_channel == ReleaseChannel::Dev { entries.push(ContextPickerEntry { name: "Folder".into(), - kind: ContextKind::Directory, + kind: ContextPickerEntryKind::Directory, icon: IconName::Folder, }); } entries.push(ContextPickerEntry { name: "Fetch".into(), - kind: ContextKind::FetchedUrl, + kind: ContextPickerEntryKind::FetchedUrl, icon: IconName::Globe, }); if thread_store.is_some() { entries.push(ContextPickerEntry { name: "Thread".into(), - kind: ContextKind::Thread, + kind: ContextPickerEntryKind::Thread, icon: IconName::MessageCircle, }); } @@ -140,10 +139,18 @@ impl Render for ContextPicker { #[derive(Clone)] struct ContextPickerEntry { name: SharedString, - kind: ContextKind, + kind: ContextPickerEntryKind, icon: IconName, } +#[derive(Debug, Clone)] +enum ContextPickerEntryKind { + File, + Directory, + FetchedUrl, + Thread, +} + pub(crate) struct ContextPickerDelegate { context_picker: WeakView, workspace: WeakView, @@ -183,7 +190,7 @@ impl PickerDelegate for ContextPickerDelegate { self.context_picker .update(cx, |this, cx| { match entry.kind { - ContextKind::File => { + ContextPickerEntryKind::File => { this.mode = ContextPickerMode::File(cx.new_view(|cx| { FileContextPicker::new( self.context_picker.clone(), @@ -194,7 +201,7 @@ impl PickerDelegate for ContextPickerDelegate { ) })); } - ContextKind::Directory => { + ContextPickerEntryKind::Directory => { this.mode = ContextPickerMode::Directory(cx.new_view(|cx| { DirectoryContextPicker::new( self.context_picker.clone(), @@ -205,7 +212,7 @@ impl PickerDelegate for ContextPickerDelegate { ) })); } - ContextKind::FetchedUrl => { + ContextPickerEntryKind::FetchedUrl => { this.mode = ContextPickerMode::Fetch(cx.new_view(|cx| { FetchContextPicker::new( self.context_picker.clone(), @@ -216,7 +223,7 @@ impl PickerDelegate for ContextPickerDelegate { ) })); } - ContextKind::Thread => { + ContextPickerEntryKind::Thread => { if let Some(thread_store) = self.thread_store.as_ref() { this.mode = ContextPickerMode::Thread(cx.new_view(|cx| { ThreadContextPicker::new( diff --git a/crates/assistant2/src/context_picker/file_context_picker.rs b/crates/assistant2/src/context_picker/file_context_picker.rs index db497b43a04fe..c8258246e5001 100644 --- a/crates/assistant2/src/context_picker/file_context_picker.rs +++ b/crates/assistant2/src/context_picker/file_context_picker.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use fuzzy::PathMatch; use gpui::{AppContext, DismissEvent, FocusHandle, FocusableView, Task, View, WeakModel, WeakView}; use picker::{Picker, PickerDelegate}; -use project::{PathMatchCandidateSet, WorktreeId}; +use project::{PathMatchCandidateSet, ProjectPath, WorktreeId}; use ui::{prelude::*, ListItem}; use util::ResultExt as _; use workspace::Workspace; @@ -207,11 +207,20 @@ impl PickerDelegate for FileContextPickerDelegate { let worktree_id = WorktreeId::from_usize(mat.worktree_id); let confirm_behavior = self.confirm_behavior; cx.spawn(|this, mut cx| async move { - let Some(open_buffer_task) = project + let Some((entry_id, open_buffer_task)) = project .update(&mut cx, |project, cx| { - project.open_buffer((worktree_id, path.clone()), cx) + let project_path = ProjectPath { + worktree_id, + path: path.clone(), + }; + + let entry_id = project.entry_for_path(&project_path, cx)?.id; + let task = project.open_buffer(project_path, cx); + + Some((entry_id, task)) }) .ok() + .flatten() else { return anyhow::Ok(()); }; @@ -232,7 +241,7 @@ impl PickerDelegate for FileContextPickerDelegate { text.push_str("```\n"); context_store.insert_context( - ContextKind::File, + ContextKind::File(entry_id), path.to_string_lossy().to_string(), text, ); diff --git a/crates/assistant2/src/context_store.rs b/crates/assistant2/src/context_store.rs index febd1f597dbfa..8db5df0087469 100644 --- a/crates/assistant2/src/context_store.rs +++ b/crates/assistant2/src/context_store.rs @@ -1,4 +1,5 @@ use gpui::SharedString; +use project::ProjectEntryId; use crate::context::{Context, ContextId, ContextKind}; @@ -44,4 +45,13 @@ impl ContextStore { pub fn remove_context(&mut self, id: &ContextId) { self.context.retain(|context| context.id != *id); } + + pub fn contains_project_entry(&self, entry_id: ProjectEntryId) -> bool { + self.context.iter().any(|probe| match probe.kind { + ContextKind::File(probe_entry_id) => probe_entry_id == entry_id, + ContextKind::Directory => false, + ContextKind::FetchedUrl => false, + ContextKind::Thread => false, + }) + } } diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index 4e823d5e17631..d93bf176bc9c2 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/crates/assistant2/src/context_strip.rs @@ -3,9 +3,11 @@ use std::rc::Rc; use editor::Editor; use gpui::{FocusHandle, Model, View, WeakModel, WeakView}; use language::Buffer; +use project::ProjectEntryId; use ui::{prelude::*, PopoverMenu, PopoverMenuHandle, Tooltip}; use workspace::Workspace; +use crate::context::ContextKind; use crate::context_picker::{ConfirmBehavior, ContextPicker}; use crate::context_store::ContextStore; use crate::thread_store::ThreadStore; @@ -23,6 +25,7 @@ pub struct ContextStrip { #[derive(Clone)] pub struct SuggestedContext { + entry_id: ProjectEntryId, title: SharedString, buffer: WeakModel, } @@ -54,39 +57,46 @@ impl ContextStrip { } pub fn update_suggested_context(&mut self, workspace: &Workspace, cx: &WindowContext) { - if let Some(active_buffer) = self.get_active_buffer(workspace, cx) { - let buffer = active_buffer.read(cx); - - let title: SharedString = match buffer.file() { - Some(file) => file.path().to_string_lossy().into_owned().into(), - None => "untitled".into(), - }; - - self.suggested_context = Some(SuggestedContext { - title, - buffer: active_buffer.downgrade(), - }); - } else { - self.suggested_context = None; - } + self.suggested_context = self.get_suggested_context(workspace, cx); } - fn get_active_buffer( + fn get_suggested_context( &self, workspace: &Workspace, cx: &WindowContext, - ) -> Option> { - let editor = workspace.active_item_as::(cx)?.read(cx); - editor.buffer().read(cx).as_singleton() + ) -> Option { + let active_item = workspace.active_item(cx)?; + let entry_id = *active_item.project_entry_ids(cx).first()?; + + let editor = active_item.to_any().downcast::().ok()?.read(cx); + let active_buffer = editor.buffer().read(cx).as_singleton()?; + + let file = active_buffer.read(cx).file()?; + let title = file.path().to_string_lossy().into_owned().into(); + + Some(SuggestedContext { + entry_id, + title, + buffer: active_buffer.downgrade(), + }) } } impl Render for ContextStrip { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { - let context = self.context_store.read(cx).context().clone(); + let context_store = self.context_store.read(cx); + let context = context_store.context().clone(); let context_picker = self.context_picker.clone(); let focus_handle = self.focus_handle.clone(); + let suggested_context = self.suggested_context.as_ref().and_then(|suggested| { + if context_store.contains_project_entry(suggested.entry_id) { + None + } else { + Some(suggested.clone()) + } + }); + h_flex() .flex_wrap() .gap_1() @@ -153,7 +163,7 @@ impl Render for ContextStrip { })) }) })) - .when_some(self.suggested_context.clone(), |el, suggested| { + .when_some(suggested_context, |el, suggested| { el.child( Button::new("add-suggested-context", suggested.title.clone()) .on_click({ @@ -169,7 +179,7 @@ impl Render for ContextStrip { context_store.update(cx, move |context_store, _cx| { context_store.insert_context( - crate::context::ContextKind::File, + ContextKind::File(suggested.entry_id), title, text, ); diff --git a/crates/assistant2/src/ui/context_pill.rs b/crates/assistant2/src/ui/context_pill.rs index fb926386e2ac8..8aadc9d6a6f20 100644 --- a/crates/assistant2/src/ui/context_pill.rs +++ b/crates/assistant2/src/ui/context_pill.rs @@ -33,7 +33,7 @@ impl RenderOnce for ContextPill { px(4.) }; let icon = match self.context.kind { - ContextKind::File => IconName::File, + ContextKind::File(_) => IconName::File, ContextKind::Directory => IconName::Folder, ContextKind::FetchedUrl => IconName::Globe, ContextKind::Thread => IconName::MessageCircle, From 5b3e3f3660f091e8a7c22acbacd0f70745c35368 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 31 Dec 2024 12:22:09 -0300 Subject: [PATCH 5/7] Subscribe to workspace on context_strip --- crates/assistant2/src/assistant_panel.rs | 19 +------------------ crates/assistant2/src/context_strip.rs | 24 +++++++++++++++++++++--- crates/assistant2/src/message_editor.rs | 6 ------ 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/crates/assistant2/src/assistant_panel.rs b/crates/assistant2/src/assistant_panel.rs index fd53900fa1d6d..522d2b4eea60d 100644 --- a/crates/assistant2/src/assistant_panel.rs +++ b/crates/assistant2/src/assistant_panel.rs @@ -26,7 +26,7 @@ use crate::{NewThread, OpenHistory, ToggleFocus}; pub fn init(cx: &mut AppContext) { cx.observe_new_views( - |workspace: &mut Workspace, cx: &mut ViewContext| { + |workspace: &mut Workspace, _cx: &mut ViewContext| { workspace .register_action(|workspace, _: &ToggleFocus, cx| { workspace.toggle_panel_focus::(cx); @@ -43,23 +43,6 @@ pub fn init(cx: &mut AppContext) { panel.update(cx, |panel, cx| panel.open_history(cx)); } }); - - cx.subscribe( - &cx.view().clone(), - move |workspace, _, event, cx| match event { - workspace::Event::WorkspaceCreated(_) | workspace::Event::ActiveItemChanged => { - if let Some(panel) = workspace.panel::(cx) { - panel.update(cx, |panel, cx| { - panel.message_editor.update(cx, |editor, cx| { - editor.update_suggested_context(&workspace, cx) - }) - }); - } - } - _ => {} - }, - ) - .detach(); }, ) .detach(); diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index d93bf176bc9c2..40296187045da 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/crates/assistant2/src/context_strip.rs @@ -1,7 +1,7 @@ use std::rc::Rc; use editor::Editor; -use gpui::{FocusHandle, Model, View, WeakModel, WeakView}; +use gpui::{FocusHandle, Model, Subscription, View, WeakModel, WeakView}; use language::Buffer; use project::ProjectEntryId; use ui::{prelude::*, PopoverMenu, PopoverMenuHandle, Tooltip}; @@ -21,6 +21,7 @@ pub struct ContextStrip { context_picker_menu_handle: PopoverMenuHandle, focus_handle: FocusHandle, suggested_context: Option, + _subscription: Option, } #[derive(Clone)] @@ -39,6 +40,12 @@ impl ContextStrip { context_picker_menu_handle: PopoverMenuHandle, cx: &mut ViewContext, ) -> Self { + let subscription = if let Some(workspace) = workspace.upgrade() { + Some(cx.subscribe(&workspace, Self::handle_workspace_event)) + } else { + None + }; + Self { context_store: context_store.clone(), context_picker: cx.new_view(|cx| { @@ -53,11 +60,22 @@ impl ContextStrip { context_picker_menu_handle, focus_handle, suggested_context: None, + _subscription: subscription, } } - pub fn update_suggested_context(&mut self, workspace: &Workspace, cx: &WindowContext) { - self.suggested_context = self.get_suggested_context(workspace, cx); + fn handle_workspace_event( + &mut self, + workspace: View, + event: &workspace::Event, + cx: &mut ViewContext, + ) { + match event { + workspace::Event::WorkspaceCreated(_) | workspace::Event::ActiveItemChanged => { + self.suggested_context = self.get_suggested_context(workspace.read(cx), cx); + } + _ => {} + } } fn get_suggested_context( diff --git a/crates/assistant2/src/message_editor.rs b/crates/assistant2/src/message_editor.rs index de7a63bdb7256..3f31552e46313 100644 --- a/crates/assistant2/src/message_editor.rs +++ b/crates/assistant2/src/message_editor.rs @@ -194,12 +194,6 @@ impl MessageEditor { let editor_focus_handle = self.editor.focus_handle(cx); cx.focus(&editor_focus_handle); } - - pub fn update_suggested_context(&mut self, workspace: &Workspace, cx: &mut ViewContext) { - self.context_strip.update(cx, |context_strip, cx| { - context_strip.update_suggested_context(workspace, cx); - }); - } } impl FocusableView for MessageEditor { From 2fb529f666ddefe32116976961126c5b31b43c3b Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 31 Dec 2024 16:39:56 -0300 Subject: [PATCH 6/7] Do not suggest file in inline assistant --- crates/assistant2/src/context_strip.rs | 16 +++++++++++++++- crates/assistant2/src/inline_prompt_editor.rs | 4 +++- crates/assistant2/src/message_editor.rs | 3 ++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index 40296187045da..6f2589991fe44 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/crates/assistant2/src/context_strip.rs @@ -24,6 +24,11 @@ pub struct ContextStrip { _subscription: Option, } +pub enum SuggestContextKind { + File, + Thread, +} + #[derive(Clone)] pub struct SuggestedContext { entry_id: ProjectEntryId, @@ -38,10 +43,19 @@ impl ContextStrip { thread_store: Option>, focus_handle: FocusHandle, context_picker_menu_handle: PopoverMenuHandle, + suggest_context_kind: SuggestContextKind, cx: &mut ViewContext, ) -> Self { let subscription = if let Some(workspace) = workspace.upgrade() { - Some(cx.subscribe(&workspace, Self::handle_workspace_event)) + match suggest_context_kind { + SuggestContextKind::File => { + Some(cx.subscribe(&workspace, Self::handle_workspace_event)) + } + SuggestContextKind::Thread => { + // TODO: Suggest current thread + None + } + } } else { None }; diff --git a/crates/assistant2/src/inline_prompt_editor.rs b/crates/assistant2/src/inline_prompt_editor.rs index 4df5fe33b55bf..f14ba83c175e3 100644 --- a/crates/assistant2/src/inline_prompt_editor.rs +++ b/crates/assistant2/src/inline_prompt_editor.rs @@ -2,7 +2,7 @@ use crate::assistant_model_selector::AssistantModelSelector; use crate::buffer_codegen::BufferCodegen; use crate::context_picker::ContextPicker; use crate::context_store::ContextStore; -use crate::context_strip::ContextStrip; +use crate::context_strip::{ContextStrip, SuggestContextKind}; use crate::terminal_codegen::TerminalCodegen; use crate::thread_store::ThreadStore; use crate::{CycleNextInlineAssist, CyclePreviousInlineAssist}; @@ -793,6 +793,7 @@ impl PromptEditor { thread_store.clone(), prompt_editor.focus_handle(cx), context_picker_menu_handle.clone(), + SuggestContextKind::Thread, cx, ) }), @@ -932,6 +933,7 @@ impl PromptEditor { thread_store.clone(), prompt_editor.focus_handle(cx), context_picker_menu_handle.clone(), + SuggestContextKind::Thread, cx, ) }), diff --git a/crates/assistant2/src/message_editor.rs b/crates/assistant2/src/message_editor.rs index 3f31552e46313..7b67d93091d51 100644 --- a/crates/assistant2/src/message_editor.rs +++ b/crates/assistant2/src/message_editor.rs @@ -20,7 +20,7 @@ use workspace::Workspace; use crate::assistant_model_selector::AssistantModelSelector; use crate::context_picker::{ConfirmBehavior, ContextPicker}; use crate::context_store::ContextStore; -use crate::context_strip::ContextStrip; +use crate::context_strip::{ContextStrip, SuggestContextKind}; use crate::thread::{RequestKind, Thread}; use crate::thread_store::ThreadStore; use crate::{Chat, ToggleContextPicker, ToggleModelSelector}; @@ -87,6 +87,7 @@ impl MessageEditor { Some(thread_store.clone()), editor.focus_handle(cx), context_picker_menu_handle.clone(), + SuggestContextKind::File, cx, ) }), From a6bef03d18231814968ef71ee5e4ead9c64d7ac9 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 31 Dec 2024 19:16:05 -0300 Subject: [PATCH 7/7] Do not needlessly update suggested file --- crates/assistant2/src/context_strip.rs | 42 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/crates/assistant2/src/context_strip.rs b/crates/assistant2/src/context_strip.rs index 6f2589991fe44..a4c304fcbc6bc 100644 --- a/crates/assistant2/src/context_strip.rs +++ b/crates/assistant2/src/context_strip.rs @@ -1,11 +1,11 @@ use std::rc::Rc; use editor::Editor; -use gpui::{FocusHandle, Model, Subscription, View, WeakModel, WeakView}; +use gpui::{EntityId, FocusHandle, Model, Subscription, View, WeakModel, WeakView}; use language::Buffer; use project::ProjectEntryId; use ui::{prelude::*, PopoverMenu, PopoverMenuHandle, Tooltip}; -use workspace::Workspace; +use workspace::{ItemHandle, Workspace}; use crate::context::ContextKind; use crate::context_picker::{ConfirmBehavior, ContextPicker}; @@ -20,6 +20,7 @@ pub struct ContextStrip { context_picker: View, context_picker_menu_handle: PopoverMenuHandle, focus_handle: FocusHandle, + workspace_active_pane_id: Option, suggested_context: Option, _subscription: Option, } @@ -46,18 +47,18 @@ impl ContextStrip { suggest_context_kind: SuggestContextKind, cx: &mut ViewContext, ) -> Self { - let subscription = if let Some(workspace) = workspace.upgrade() { - match suggest_context_kind { - SuggestContextKind::File => { + let subscription = match suggest_context_kind { + SuggestContextKind::File => { + if let Some(workspace) = workspace.upgrade() { Some(cx.subscribe(&workspace, Self::handle_workspace_event)) - } - SuggestContextKind::Thread => { - // TODO: Suggest current thread + } else { None } } - } else { - None + SuggestContextKind::Thread => { + // TODO: Suggest current thread + None + } }; Self { @@ -73,6 +74,7 @@ impl ContextStrip { }), context_picker_menu_handle, focus_handle, + workspace_active_pane_id: None, suggested_context: None, _subscription: subscription, } @@ -86,18 +88,28 @@ impl ContextStrip { ) { match event { workspace::Event::WorkspaceCreated(_) | workspace::Event::ActiveItemChanged => { - self.suggested_context = self.get_suggested_context(workspace.read(cx), cx); + let workspace = workspace.read(cx); + + if let Some(active_item) = workspace.active_item(cx) { + let new_active_item_id = Some(active_item.item_id()); + + if self.workspace_active_pane_id != new_active_item_id { + self.suggested_context = Self::suggested_file(active_item, cx); + self.workspace_active_pane_id = new_active_item_id; + } + } else { + self.suggested_context = None; + self.workspace_active_pane_id = None; + } } _ => {} } } - fn get_suggested_context( - &self, - workspace: &Workspace, + fn suggested_file( + active_item: Box, cx: &WindowContext, ) -> Option { - let active_item = workspace.active_item(cx)?; let entry_id = *active_item.project_entry_ids(cx).first()?; let editor = active_item.to_any().downcast::().ok()?.read(cx);