thread_view: Fix issues with images (#36509)
- Clean up failed load tasks for mentions that require async processing - When dragging and dropping files, hold onto added worktrees until any async processing has completed; this fixes a bug when dragging items from outside the project Release Notes: - N/A
This commit is contained in:
parent
a91acb5f41
commit
df9c2aefb1
3 changed files with 85 additions and 61 deletions
|
@ -763,14 +763,16 @@ fn confirm_completion_callback(
|
||||||
message_editor
|
message_editor
|
||||||
.clone()
|
.clone()
|
||||||
.update(cx, |message_editor, cx| {
|
.update(cx, |message_editor, cx| {
|
||||||
message_editor.confirm_completion(
|
message_editor
|
||||||
crease_text,
|
.confirm_completion(
|
||||||
start,
|
crease_text,
|
||||||
content_len,
|
start,
|
||||||
mention_uri,
|
content_len,
|
||||||
window,
|
mention_uri,
|
||||||
cx,
|
window,
|
||||||
)
|
cx,
|
||||||
|
)
|
||||||
|
.detach();
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,7 +26,7 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use language::{Buffer, Language};
|
use language::{Buffer, Language};
|
||||||
use language_model::LanguageModelImage;
|
use language_model::LanguageModelImage;
|
||||||
use project::{CompletionIntent, Project, ProjectPath, Worktree};
|
use project::{Project, ProjectPath, Worktree};
|
||||||
use rope::Point;
|
use rope::Point;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -202,18 +202,18 @@ impl MessageEditor {
|
||||||
mention_uri: MentionUri,
|
mention_uri: MentionUri,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) -> Task<()> {
|
||||||
let snapshot = self
|
let snapshot = self
|
||||||
.editor
|
.editor
|
||||||
.update(cx, |editor, cx| editor.snapshot(window, cx));
|
.update(cx, |editor, cx| editor.snapshot(window, cx));
|
||||||
let Some((excerpt_id, _, _)) = snapshot.buffer_snapshot.as_singleton() else {
|
let Some((excerpt_id, _, _)) = snapshot.buffer_snapshot.as_singleton() else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
let Some(anchor) = snapshot
|
let Some(anchor) = snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.anchor_in_excerpt(*excerpt_id, start)
|
.anchor_in_excerpt(*excerpt_id, start)
|
||||||
else {
|
else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
|
|
||||||
if let MentionUri::File { abs_path, .. } = &mention_uri {
|
if let MentionUri::File { abs_path, .. } = &mention_uri {
|
||||||
|
@ -228,7 +228,7 @@ impl MessageEditor {
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.project_path_for_absolute_path(abs_path, cx)
|
.project_path_for_absolute_path(abs_path, cx)
|
||||||
else {
|
else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
let image = cx
|
let image = cx
|
||||||
.spawn(async move |_, cx| {
|
.spawn(async move |_, cx| {
|
||||||
|
@ -252,9 +252,9 @@ impl MessageEditor {
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
) else {
|
) else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
self.confirm_mention_for_image(
|
return self.confirm_mention_for_image(
|
||||||
crease_id,
|
crease_id,
|
||||||
anchor,
|
anchor,
|
||||||
Some(abs_path.clone()),
|
Some(abs_path.clone()),
|
||||||
|
@ -262,7 +262,6 @@ impl MessageEditor {
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,27 +275,28 @@ impl MessageEditor {
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
) else {
|
) else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
|
|
||||||
match mention_uri {
|
match mention_uri {
|
||||||
MentionUri::Fetch { url } => {
|
MentionUri::Fetch { url } => {
|
||||||
self.confirm_mention_for_fetch(crease_id, anchor, url, window, cx);
|
self.confirm_mention_for_fetch(crease_id, anchor, url, window, cx)
|
||||||
}
|
}
|
||||||
MentionUri::Directory { abs_path } => {
|
MentionUri::Directory { abs_path } => {
|
||||||
self.confirm_mention_for_directory(crease_id, anchor, abs_path, window, cx);
|
self.confirm_mention_for_directory(crease_id, anchor, abs_path, window, cx)
|
||||||
}
|
}
|
||||||
MentionUri::Thread { id, name } => {
|
MentionUri::Thread { id, name } => {
|
||||||
self.confirm_mention_for_thread(crease_id, anchor, id, name, window, cx);
|
self.confirm_mention_for_thread(crease_id, anchor, id, name, window, cx)
|
||||||
}
|
}
|
||||||
MentionUri::TextThread { path, name } => {
|
MentionUri::TextThread { path, name } => {
|
||||||
self.confirm_mention_for_text_thread(crease_id, anchor, path, name, window, cx);
|
self.confirm_mention_for_text_thread(crease_id, anchor, path, name, window, cx)
|
||||||
}
|
}
|
||||||
MentionUri::File { .. }
|
MentionUri::File { .. }
|
||||||
| MentionUri::Symbol { .. }
|
| MentionUri::Symbol { .. }
|
||||||
| MentionUri::Rule { .. }
|
| MentionUri::Rule { .. }
|
||||||
| MentionUri::Selection { .. } => {
|
| MentionUri::Selection { .. } => {
|
||||||
self.mention_set.insert_uri(crease_id, mention_uri.clone());
|
self.mention_set.insert_uri(crease_id, mention_uri.clone());
|
||||||
|
Task::ready(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,7 +308,7 @@ impl MessageEditor {
|
||||||
abs_path: PathBuf,
|
abs_path: PathBuf,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) -> Task<()> {
|
||||||
fn collect_files_in_path(worktree: &Worktree, path: &Path) -> Vec<(Arc<Path>, PathBuf)> {
|
fn collect_files_in_path(worktree: &Worktree, path: &Path) -> Vec<(Arc<Path>, PathBuf)> {
|
||||||
let mut files = Vec::new();
|
let mut files = Vec::new();
|
||||||
|
|
||||||
|
@ -331,13 +331,13 @@ impl MessageEditor {
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.project_path_for_absolute_path(&abs_path, cx)
|
.project_path_for_absolute_path(&abs_path, cx)
|
||||||
else {
|
else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
let Some(entry) = self.project.read(cx).entry_for_path(&project_path, cx) else {
|
let Some(entry) = self.project.read(cx).entry_for_path(&project_path, cx) else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
let Some(worktree) = self.project.read(cx).worktree_for_entry(entry.id, cx) else {
|
let Some(worktree) = self.project.read(cx).worktree_for_entry(entry.id, cx) else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
let project = self.project.clone();
|
let project = self.project.clone();
|
||||||
let task = cx.spawn(async move |_, cx| {
|
let task = cx.spawn(async move |_, cx| {
|
||||||
|
@ -396,7 +396,9 @@ impl MessageEditor {
|
||||||
})
|
})
|
||||||
.shared();
|
.shared();
|
||||||
|
|
||||||
self.mention_set.directories.insert(abs_path, task.clone());
|
self.mention_set
|
||||||
|
.directories
|
||||||
|
.insert(abs_path.clone(), task.clone());
|
||||||
|
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
cx.spawn_in(window, async move |this, cx| {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
|
@ -414,9 +416,12 @@ impl MessageEditor {
|
||||||
editor.remove_creases([crease_id], cx);
|
editor.remove_creases([crease_id], cx);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
this.update(cx, |this, _cx| {
|
||||||
|
this.mention_set.directories.remove(&abs_path);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_mention_for_fetch(
|
fn confirm_mention_for_fetch(
|
||||||
|
@ -426,13 +431,13 @@ impl MessageEditor {
|
||||||
url: url::Url,
|
url: url::Url,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) -> Task<()> {
|
||||||
let Some(http_client) = self
|
let Some(http_client) = self
|
||||||
.workspace
|
.workspace
|
||||||
.update(cx, |workspace, _cx| workspace.client().http_client())
|
.update(cx, |workspace, _cx| workspace.client().http_client())
|
||||||
.ok()
|
.ok()
|
||||||
else {
|
else {
|
||||||
return;
|
return Task::ready(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let url_string = url.to_string();
|
let url_string = url.to_string();
|
||||||
|
@ -450,9 +455,9 @@ impl MessageEditor {
|
||||||
cx.spawn_in(window, async move |this, cx| {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
let fetch = fetch.await.notify_async_err(cx);
|
let fetch = fetch.await.notify_async_err(cx);
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
let mention_uri = MentionUri::Fetch { url };
|
|
||||||
if fetch.is_some() {
|
if fetch.is_some() {
|
||||||
this.mention_set.insert_uri(crease_id, mention_uri.clone());
|
this.mention_set
|
||||||
|
.insert_uri(crease_id, MentionUri::Fetch { url });
|
||||||
} else {
|
} else {
|
||||||
// Remove crease if we failed to fetch
|
// Remove crease if we failed to fetch
|
||||||
this.editor.update(cx, |editor, cx| {
|
this.editor.update(cx, |editor, cx| {
|
||||||
|
@ -461,11 +466,11 @@ impl MessageEditor {
|
||||||
});
|
});
|
||||||
editor.remove_creases([crease_id], cx);
|
editor.remove_creases([crease_id], cx);
|
||||||
});
|
});
|
||||||
|
this.mention_set.fetch_results.remove(&url);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
})
|
})
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn confirm_mention_for_selection(
|
pub fn confirm_mention_for_selection(
|
||||||
|
@ -528,7 +533,7 @@ impl MessageEditor {
|
||||||
name: String,
|
name: String,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) -> Task<()> {
|
||||||
let uri = MentionUri::Thread {
|
let uri = MentionUri::Thread {
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
name,
|
name,
|
||||||
|
@ -546,7 +551,7 @@ impl MessageEditor {
|
||||||
})
|
})
|
||||||
.shared();
|
.shared();
|
||||||
|
|
||||||
self.mention_set.insert_thread(id, task.clone());
|
self.mention_set.insert_thread(id.clone(), task.clone());
|
||||||
|
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
cx.spawn_in(window, async move |this, cx| {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
|
@ -564,9 +569,12 @@ impl MessageEditor {
|
||||||
editor.remove_creases([crease_id], cx);
|
editor.remove_creases([crease_id], cx);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
this.update(cx, |this, _| {
|
||||||
|
this.mention_set.thread_summaries.remove(&id);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_mention_for_text_thread(
|
fn confirm_mention_for_text_thread(
|
||||||
|
@ -577,7 +585,7 @@ impl MessageEditor {
|
||||||
name: String,
|
name: String,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) -> Task<()> {
|
||||||
let uri = MentionUri::TextThread {
|
let uri = MentionUri::TextThread {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
name,
|
name,
|
||||||
|
@ -595,7 +603,8 @@ impl MessageEditor {
|
||||||
})
|
})
|
||||||
.shared();
|
.shared();
|
||||||
|
|
||||||
self.mention_set.insert_text_thread(path, task.clone());
|
self.mention_set
|
||||||
|
.insert_text_thread(path.clone(), task.clone());
|
||||||
|
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
cx.spawn_in(window, async move |this, cx| {
|
cx.spawn_in(window, async move |this, cx| {
|
||||||
|
@ -613,9 +622,12 @@ impl MessageEditor {
|
||||||
editor.remove_creases([crease_id], cx);
|
editor.remove_creases([crease_id], cx);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
this.update(cx, |this, _| {
|
||||||
|
this.mention_set.text_thread_summaries.remove(&path);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contents(
|
pub fn contents(
|
||||||
|
@ -784,13 +796,15 @@ impl MessageEditor {
|
||||||
) else {
|
) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.confirm_mention_for_image(crease_id, anchor, None, task, window, cx);
|
self.confirm_mention_for_image(crease_id, anchor, None, task, window, cx)
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_dragged_files(
|
pub fn insert_dragged_files(
|
||||||
&self,
|
&mut self,
|
||||||
paths: Vec<project::ProjectPath>,
|
paths: Vec<project::ProjectPath>,
|
||||||
|
added_worktrees: Vec<Entity<Worktree>>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -798,6 +812,7 @@ impl MessageEditor {
|
||||||
let Some(buffer) = buffer.read(cx).as_singleton() else {
|
let Some(buffer) = buffer.read(cx).as_singleton() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let mut tasks = Vec::new();
|
||||||
for path in paths {
|
for path in paths {
|
||||||
let Some(entry) = self.project.read(cx).entry_for_path(&path, cx) else {
|
let Some(entry) = self.project.read(cx).entry_for_path(&path, cx) else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -805,39 +820,44 @@ impl MessageEditor {
|
||||||
let Some(abs_path) = self.project.read(cx).absolute_path(&path, cx) else {
|
let Some(abs_path) = self.project.read(cx).absolute_path(&path, cx) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let anchor = buffer.update(cx, |buffer, _cx| buffer.anchor_before(buffer.len()));
|
|
||||||
let path_prefix = abs_path
|
let path_prefix = abs_path
|
||||||
.file_name()
|
.file_name()
|
||||||
.unwrap_or(path.path.as_os_str())
|
.unwrap_or(path.path.as_os_str())
|
||||||
.display()
|
.display()
|
||||||
.to_string();
|
.to_string();
|
||||||
let Some(completion) = ContextPickerCompletionProvider::completion_for_path(
|
let (file_name, _) =
|
||||||
path,
|
crate::context_picker::file_context_picker::extract_file_name_and_directory(
|
||||||
&path_prefix,
|
&path.path,
|
||||||
false,
|
&path_prefix,
|
||||||
entry.is_dir(),
|
);
|
||||||
anchor..anchor,
|
|
||||||
cx.weak_entity(),
|
let uri = if entry.is_dir() {
|
||||||
self.project.clone(),
|
MentionUri::Directory { abs_path }
|
||||||
cx,
|
} else {
|
||||||
) else {
|
MentionUri::File { abs_path }
|
||||||
continue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let new_text = format!("{} ", uri.as_link());
|
||||||
|
let content_len = new_text.len() - 1;
|
||||||
|
|
||||||
|
let anchor = buffer.update(cx, |buffer, _cx| buffer.anchor_before(buffer.len()));
|
||||||
|
|
||||||
self.editor.update(cx, |message_editor, cx| {
|
self.editor.update(cx, |message_editor, cx| {
|
||||||
message_editor.edit(
|
message_editor.edit(
|
||||||
[(
|
[(
|
||||||
multi_buffer::Anchor::max()..multi_buffer::Anchor::max(),
|
multi_buffer::Anchor::max()..multi_buffer::Anchor::max(),
|
||||||
completion.new_text,
|
new_text,
|
||||||
)],
|
)],
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if let Some(confirm) = completion.confirm.clone() {
|
tasks.push(self.confirm_completion(file_name, anchor, content_len, uri, window, cx));
|
||||||
confirm(CompletionIntent::Complete, window, cx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
cx.spawn(async move |_, _| {
|
||||||
|
join_all(tasks).await;
|
||||||
|
drop(added_worktrees);
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_read_only(&mut self, read_only: bool, cx: &mut Context<Self>) {
|
pub fn set_read_only(&mut self, read_only: bool, cx: &mut Context<Self>) {
|
||||||
|
@ -855,7 +875,7 @@ impl MessageEditor {
|
||||||
image: Shared<Task<Result<Arc<Image>, String>>>,
|
image: Shared<Task<Result<Arc<Image>, String>>>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) -> Task<()> {
|
||||||
let editor = self.editor.clone();
|
let editor = self.editor.clone();
|
||||||
let task = cx
|
let task = cx
|
||||||
.spawn_in(window, {
|
.spawn_in(window, {
|
||||||
|
@ -900,9 +920,12 @@ impl MessageEditor {
|
||||||
editor.remove_creases([crease_id], cx);
|
editor.remove_creases([crease_id], cx);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
this.update(cx, |this, _cx| {
|
||||||
|
this.mention_set.images.remove(&crease_id);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mode(&mut self, mode: EditorMode, cx: &mut Context<Self>) {
|
pub fn set_mode(&mut self, mode: EditorMode, cx: &mut Context<Self>) {
|
||||||
|
|
|
@ -3429,8 +3429,7 @@ impl AcpThreadView {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
self.message_editor.update(cx, |message_editor, cx| {
|
self.message_editor.update(cx, |message_editor, cx| {
|
||||||
message_editor.insert_dragged_files(paths, window, cx);
|
message_editor.insert_dragged_files(paths, added_worktrees, window, cx);
|
||||||
drop(added_worktrees);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue