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
This commit is contained in:
Agus Zubiaga 2025-04-03 10:29:41 -03:00 committed by GitHub
parent 9693eab098
commit fe27d11f08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 32 additions and 95 deletions

View file

@ -360,73 +360,15 @@ impl ContextPicker {
} }
fn recent_entries(&self, cx: &mut App) -> Vec<RecentEntry> { fn recent_entries(&self, cx: &mut App) -> Vec<RecentEntry> {
let Some(workspace) = self.workspace.upgrade().map(|w| w.read(cx)) else { let Some(workspace) = self.workspace.upgrade() else {
return vec![]; 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![]; return vec![];
}; };
let mut recent = Vec::with_capacity(6); recent_context_picker_entries(context_store, self.thread_store.clone(), workspace, cx)
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::<AssistantPanel>(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
} }
} }
@ -480,16 +422,6 @@ fn supported_context_picker_modes(
modes modes
} }
fn active_singleton_buffer_path(workspace: &Workspace, cx: &App) -> Option<PathBuf> {
let active_item = workspace.active_item(cx)?;
let editor = active_item.to_any().downcast::<Editor>().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( fn recent_context_picker_entries(
context_store: Entity<ContextStore>, context_store: Entity<ContextStore>,
thread_store: Option<WeakEntity<ThreadStore>>, thread_store: Option<WeakEntity<ThreadStore>>,
@ -498,14 +430,8 @@ fn recent_context_picker_entries(
) -> Vec<RecentEntry> { ) -> Vec<RecentEntry> {
let mut recent = Vec::with_capacity(6); 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); 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); let project = workspace.project().read(cx);
recent.extend( recent.extend(

View file

@ -890,10 +890,10 @@ mod tests {
assert_eq!( assert_eq!(
current_completion_labels(editor), current_completion_labels(editor),
&[ &[
"editor dir/",
"seven.txt dir/b/", "seven.txt dir/b/",
"six.txt dir/b/", "six.txt dir/b/",
"five.txt dir/b/", "five.txt dir/b/",
"four.txt dir/a/",
"Files & Directories", "Files & Directories",
"Symbols", "Symbols",
"Fetch" "Fetch"
@ -988,14 +988,14 @@ mod tests {
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.text(cx), 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!(!editor.has_visible_completions_menu());
assert_eq!( assert_eq!(
crease_ranges(editor, cx), crease_ranges(editor, cx),
vec![ vec![
Point::new(0, 6)..Point::new(0, 36), 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| { editor.update(&mut cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.text(cx), 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!(editor.has_visible_completions_menu());
assert_eq!( assert_eq!(
crease_ranges(editor, cx), crease_ranges(editor, cx),
vec![ vec![
Point::new(0, 6)..Point::new(0, 36), 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| { editor.update(&mut cx, |editor, cx| {
assert_eq!( assert_eq!(
editor.text(cx), 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!(!editor.has_visible_completions_menu());
assert_eq!( assert_eq!(
crease_ranges(editor, cx), crease_ranges(editor, cx),
vec![ vec![
Point::new(0, 6)..Point::new(0, 36), Point::new(0, 6)..Point::new(0, 36),
Point::new(0, 43)..Point::new(0, 77), Point::new(0, 43)..Point::new(0, 69),
Point::new(1, 0)..Point::new(1, 30) Point::new(1, 0)..Point::new(1, 34)
] ]
); );
}); });

View file

@ -468,15 +468,9 @@ impl Matches {
path: found_path.clone(), path: found_path.clone(),
panel_match: None, panel_match: None,
}; };
self.matches
.extend(currently_opened.into_iter().map(path_to_entry));
self.matches.extend( self.matches
history_items .extend(history_items.into_iter().map(path_to_entry));
.into_iter()
.filter(|found_path| Some(*found_path) != currently_opened)
.map(path_to_entry),
);
return; return;
}; };

View file

@ -1429,8 +1429,10 @@ impl Workspace {
) -> impl Iterator<Item = (ProjectPath, Option<PathBuf>)> { ) -> impl Iterator<Item = (ProjectPath, Option<PathBuf>)> {
let mut abs_paths_opened: HashMap<PathBuf, HashSet<ProjectPath>> = HashMap::default(); let mut abs_paths_opened: HashMap<PathBuf, HashSet<ProjectPath>> = HashMap::default();
let mut history: HashMap<ProjectPath, (Option<PathBuf>, usize)> = HashMap::default(); let mut history: HashMap<ProjectPath, (Option<PathBuf>, usize)> = HashMap::default();
for pane in &self.panes { for pane in &self.panes {
let pane = pane.read(cx); let pane = pane.read(cx);
pane.nav_history() pane.nav_history()
.for_each_entry(cx, |entry, (project_path, fs_path)| { .for_each_entry(cx, |entry, (project_path, fs_path)| {
if let Some(fs_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 history
.into_iter() .into_iter()
.sorted_by_key(|(_, (_, timestamp))| *timestamp) .sorted_by_key(|(_, (_, order))| *order)
.map(|(project_path, (fs_path, _))| (project_path, fs_path)) .map(|(project_path, (fs_path, _))| (project_path, fs_path))
.rev() .rev()
.filter(move |(history_path, abs_path)| { .filter(move |(history_path, abs_path)| {