Compare commits
9 Commits
git-graph
...
agent-past
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87251198ef | ||
|
|
7997c29260 | ||
|
|
23c1556b9e | ||
|
|
67e4361040 | ||
|
|
0317d0497d | ||
|
|
f2476cf44e | ||
|
|
32ece6eba8 | ||
|
|
48e728e086 | ||
|
|
302d91ddd9 |
@@ -21,8 +21,8 @@ use editor::{
|
||||
};
|
||||
use futures::{FutureExt as _, future::join_all};
|
||||
use gpui::{
|
||||
AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, ImageFormat, KeyContext,
|
||||
SharedString, Subscription, Task, TextStyle, WeakEntity,
|
||||
AppContext, ClipboardEntry, Context, Entity, EventEmitter, FocusHandle, Focusable, ImageFormat,
|
||||
KeyContext, SharedString, Subscription, Task, TextStyle, WeakEntity,
|
||||
};
|
||||
use language::{Buffer, Language, language_settings::InlayHintKind};
|
||||
use project::{CompletionIntent, InlayHint, InlayHintLabel, InlayId, Project, Worktree};
|
||||
@@ -543,6 +543,120 @@ impl MessageEditor {
|
||||
}
|
||||
|
||||
fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let editor_clipboard_selections = cx
|
||||
.read_from_clipboard()
|
||||
.and_then(|item| item.entries().first().cloned())
|
||||
.and_then(|entry| match entry {
|
||||
ClipboardEntry::String(text) => {
|
||||
text.metadata_json::<Vec<editor::ClipboardSelection>>()
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let has_file_context = editor_clipboard_selections
|
||||
.as_ref()
|
||||
.is_some_and(|selections| {
|
||||
selections
|
||||
.iter()
|
||||
.any(|sel| sel.file_path.is_some() && sel.line_range.is_some())
|
||||
});
|
||||
|
||||
if has_file_context {
|
||||
if let Some((workspace, selections)) =
|
||||
self.workspace.upgrade().zip(editor_clipboard_selections)
|
||||
{
|
||||
cx.stop_propagation();
|
||||
|
||||
let project = workspace.read(cx).project().clone();
|
||||
for selection in selections {
|
||||
if let (Some(file_path), Some(line_range)) =
|
||||
(selection.file_path, selection.line_range)
|
||||
{
|
||||
let crease_text =
|
||||
acp_thread::selection_name(Some(file_path.as_ref()), &line_range);
|
||||
|
||||
let mention_uri = MentionUri::Selection {
|
||||
abs_path: Some(file_path.clone()),
|
||||
line_range: line_range.clone(),
|
||||
};
|
||||
|
||||
let mention_text = mention_uri.as_link().to_string();
|
||||
let (excerpt_id, text_anchor, content_len) =
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
let buffer = editor.buffer().read(cx);
|
||||
let snapshot = buffer.snapshot(cx);
|
||||
let (excerpt_id, _, buffer_snapshot) =
|
||||
snapshot.as_singleton().unwrap();
|
||||
let start_offset = buffer_snapshot.len();
|
||||
let text_anchor = buffer_snapshot.anchor_before(start_offset);
|
||||
|
||||
editor.insert(&mention_text, window, cx);
|
||||
editor.insert(" ", window, cx);
|
||||
|
||||
(*excerpt_id, text_anchor, mention_text.len())
|
||||
});
|
||||
|
||||
let Some((crease_id, tx)) = insert_crease_for_mention(
|
||||
excerpt_id,
|
||||
text_anchor,
|
||||
content_len,
|
||||
crease_text.into(),
|
||||
mention_uri.icon_path(cx),
|
||||
None,
|
||||
self.editor.clone(),
|
||||
window,
|
||||
cx,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
drop(tx);
|
||||
|
||||
let mention_task = cx
|
||||
.spawn({
|
||||
let project = project.clone();
|
||||
async move |_, cx| {
|
||||
let project_path = project
|
||||
.update(cx, |project, cx| {
|
||||
project.project_path_for_absolute_path(&file_path, cx)
|
||||
})
|
||||
.map_err(|e| e.to_string())?
|
||||
.ok_or_else(|| "project path not found".to_string())?;
|
||||
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_buffer(project_path, cx)
|
||||
})
|
||||
.map_err(|e| e.to_string())?
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
buffer
|
||||
.update(cx, |buffer, cx| {
|
||||
let start = Point::new(*line_range.start(), 0)
|
||||
.min(buffer.max_point());
|
||||
let end = Point::new(*line_range.end() + 1, 0)
|
||||
.min(buffer.max_point());
|
||||
let content =
|
||||
buffer.text_for_range(start..end).collect();
|
||||
Mention::Text {
|
||||
content,
|
||||
tracked_buffers: vec![cx.entity()],
|
||||
}
|
||||
})
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
})
|
||||
.shared();
|
||||
|
||||
self.mention_set.update(cx, |mention_set, _cx| {
|
||||
mention_set.insert_mention(crease_id, mention_uri.clone(), mention_task)
|
||||
});
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if self.prompt_capabilities.borrow().image
|
||||
&& let Some(task) =
|
||||
paste_images_as_context(self.editor.clone(), self.mention_set.clone(), window, cx)
|
||||
|
||||
@@ -1682,6 +1682,98 @@ impl TextThreadEditor {
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let editor_clipboard_selections = cx
|
||||
.read_from_clipboard()
|
||||
.and_then(|item| item.entries().first().cloned())
|
||||
.and_then(|entry| match entry {
|
||||
ClipboardEntry::String(text) => {
|
||||
text.metadata_json::<Vec<editor::ClipboardSelection>>()
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let has_file_context = editor_clipboard_selections
|
||||
.as_ref()
|
||||
.is_some_and(|selections| {
|
||||
selections
|
||||
.iter()
|
||||
.any(|sel| sel.file_path.is_some() && sel.line_range.is_some())
|
||||
});
|
||||
|
||||
if has_file_context {
|
||||
if let Some(clipboard_item) = cx.read_from_clipboard() {
|
||||
if let Some(ClipboardEntry::String(clipboard_text)) =
|
||||
clipboard_item.entries().first()
|
||||
{
|
||||
if let Some(selections) = editor_clipboard_selections {
|
||||
cx.stop_propagation();
|
||||
|
||||
let text = clipboard_text.text();
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
let mut current_offset = 0;
|
||||
let weak_editor = cx.entity().downgrade();
|
||||
|
||||
for selection in selections {
|
||||
if let (Some(file_path), Some(line_range)) =
|
||||
(selection.file_path, selection.line_range)
|
||||
{
|
||||
let selected_text =
|
||||
&text[current_offset..current_offset + selection.len];
|
||||
let fence = assistant_slash_commands::codeblock_fence_for_path(
|
||||
file_path.to_str(),
|
||||
Some(line_range.clone()),
|
||||
);
|
||||
let formatted_text = format!("{fence}{selected_text}\n```");
|
||||
|
||||
let insert_point = editor
|
||||
.selections
|
||||
.newest::<Point>(&editor.display_snapshot(cx))
|
||||
.head();
|
||||
let start_row = MultiBufferRow(insert_point.row);
|
||||
|
||||
editor.insert(&formatted_text, window, cx);
|
||||
|
||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
let anchor_before = snapshot.anchor_after(insert_point);
|
||||
let anchor_after = editor
|
||||
.selections
|
||||
.newest_anchor()
|
||||
.head()
|
||||
.bias_left(&snapshot);
|
||||
|
||||
editor.insert("\n", window, cx);
|
||||
|
||||
let crease_text = acp_thread::selection_name(
|
||||
Some(file_path.as_ref()),
|
||||
&line_range,
|
||||
);
|
||||
|
||||
let fold_placeholder = quote_selection_fold_placeholder(
|
||||
crease_text,
|
||||
weak_editor.clone(),
|
||||
);
|
||||
let crease = Crease::inline(
|
||||
anchor_before..anchor_after,
|
||||
fold_placeholder,
|
||||
render_quote_selection_output_toggle,
|
||||
|_, _, _, _| Empty.into_any(),
|
||||
);
|
||||
editor.insert_creases(vec![crease], cx);
|
||||
editor.fold_at(start_row, window, cx);
|
||||
|
||||
current_offset += selection.len;
|
||||
if !selection.is_entire_line && current_offset < text.len() {
|
||||
current_offset += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cx.stop_propagation();
|
||||
|
||||
let mut images = if let Some(item) = cx.read_from_clipboard() {
|
||||
|
||||
@@ -1592,6 +1592,45 @@ pub struct ClipboardSelection {
|
||||
pub is_entire_line: bool,
|
||||
/// The indentation of the first line when this content was originally copied.
|
||||
pub first_line_indent: u32,
|
||||
#[serde(default)]
|
||||
pub file_path: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub line_range: Option<RangeInclusive<u32>>,
|
||||
}
|
||||
|
||||
impl ClipboardSelection {
|
||||
pub fn for_buffer(
|
||||
len: usize,
|
||||
is_entire_line: bool,
|
||||
range: Range<Point>,
|
||||
buffer: &MultiBufferSnapshot,
|
||||
project: Option<&Entity<Project>>,
|
||||
cx: &App,
|
||||
) -> Self {
|
||||
let first_line_indent = buffer
|
||||
.indent_size_for_line(MultiBufferRow(range.start.row))
|
||||
.len;
|
||||
|
||||
let file_path = util::maybe!({
|
||||
let project = project?.read(cx);
|
||||
let file = buffer.file_at(range.start)?;
|
||||
let project_path = ProjectPath {
|
||||
worktree_id: file.worktree_id(cx),
|
||||
path: file.path().clone(),
|
||||
};
|
||||
project.absolute_path(&project_path, cx)
|
||||
});
|
||||
|
||||
let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
|
||||
|
||||
Self {
|
||||
len,
|
||||
is_entire_line,
|
||||
first_line_indent,
|
||||
file_path,
|
||||
line_range,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// selections, scroll behavior, was newest selection reversed
|
||||
@@ -12812,13 +12851,15 @@ impl Editor {
|
||||
text.push_str(chunk);
|
||||
len += chunk.len();
|
||||
}
|
||||
clipboard_selections.push(ClipboardSelection {
|
||||
|
||||
clipboard_selections.push(ClipboardSelection::for_buffer(
|
||||
len,
|
||||
is_entire_line,
|
||||
first_line_indent: buffer
|
||||
.indent_size_for_line(MultiBufferRow(selection.start.row))
|
||||
.len,
|
||||
});
|
||||
selection.range(),
|
||||
&buffer,
|
||||
self.project.as_ref(),
|
||||
cx,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12961,13 +13002,14 @@ impl Editor {
|
||||
text.push('\n');
|
||||
len += 1;
|
||||
}
|
||||
clipboard_selections.push(ClipboardSelection {
|
||||
clipboard_selections.push(ClipboardSelection::for_buffer(
|
||||
len,
|
||||
is_entire_line,
|
||||
first_line_indent: buffer
|
||||
.indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
|
||||
.len,
|
||||
});
|
||||
trimmed_range,
|
||||
&buffer,
|
||||
self.project.as_ref(),
|
||||
cx,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ use editor::{ClipboardSelection, Editor, SelectionEffects};
|
||||
use gpui::Context;
|
||||
use gpui::Window;
|
||||
use language::Point;
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use settings::Settings;
|
||||
|
||||
struct HighlightOnYank;
|
||||
@@ -198,11 +197,14 @@ impl Vim {
|
||||
if kind.linewise() {
|
||||
text.push('\n');
|
||||
}
|
||||
clipboard_selections.push(ClipboardSelection {
|
||||
len: text.len() - initial_len,
|
||||
is_entire_line: false,
|
||||
first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
|
||||
});
|
||||
clipboard_selections.push(ClipboardSelection::for_buffer(
|
||||
text.len() - initial_len,
|
||||
false,
|
||||
start..end,
|
||||
&buffer,
|
||||
editor.project(),
|
||||
cx,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user