assistant2: Push logic for adding file context down into the ContextStore (#22846)

This PR takes the logic for adding file context out of the
`FileContextPicker` and pushes it down into the `ContextStore`.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-01-08 12:46:49 -05:00 committed by GitHub
parent d855eb3acb
commit 86f5bb1cc0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 68 additions and 65 deletions

View file

@ -193,81 +193,41 @@ impl PickerDelegate for FileContextPickerDelegate {
return; return;
}; };
let workspace = self.workspace.clone(); let project_path = ProjectPath {
let Some(project) = workspace worktree_id: WorktreeId::from_usize(mat.worktree_id),
.upgrade() path: mat.path.clone(),
.map(|workspace| workspace.read(cx).project().clone()) };
let Some(task) = self
.context_store
.update(cx, |context_store, cx| {
context_store.add_file(project_path, cx)
})
.ok()
else { else {
return; return;
}; };
let path = mat.path.clone();
let already_included = self let workspace = self.workspace.clone();
.context_store
.update(cx, |context_store, _cx| {
match context_store.included_file(&path) {
Some(IncludedFile::Direct(context_id)) => {
context_store.remove_context(&context_id);
true
}
Some(IncludedFile::InDirectory(_)) => true,
None => false,
}
})
.unwrap_or(true);
if already_included {
return;
}
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 Some(open_buffer_task) = project match task.await {
.update(&mut cx, |project, cx| { Ok(()) => {
let project_path = ProjectPath { this.update(&mut cx, |this, cx| match confirm_behavior {
worktree_id,
path: path.clone(),
};
let task = project.open_buffer(project_path, cx);
Some(task)
})
.ok()
.flatten()
else {
return anyhow::Ok(());
};
let result = open_buffer_task.await;
this.update(&mut cx, |this, cx| match result {
Ok(buffer) => {
this.delegate
.context_store
.update(cx, |context_store, cx| {
context_store.insert_file(buffer.read(cx));
})?;
match confirm_behavior {
ConfirmBehavior::KeepOpen => {} ConfirmBehavior::KeepOpen => {}
ConfirmBehavior::Close => this.delegate.dismissed(cx), ConfirmBehavior::Close => this.delegate.dismissed(cx),
} })?;
anyhow::Ok(())
} }
Err(err) => { Err(err) => {
let Some(workspace) = workspace.upgrade() else { let Some(workspace) = workspace.upgrade() else {
return anyhow::Ok(()); return anyhow::Ok(());
}; };
workspace.update(cx, |workspace, cx| { workspace.update(&mut cx, |workspace, cx| {
workspace.show_error(&err, cx); workspace.show_error(&err, cx);
}); })?;
anyhow::Ok(())
} }
})??; }
anyhow::Ok(()) anyhow::Ok(())
}) })

View file

@ -1,9 +1,12 @@
use std::fmt::Write as _; use std::fmt::Write as _;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::{anyhow, Result};
use collections::{HashMap, HashSet}; use collections::{HashMap, HashSet};
use gpui::SharedString; use gpui::{ModelContext, SharedString, Task, WeakView};
use language::Buffer; use language::Buffer;
use project::ProjectPath;
use workspace::Workspace;
use crate::thread::Thread; use crate::thread::Thread;
use crate::{ use crate::{
@ -12,6 +15,7 @@ use crate::{
}; };
pub struct ContextStore { pub struct ContextStore {
workspace: WeakView<Workspace>,
context: Vec<Context>, context: Vec<Context>,
next_context_id: ContextId, next_context_id: ContextId,
files: HashMap<PathBuf, ContextId>, files: HashMap<PathBuf, ContextId>,
@ -21,8 +25,9 @@ pub struct ContextStore {
} }
impl ContextStore { impl ContextStore {
pub fn new() -> Self { pub fn new(workspace: WeakView<Workspace>) -> Self {
Self { Self {
workspace,
context: Vec::new(), context: Vec::new(),
next_context_id: ContextId(0), next_context_id: ContextId(0),
files: HashMap::default(), files: HashMap::default(),
@ -44,6 +49,44 @@ impl ContextStore {
self.fetched_urls.clear(); self.fetched_urls.clear();
} }
pub fn add_file(
&mut self,
project_path: ProjectPath,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
let workspace = self.workspace.clone();
let Some(project) = workspace
.upgrade()
.map(|workspace| workspace.read(cx).project().clone())
else {
return Task::ready(Err(anyhow!("failed to read project")));
};
let already_included = match self.included_file(&project_path.path) {
Some(IncludedFile::Direct(context_id)) => {
self.remove_context(&context_id);
true
}
Some(IncludedFile::InDirectory(_)) => true,
None => false,
};
if already_included {
return Task::ready(Ok(()));
}
cx.spawn(|this, mut cx| async move {
let open_buffer_task =
project.update(&mut cx, |project, cx| project.open_buffer(project_path, cx))?;
let buffer = open_buffer_task.await?;
this.update(&mut cx, |this, cx| {
this.insert_file(buffer.read(cx));
})?;
anyhow::Ok(())
})
}
pub fn insert_file(&mut self, buffer: &Buffer) { pub fn insert_file(&mut self, buffer: &Buffer) {
let Some(file) = buffer.file() else { let Some(file) = buffer.file() else {
return; return;

View file

@ -335,7 +335,7 @@ impl InlineAssistant {
let mut assist_to_focus = None; let mut assist_to_focus = None;
for range in codegen_ranges { for range in codegen_ranges {
let assist_id = self.next_assist_id.post_inc(); let assist_id = self.next_assist_id.post_inc();
let context_store = cx.new_model(|_cx| ContextStore::new()); let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone()));
let codegen = cx.new_model(|cx| { let codegen = cx.new_model(|cx| {
BufferCodegen::new( BufferCodegen::new(
editor.read(cx).buffer().clone(), editor.read(cx).buffer().clone(),
@ -445,7 +445,7 @@ impl InlineAssistant {
range.end = range.end.bias_right(&snapshot); range.end = range.end.bias_right(&snapshot);
} }
let context_store = cx.new_model(|_cx| ContextStore::new()); let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone()));
let codegen = cx.new_model(|cx| { let codegen = cx.new_model(|cx| {
BufferCodegen::new( BufferCodegen::new(

View file

@ -47,7 +47,7 @@ impl MessageEditor {
thread: Model<Thread>, thread: Model<Thread>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
let context_store = cx.new_model(|_cx| ContextStore::new()); let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone()));
let context_picker_menu_handle = PopoverMenuHandle::default(); let context_picker_menu_handle = PopoverMenuHandle::default();
let inline_context_picker_menu_handle = PopoverMenuHandle::default(); let inline_context_picker_menu_handle = PopoverMenuHandle::default();
let model_selector_menu_handle = PopoverMenuHandle::default(); let model_selector_menu_handle = PopoverMenuHandle::default();

View file

@ -78,7 +78,7 @@ impl TerminalInlineAssistant {
let prompt_buffer = cx.new_model(|cx| { let prompt_buffer = cx.new_model(|cx| {
MultiBuffer::singleton(cx.new_model(|cx| Buffer::local(String::new(), cx)), cx) MultiBuffer::singleton(cx.new_model(|cx| Buffer::local(String::new(), cx)), cx)
}); });
let context_store = cx.new_model(|_cx| ContextStore::new()); let context_store = cx.new_model(|_cx| ContextStore::new(workspace.clone()));
let codegen = cx.new_model(|_| TerminalCodegen::new(terminal, self.telemetry.clone())); let codegen = cx.new_model(|_| TerminalCodegen::new(terminal, self.telemetry.clone()));
let prompt_editor = cx.new_view(|cx| { let prompt_editor = cx.new_view(|cx| {