mirror of
https://github.com/zed-industries/zed.git
synced 2024-10-23 23:09:42 +00:00
assistant: Improve quote selection (#16038)
https://github.com/user-attachments/assets/fe283eec-169f-4dfd-bae2-cc72c1c3f223 Release Notes: - Include more context when using `assistant: Quote selection` to insert text into the assistant panel --------- Co-authored-by: Thorsten <thorsten@zed.dev>
This commit is contained in:
parent
46a4dd3ab1
commit
c633fa5a10
1 changed files with 153 additions and 28 deletions
|
@ -6,6 +6,7 @@ use crate::{
|
|||
slash_command::{
|
||||
default_command::DefaultSlashCommand,
|
||||
docs_command::{DocsSlashCommand, DocsSlashCommandArgs},
|
||||
file_command::codeblock_fence_for_path,
|
||||
SlashCommandCompletionProvider, SlashCommandRegistry,
|
||||
},
|
||||
terminal_inline_assistant::TerminalInlineAssistant,
|
||||
|
@ -2929,6 +2930,11 @@ impl ContextEditor {
|
|||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||
let range = editor::ToOffset::to_offset(&selection.start, &buffer)
|
||||
..editor::ToOffset::to_offset(&selection.end, &buffer);
|
||||
let selected_text = buffer.text_for_range(range.clone()).collect::<String>();
|
||||
if selected_text.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let start_language = buffer.language_at(range.start);
|
||||
let end_language = buffer.language_at(range.end);
|
||||
let language_name = if start_language == end_language {
|
||||
|
@ -2938,19 +2944,66 @@ impl ContextEditor {
|
|||
};
|
||||
let language_name = language_name.as_deref().unwrap_or("");
|
||||
|
||||
let selected_text = buffer.text_for_range(range).collect::<String>();
|
||||
let text = if selected_text.is_empty() {
|
||||
None
|
||||
let filename = buffer
|
||||
.file_at(selection.start)
|
||||
.map(|file| file.full_path(cx));
|
||||
|
||||
let text = if language_name == "markdown" {
|
||||
selected_text
|
||||
.lines()
|
||||
.map(|line| format!("> {}", line))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
} else {
|
||||
Some(if language_name == "markdown" {
|
||||
selected_text
|
||||
.lines()
|
||||
.map(|line| format!("> {}", line))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
let start_symbols = buffer
|
||||
.symbols_containing(selection.start, None)
|
||||
.map(|(_, symbols)| symbols);
|
||||
let end_symbols = buffer
|
||||
.symbols_containing(selection.end, None)
|
||||
.map(|(_, symbols)| symbols);
|
||||
|
||||
let outline_text =
|
||||
if let Some((start_symbols, end_symbols)) = start_symbols.zip(end_symbols) {
|
||||
Some(
|
||||
start_symbols
|
||||
.into_iter()
|
||||
.zip(end_symbols)
|
||||
.take_while(|(a, b)| a == b)
|
||||
.map(|(a, _)| a.text)
|
||||
.collect::<Vec<_>>()
|
||||
.join(" > "),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let line_comment_prefix = start_language
|
||||
.and_then(|l| l.default_scope().line_comment_prefixes().first().cloned());
|
||||
|
||||
let fence = codeblock_fence_for_path(
|
||||
filename.as_deref(),
|
||||
Some(selection.start.row..selection.end.row),
|
||||
);
|
||||
|
||||
if let Some((line_comment_prefix, outline_text)) = line_comment_prefix.zip(outline_text)
|
||||
{
|
||||
let breadcrumb = format!("{line_comment_prefix}Excerpt from: {outline_text}\n");
|
||||
format!("{fence}{breadcrumb}{selected_text}\n```")
|
||||
} else {
|
||||
format!("```{language_name}\n{selected_text}\n```")
|
||||
})
|
||||
format!("{fence}{selected_text}\n```")
|
||||
}
|
||||
};
|
||||
|
||||
let crease_title = if let Some(path) = filename {
|
||||
let start_line = selection.start.row + 1;
|
||||
let end_line = selection.end.row + 1;
|
||||
if start_line == end_line {
|
||||
format!("{}, Line {}", path.display(), start_line)
|
||||
} else {
|
||||
format!("{}, Lines {} to {}", path.display(), start_line, end_line)
|
||||
}
|
||||
} else {
|
||||
"Quoted selection".to_string()
|
||||
};
|
||||
|
||||
// Activate the panel
|
||||
|
@ -2958,24 +3011,55 @@ impl ContextEditor {
|
|||
workspace.toggle_panel_focus::<AssistantPanel>(cx);
|
||||
}
|
||||
|
||||
if let Some(text) = text {
|
||||
panel.update(cx, |_, cx| {
|
||||
// Wait to create a new context until the workspace is no longer
|
||||
// being updated.
|
||||
cx.defer(move |panel, cx| {
|
||||
if let Some(context) = panel
|
||||
.active_context_editor(cx)
|
||||
.or_else(|| panel.new_context(cx))
|
||||
{
|
||||
context.update(cx, |context, cx| {
|
||||
context
|
||||
.editor
|
||||
.update(cx, |editor, cx| editor.insert(&text, cx))
|
||||
});
|
||||
};
|
||||
});
|
||||
panel.update(cx, |_, cx| {
|
||||
// Wait to create a new context until the workspace is no longer
|
||||
// being updated.
|
||||
cx.defer(move |panel, cx| {
|
||||
if let Some(context) = panel
|
||||
.active_context_editor(cx)
|
||||
.or_else(|| panel.new_context(cx))
|
||||
{
|
||||
context.update(cx, |context, cx| {
|
||||
context.editor.update(cx, |editor, cx| {
|
||||
editor.insert("\n", cx);
|
||||
|
||||
let point = editor.selections.newest::<Point>(cx).head();
|
||||
let start_row = MultiBufferRow(point.row);
|
||||
|
||||
editor.insert(&text, cx);
|
||||
|
||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
let anchor_before = snapshot.anchor_after(point);
|
||||
let anchor_after = editor
|
||||
.selections
|
||||
.newest_anchor()
|
||||
.head()
|
||||
.bias_left(&snapshot);
|
||||
|
||||
editor.insert("\n", cx);
|
||||
|
||||
let fold_placeholder = quote_selection_fold_placeholder(
|
||||
crease_title,
|
||||
cx.view().downgrade(),
|
||||
);
|
||||
let crease = Crease::new(
|
||||
anchor_before..anchor_after,
|
||||
fold_placeholder,
|
||||
render_quote_selection_output_toggle,
|
||||
|_, _, _| Empty.into_any(),
|
||||
);
|
||||
editor.insert_creases(vec![crease], cx);
|
||||
editor.fold_at(
|
||||
&FoldAt {
|
||||
buffer_row: start_row,
|
||||
},
|
||||
cx,
|
||||
);
|
||||
})
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn copy(&mut self, _: &editor::actions::Copy, cx: &mut ViewContext<Self>) {
|
||||
|
@ -4028,6 +4112,47 @@ fn render_slash_command_output_toggle(
|
|||
.into_any_element()
|
||||
}
|
||||
|
||||
fn quote_selection_fold_placeholder(title: String, editor: WeakView<Editor>) -> FoldPlaceholder {
|
||||
FoldPlaceholder {
|
||||
render: Arc::new({
|
||||
move |fold_id, fold_range, _cx| {
|
||||
let editor = editor.clone();
|
||||
ButtonLike::new(fold_id)
|
||||
.style(ButtonStyle::Filled)
|
||||
.layer(ElevationIndex::ElevatedSurface)
|
||||
.child(Icon::new(IconName::FileText))
|
||||
.child(Label::new(title.clone()).single_line())
|
||||
.on_click(move |_, cx| {
|
||||
editor
|
||||
.update(cx, |editor, cx| {
|
||||
let buffer_start = fold_range
|
||||
.start
|
||||
.to_point(&editor.buffer().read(cx).read(cx));
|
||||
let buffer_row = MultiBufferRow(buffer_start.row);
|
||||
editor.unfold_at(&UnfoldAt { buffer_row }, cx);
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
}),
|
||||
constrain_width: false,
|
||||
merge_adjacent: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn render_quote_selection_output_toggle(
|
||||
row: MultiBufferRow,
|
||||
is_folded: bool,
|
||||
fold: ToggleFold,
|
||||
_cx: &mut WindowContext,
|
||||
) -> AnyElement {
|
||||
Disclosure::new(("quote-selection-indicator", row.0 as u64), !is_folded)
|
||||
.selected(is_folded)
|
||||
.on_click(move |_e, cx| fold(!is_folded, cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_pending_slash_command_gutter_decoration(
|
||||
row: MultiBufferRow,
|
||||
status: &PendingSlashCommandStatus,
|
||||
|
|
Loading…
Reference in a new issue