From 3e28fa2cc458560a01c764389e46e019aa833ed0 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Thu, 3 Apr 2025 10:29:41 -0300 Subject: [PATCH] agent: Include active file in recent history (#27914) This happened because of two reasons: - `Workspace::recent_navigation_history` didn't include the current file - The context picker added the current file to a exclude list The latter was actually intentional because we already show the file in the suggested context, but now that we actually have mentions, it's just inconvenient not to have it there. Release Notes: - N/A --- crates/agent/src/context_picker.rs | 82 +------------------ .../src/context_picker/completion_provider.rs | 16 ++-- crates/file_finder/src/file_finder.rs | 10 +-- crates/workspace/src/workspace.rs | 19 ++++- 4 files changed, 32 insertions(+), 95 deletions(-) diff --git a/crates/agent/src/context_picker.rs b/crates/agent/src/context_picker.rs index 6b6254cf7f167887d07eeb58ef019f1fe13fb992..a1588f3ec6257e955491acda8a81cb08167c267f 100644 --- a/crates/agent/src/context_picker.rs +++ b/crates/agent/src/context_picker.rs @@ -360,73 +360,15 @@ impl ContextPicker { } fn recent_entries(&self, cx: &mut App) -> Vec { - let Some(workspace) = self.workspace.upgrade().map(|w| w.read(cx)) else { + let Some(workspace) = self.workspace.upgrade() else { return vec![]; }; - let Some(context_store) = self.context_store.upgrade().map(|cs| cs.read(cx)) else { + let Some(context_store) = self.context_store.upgrade() else { return vec![]; }; - let mut recent = Vec::with_capacity(6); - - let mut current_files = context_store.file_paths(cx); - - if let Some(active_path) = active_singleton_buffer_path(&workspace, cx) { - current_files.insert(active_path); - } - - let project = workspace.project().read(cx); - - recent.extend( - workspace - .recent_navigation_history_iter(cx) - .filter(|(path, _)| !current_files.contains(&path.path.to_path_buf())) - .take(4) - .filter_map(|(project_path, _)| { - project - .worktree_for_id(project_path.worktree_id, cx) - .map(|worktree| RecentEntry::File { - project_path, - path_prefix: worktree.read(cx).root_name().into(), - }) - }), - ); - - let mut current_threads = context_store.thread_ids(); - - if let Some(active_thread) = workspace - .panel::(cx) - .map(|panel| panel.read(cx).active_thread(cx)) - { - current_threads.insert(active_thread.read(cx).id().clone()); - } - - let Some(thread_store) = self - .thread_store - .as_ref() - .and_then(|thread_store| thread_store.upgrade()) - else { - return recent; - }; - - thread_store.update(cx, |thread_store, _cx| { - recent.extend( - thread_store - .threads() - .into_iter() - .filter(|thread| !current_threads.contains(&thread.id)) - .take(2) - .map(|thread| { - RecentEntry::Thread(ThreadContextEntry { - id: thread.id, - summary: thread.summary, - }) - }), - ) - }); - - recent + recent_context_picker_entries(context_store, self.thread_store.clone(), workspace, cx) } } @@ -480,16 +422,6 @@ fn supported_context_picker_modes( modes } -fn active_singleton_buffer_path(workspace: &Workspace, cx: &App) -> Option { - let active_item = workspace.active_item(cx)?; - - let editor = active_item.to_any().downcast::().ok()?.read(cx); - let buffer = editor.buffer().read(cx).as_singleton()?; - - let path = buffer.read(cx).file()?.path().to_path_buf(); - Some(path) -} - fn recent_context_picker_entries( context_store: Entity, thread_store: Option>, @@ -498,14 +430,8 @@ fn recent_context_picker_entries( ) -> Vec { let mut recent = Vec::with_capacity(6); - let mut current_files = context_store.read(cx).file_paths(cx); - + let current_files = context_store.read(cx).file_paths(cx); let workspace = workspace.read(cx); - - if let Some(active_path) = active_singleton_buffer_path(workspace, cx) { - current_files.insert(active_path); - } - let project = workspace.project().read(cx); recent.extend( diff --git a/crates/agent/src/context_picker/completion_provider.rs b/crates/agent/src/context_picker/completion_provider.rs index 016d3e8567adec7521c3987a624d7ca416468c29..c0af143d7555f23d243f726ce03dd72ff033b9af 100644 --- a/crates/agent/src/context_picker/completion_provider.rs +++ b/crates/agent/src/context_picker/completion_provider.rs @@ -890,10 +890,10 @@ mod tests { assert_eq!( current_completion_labels(editor), &[ + "editor dir/", "seven.txt dir/b/", "six.txt dir/b/", "five.txt dir/b/", - "four.txt dir/a/", "Files & Directories", "Symbols", "Fetch" @@ -988,14 +988,14 @@ mod tests { editor.update(&mut cx, |editor, cx| { assert_eq!( editor.text(cx), - "Lorem [@one.txt](file:dir/a/one.txt) Ipsum [@seven.txt](file:dir/b/seven.txt)" + "Lorem [@one.txt](file:dir/a/one.txt) Ipsum [@editor](file:dir/editor)" ); assert!(!editor.has_visible_completions_menu()); assert_eq!( crease_ranges(editor, cx), vec![ Point::new(0, 6)..Point::new(0, 36), - Point::new(0, 43)..Point::new(0, 77) + Point::new(0, 43)..Point::new(0, 69) ] ); }); @@ -1005,14 +1005,14 @@ mod tests { editor.update(&mut cx, |editor, cx| { assert_eq!( editor.text(cx), - "Lorem [@one.txt](file:dir/a/one.txt) Ipsum [@seven.txt](file:dir/b/seven.txt)\n@" + "Lorem [@one.txt](file:dir/a/one.txt) Ipsum [@editor](file:dir/editor)\n@" ); assert!(editor.has_visible_completions_menu()); assert_eq!( crease_ranges(editor, cx), vec![ Point::new(0, 6)..Point::new(0, 36), - Point::new(0, 43)..Point::new(0, 77) + Point::new(0, 43)..Point::new(0, 69) ] ); }); @@ -1026,15 +1026,15 @@ mod tests { editor.update(&mut cx, |editor, cx| { assert_eq!( editor.text(cx), - "Lorem [@one.txt](file:dir/a/one.txt) Ipsum [@seven.txt](file:dir/b/seven.txt)\n[@six.txt](file:dir/b/six.txt)" + "Lorem [@one.txt](file:dir/a/one.txt) Ipsum [@editor](file:dir/editor)\n[@seven.txt](file:dir/b/seven.txt)" ); assert!(!editor.has_visible_completions_menu()); assert_eq!( crease_ranges(editor, cx), vec![ Point::new(0, 6)..Point::new(0, 36), - Point::new(0, 43)..Point::new(0, 77), - Point::new(1, 0)..Point::new(1, 30) + Point::new(0, 43)..Point::new(0, 69), + Point::new(1, 0)..Point::new(1, 34) ] ); }); diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 7bcfe9c93c167781e9b83cb676fc30724b8c3e92..1a74c4e4bb80657bf98eda5622d854e6de83c03c 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -468,15 +468,9 @@ impl Matches { path: found_path.clone(), panel_match: None, }; - self.matches - .extend(currently_opened.into_iter().map(path_to_entry)); - self.matches.extend( - history_items - .into_iter() - .filter(|found_path| Some(*found_path) != currently_opened) - .map(path_to_entry), - ); + self.matches + .extend(history_items.into_iter().map(path_to_entry)); return; }; diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 843bbd57863a6322264e1f31757361dea9031d8b..209a195a364f9acf1bf7d3bacbcde4b4f778a664 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1429,8 +1429,10 @@ impl Workspace { ) -> impl Iterator)> { let mut abs_paths_opened: HashMap> = HashMap::default(); let mut history: HashMap, usize)> = HashMap::default(); + for pane in &self.panes { let pane = pane.read(cx); + pane.nav_history() .for_each_entry(cx, |entry, (project_path, fs_path)| { if let Some(fs_path) = &fs_path { @@ -1452,11 +1454,26 @@ impl Workspace { } } }); + + if let Some(item) = pane.active_item() { + if let Some(project_path) = item.project_path(cx) { + let fs_path = self.project.read(cx).absolute_path(&project_path, cx); + + if let Some(fs_path) = &fs_path { + abs_paths_opened + .entry(fs_path.clone()) + .or_default() + .insert(project_path.clone()); + } + + history.insert(project_path, (fs_path, std::usize::MAX)); + } + } } history .into_iter() - .sorted_by_key(|(_, (_, timestamp))| *timestamp) + .sorted_by_key(|(_, (_, order))| *order) .map(|(project_path, (fs_path, _))| (project_path, fs_path)) .rev() .filter(move |(history_path, abs_path)| {