diff --git a/crates/agent/src/context.rs b/crates/agent/src/context.rs index 98437778aa..62106e1968 100644 --- a/crates/agent/src/context.rs +++ b/crates/agent/src/context.rs @@ -734,6 +734,7 @@ impl Display for RulesContext { #[derive(Debug, Clone)] pub struct ImageContext { pub project_path: Option, + pub full_path: Option>, pub original_image: Arc, // TODO: handle this elsewhere and remove `ignore-interior-mutability` opt-out in clippy.toml // needed due to a false positive of `clippy::mutable_key_type`. diff --git a/crates/agent/src/context_store.rs b/crates/agent/src/context_store.rs index 110db59864..f4697d9eb4 100644 --- a/crates/agent/src/context_store.rs +++ b/crates/agent/src/context_store.rs @@ -7,7 +7,7 @@ use assistant_context_editor::AssistantContext; use collections::{HashSet, IndexSet}; use futures::{self, FutureExt}; use gpui::{App, Context, Entity, EventEmitter, Image, SharedString, Task, WeakEntity}; -use language::Buffer; +use language::{Buffer, File as _}; use language_model::LanguageModelImage; use project::image_store::is_image_file; use project::{Project, ProjectItem, ProjectPath, Symbol}; @@ -304,11 +304,13 @@ impl ContextStore { project.open_image(project_path.clone(), cx) })?; let image_item = open_image_task.await?; - let image = image_item.read_with(cx, |image_item, _| image_item.image.clone())?; + this.update(cx, |this, cx| { + let item = image_item.read(cx); this.insert_image( - Some(image_item.read(cx).project_path(cx)), - image, + Some(item.project_path(cx)), + Some(item.file.full_path(cx).into()), + item.image.clone(), remove_if_exists, cx, ) @@ -317,12 +319,13 @@ impl ContextStore { } pub fn add_image_instance(&mut self, image: Arc, cx: &mut Context) { - self.insert_image(None, image, false, cx); + self.insert_image(None, None, image, false, cx); } fn insert_image( &mut self, project_path: Option, + full_path: Option>, image: Arc, remove_if_exists: bool, cx: &mut Context, @@ -330,6 +333,7 @@ impl ContextStore { let image_task = LanguageModelImage::from_image(image.clone(), cx).shared(); let context = AgentContextHandle::Image(ImageContext { project_path, + full_path, original_image: image, image_task, context_id: self.next_context_id.post_inc(), diff --git a/crates/agent/src/ui/context_pill.rs b/crates/agent/src/ui/context_pill.rs index fe59889d25..605a142980 100644 --- a/crates/agent/src/ui/context_pill.rs +++ b/crates/agent/src/ui/context_pill.rs @@ -304,7 +304,7 @@ impl AddedContext { AgentContextHandle::Thread(handle) => Some(Self::pending_thread(handle, cx)), AgentContextHandle::TextThread(handle) => Some(Self::pending_text_thread(handle, cx)), AgentContextHandle::Rules(handle) => Self::pending_rules(handle, prompt_store, cx), - AgentContextHandle::Image(handle) => Some(Self::image(handle)), + AgentContextHandle::Image(handle) => Some(Self::image(handle, cx)), } } @@ -318,7 +318,7 @@ impl AddedContext { AgentContext::Thread(context) => Self::attached_thread(context), AgentContext::TextThread(context) => Self::attached_text_thread(context), AgentContext::Rules(context) => Self::attached_rules(context), - AgentContext::Image(context) => Self::image(context.clone()), + AgentContext::Image(context) => Self::image(context.clone(), cx), } } @@ -333,14 +333,8 @@ impl AddedContext { fn file(handle: FileContextHandle, full_path: &Path, cx: &App) -> AddedContext { let full_path_string: SharedString = full_path.to_string_lossy().into_owned().into(); - let name = full_path - .file_name() - .map(|n| n.to_string_lossy().into_owned().into()) - .unwrap_or_else(|| full_path_string.clone()); - let parent = full_path - .parent() - .and_then(|p| p.file_name()) - .map(|n| n.to_string_lossy().into_owned().into()); + let (name, parent) = + extract_file_name_and_directory_from_full_path(full_path, &full_path_string); AddedContext { kind: ContextKind::File, name, @@ -370,14 +364,8 @@ impl AddedContext { fn directory(handle: DirectoryContextHandle, full_path: &Path) -> AddedContext { let full_path_string: SharedString = full_path.to_string_lossy().into_owned().into(); - let name = full_path - .file_name() - .map(|n| n.to_string_lossy().into_owned().into()) - .unwrap_or_else(|| full_path_string.clone()); - let parent = full_path - .parent() - .and_then(|p| p.file_name()) - .map(|n| n.to_string_lossy().into_owned().into()); + let (name, parent) = + extract_file_name_and_directory_from_full_path(full_path, &full_path_string); AddedContext { kind: ContextKind::Directory, name, @@ -605,13 +593,23 @@ impl AddedContext { } } - fn image(context: ImageContext) -> AddedContext { + fn image(context: ImageContext, cx: &App) -> AddedContext { + let (name, parent, icon_path) = if let Some(full_path) = context.full_path.as_ref() { + let full_path_string: SharedString = full_path.to_string_lossy().into_owned().into(); + let (name, parent) = + extract_file_name_and_directory_from_full_path(full_path, &full_path_string); + let icon_path = FileIcons::get_icon(&full_path, cx); + (name, parent, icon_path) + } else { + ("Image".into(), None, None) + }; + AddedContext { kind: ContextKind::Image, - name: "Image".into(), - parent: None, + name, + parent, tooltip: None, - icon_path: None, + icon_path, status: match context.status() { ImageStatus::Loading => ContextStatus::Loading { message: "Loading…".into(), @@ -639,6 +637,22 @@ impl AddedContext { } } +fn extract_file_name_and_directory_from_full_path( + path: &Path, + name_fallback: &SharedString, +) -> (SharedString, Option) { + let name = path + .file_name() + .map(|n| n.to_string_lossy().into_owned().into()) + .unwrap_or_else(|| name_fallback.clone()); + let parent = path + .parent() + .and_then(|p| p.file_name()) + .map(|n| n.to_string_lossy().into_owned().into()); + + (name, parent) +} + #[derive(Debug, Clone)] struct ContextFileExcerpt { pub file_name_and_range: SharedString, @@ -765,37 +779,49 @@ impl Component for AddedContext { let mut next_context_id = ContextId::zero(); let image_ready = ( "Ready", - AddedContext::image(ImageContext { - context_id: next_context_id.post_inc(), - project_path: None, - original_image: Arc::new(Image::empty()), - image_task: Task::ready(Some(LanguageModelImage::empty())).shared(), - }), + AddedContext::image( + ImageContext { + context_id: next_context_id.post_inc(), + project_path: None, + full_path: None, + original_image: Arc::new(Image::empty()), + image_task: Task::ready(Some(LanguageModelImage::empty())).shared(), + }, + cx, + ), ); let image_loading = ( "Loading", - AddedContext::image(ImageContext { - context_id: next_context_id.post_inc(), - project_path: None, - original_image: Arc::new(Image::empty()), - image_task: cx - .background_spawn(async move { - smol::Timer::after(Duration::from_secs(60 * 5)).await; - Some(LanguageModelImage::empty()) - }) - .shared(), - }), + AddedContext::image( + ImageContext { + context_id: next_context_id.post_inc(), + project_path: None, + full_path: None, + original_image: Arc::new(Image::empty()), + image_task: cx + .background_spawn(async move { + smol::Timer::after(Duration::from_secs(60 * 5)).await; + Some(LanguageModelImage::empty()) + }) + .shared(), + }, + cx, + ), ); let image_error = ( "Error", - AddedContext::image(ImageContext { - context_id: next_context_id.post_inc(), - project_path: None, - original_image: Arc::new(Image::empty()), - image_task: Task::ready(None).shared(), - }), + AddedContext::image( + ImageContext { + context_id: next_context_id.post_inc(), + project_path: None, + full_path: None, + original_image: Arc::new(Image::empty()), + image_task: Task::ready(None).shared(), + }, + cx, + ), ); Some(