assistant2: Wire up the directory context picker (#22582)

This PR wires up the functionality of the directory context picker.

Release Notes:

- N/A

---------

Co-authored-by: Agus <agus@zed.dev>
This commit is contained in:
Marshall Bowers 2025-01-02 14:42:59 -05:00 committed by GitHub
parent 3cf5ab16a9
commit 2c2ca9e370
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 75 additions and 20 deletions

1
Cargo.lock generated
View file

@ -494,7 +494,6 @@ dependencies = [
"project", "project",
"proto", "proto",
"rand 0.8.5", "rand 0.8.5",
"release_channel",
"rope", "rope",
"schemars", "schemars",
"serde", "serde",

View file

@ -50,7 +50,6 @@ parking_lot.workspace = true
picker.workspace = true picker.workspace = true
project.workspace = true project.workspace = true
proto.workspace = true proto.workspace = true
release_channel.workspace = true
rope.workspace = true rope.workspace = true
schemars.workspace = true schemars.workspace = true
serde.workspace = true serde.workspace = true

View file

@ -10,7 +10,6 @@ use gpui::{
WeakModel, WeakView, WeakModel, WeakView,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use release_channel::ReleaseChannel;
use ui::{prelude::*, ListItem, ListItemSpacing}; use ui::{prelude::*, ListItem, ListItemSpacing};
use util::ResultExt; use util::ResultExt;
use workspace::Workspace; use workspace::Workspace;
@ -56,16 +55,11 @@ impl ContextPicker {
kind: ContextPickerEntryKind::File, kind: ContextPickerEntryKind::File,
icon: IconName::File, icon: IconName::File,
}); });
let release_channel = ReleaseChannel::global(cx); entries.push(ContextPickerEntry {
// The directory context picker isn't fully implemented yet, so limit it name: "Folder".into(),
// to development builds. kind: ContextPickerEntryKind::Directory,
if release_channel == ReleaseChannel::Dev { icon: IconName::Folder,
entries.push(ContextPickerEntry { });
name: "Folder".into(),
kind: ContextPickerEntryKind::Directory,
icon: IconName::Folder,
});
}
entries.push(ContextPickerEntry { entries.push(ContextPickerEntry {
name: "Fetch".into(), name: "Fetch".into(),
kind: ContextPickerEntryKind::FetchedUrl, kind: ContextPickerEntryKind::FetchedUrl,

View file

@ -1,19 +1,18 @@
// TODO: Remove this when we finish the implementation.
#![allow(unused)]
use std::path::Path; use std::path::Path;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::Arc; use std::sync::Arc;
use anyhow::anyhow;
use fuzzy::PathMatch; use fuzzy::PathMatch;
use gpui::{AppContext, DismissEvent, FocusHandle, FocusableView, Task, View, WeakModel, WeakView}; use gpui::{AppContext, DismissEvent, FocusHandle, FocusableView, Task, View, WeakModel, WeakView};
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use project::{PathMatchCandidateSet, WorktreeId}; use project::{PathMatchCandidateSet, ProjectPath, Worktree, WorktreeId};
use ui::{prelude::*, ListItem}; use ui::{prelude::*, ListItem};
use util::ResultExt as _; use util::ResultExt as _;
use workspace::Workspace; use workspace::Workspace;
use crate::context::ContextKind; use crate::context::ContextKind;
use crate::context_picker::file_context_picker::codeblock_fence_for_path;
use crate::context_picker::{ConfirmBehavior, ContextPicker}; use crate::context_picker::{ConfirmBehavior, ContextPicker};
use crate::context_store::ContextStore; use crate::context_store::ContextStore;
@ -193,14 +192,61 @@ impl PickerDelegate for DirectoryContextPickerDelegate {
let worktree_id = WorktreeId::from_usize(mat.worktree_id); let worktree_id = WorktreeId::from_usize(mat.worktree_id);
let confirm_behavior = self.confirm_behavior; let confirm_behavior = self.confirm_behavior;
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
let worktree = project.update(&mut cx, |project, cx| {
project
.worktree_for_id(worktree_id, cx)
.ok_or_else(|| anyhow!("no worktree found for {worktree_id:?}"))
})??;
let files = worktree.update(&mut cx, |worktree, _cx| {
collect_files_in_path(worktree, &path)
})?;
let open_buffer_tasks = project.update(&mut cx, |project, cx| {
files
.into_iter()
.map(|file_path| {
project.open_buffer(
ProjectPath {
worktree_id,
path: file_path.clone(),
},
cx,
)
})
.collect::<Vec<_>>()
})?;
let open_all_buffers_tasks = cx.background_executor().spawn(async move {
let mut buffers = Vec::with_capacity(open_buffer_tasks.len());
for open_buffer_task in open_buffer_tasks {
let buffer = open_buffer_task.await?;
buffers.push(buffer);
}
anyhow::Ok(buffers)
});
let buffers = open_all_buffers_tasks.await?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let mut text = String::new(); let mut text = String::new();
// TODO: Add the files from the selected directory. for buffer in buffers {
text.push_str(&codeblock_fence_for_path(Some(&path), None));
text.push_str(&buffer.read(cx).text());
if !text.ends_with('\n') {
text.push('\n');
}
text.push_str("```\n");
}
this.delegate this.delegate
.context_store .context_store
.update(cx, |context_store, cx| { .update(cx, |context_store, _cx| {
context_store.insert_context( context_store.insert_context(
ContextKind::Directory, ContextKind::Directory,
path.to_string_lossy().to_string(), path.to_string_lossy().to_string(),
@ -247,3 +293,17 @@ impl PickerDelegate for DirectoryContextPickerDelegate {
) )
} }
} }
fn collect_files_in_path(worktree: &Worktree, path: &Path) -> Vec<Arc<Path>> {
let mut files = Vec::new();
for entry in worktree.child_entries(path) {
if entry.is_dir() {
files.extend(collect_files_in_path(worktree, &entry.path));
} else if entry.is_file() {
files.push(entry.path.clone());
}
}
files
}

View file

@ -316,7 +316,10 @@ impl PickerDelegate for FileContextPickerDelegate {
} }
} }
fn codeblock_fence_for_path(path: Option<&Path>, row_range: Option<RangeInclusive<u32>>) -> String { pub(crate) fn codeblock_fence_for_path(
path: Option<&Path>,
row_range: Option<RangeInclusive<u32>>,
) -> String {
let mut text = String::new(); let mut text = String::new();
write!(text, "```").unwrap(); write!(text, "```").unwrap();