assistant panel: automatically insert selections (#17589)
Addresses parts of feedback from https://www.jacobcolling.com/friction-log/zed-friction-log Release Notes: - "Assistant::NewContext" now automatically does quote selection as well - "Assistant::QuoteSelection" now handles multicursor selections, inserting multiple excerpts.
This commit is contained in:
parent
dd257b8412
commit
12dde17608
1 changed files with 120 additions and 106 deletions
|
@ -939,9 +939,16 @@ impl AssistantPanel {
|
||||||
cx: &mut ViewContext<Workspace>,
|
cx: &mut ViewContext<Workspace>,
|
||||||
) {
|
) {
|
||||||
if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
|
if let Some(panel) = workspace.panel::<AssistantPanel>(cx) {
|
||||||
panel.update(cx, |panel, cx| {
|
let did_create_context = panel
|
||||||
panel.new_context(cx);
|
.update(cx, |panel, cx| {
|
||||||
});
|
panel.new_context(cx)?;
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
})
|
||||||
|
.is_some();
|
||||||
|
if did_create_context {
|
||||||
|
ContextEditor::quote_selection(workspace, &Default::default(), cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3186,87 +3193,93 @@ impl ContextEditor {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let selection = editor.update(cx, |editor, cx| editor.selections.newest_adjusted(cx));
|
let mut creases = vec![];
|
||||||
let editor = editor.read(cx);
|
editor.update(cx, |editor, cx| {
|
||||||
let buffer = editor.buffer().read(cx).snapshot(cx);
|
let selections = editor.selections.all_adjusted(cx);
|
||||||
let range = editor::ToOffset::to_offset(&selection.start, &buffer)
|
let buffer = editor.buffer().read(cx).snapshot(cx);
|
||||||
..editor::ToOffset::to_offset(&selection.end, &buffer);
|
for selection in selections {
|
||||||
let selected_text = buffer.text_for_range(range.clone()).collect::<String>();
|
let range = editor::ToOffset::to_offset(&selection.start, &buffer)
|
||||||
if selected_text.is_empty() {
|
..editor::ToOffset::to_offset(&selection.end, &buffer);
|
||||||
return;
|
let selected_text = buffer.text_for_range(range.clone()).collect::<String>();
|
||||||
}
|
if selected_text.is_empty() {
|
||||||
|
continue;
|
||||||
let start_language = buffer.language_at(range.start);
|
}
|
||||||
let end_language = buffer.language_at(range.end);
|
let start_language = buffer.language_at(range.start);
|
||||||
let language_name = if start_language == end_language {
|
let end_language = buffer.language_at(range.end);
|
||||||
start_language.map(|language| language.code_fence_block_name())
|
let language_name = if start_language == end_language {
|
||||||
} else {
|
start_language.map(|language| language.code_fence_block_name())
|
||||||
None
|
|
||||||
};
|
|
||||||
let language_name = language_name.as_deref().unwrap_or("");
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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 {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
let language_name = language_name.as_deref().unwrap_or("");
|
||||||
|
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 {
|
||||||
|
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 line_comment_prefix = start_language
|
let outline_text = if let Some((start_symbols, end_symbols)) =
|
||||||
.and_then(|l| l.default_scope().line_comment_prefixes().first().cloned());
|
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 fence = codeblock_fence_for_path(
|
let line_comment_prefix = start_language
|
||||||
filename.as_deref(),
|
.and_then(|l| l.default_scope().line_comment_prefixes().first().cloned());
|
||||||
Some(selection.start.row..selection.end.row),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some((line_comment_prefix, outline_text)) = line_comment_prefix.zip(outline_text)
|
let fence = codeblock_fence_for_path(
|
||||||
{
|
filename.as_deref(),
|
||||||
let breadcrumb = format!("{line_comment_prefix}Excerpt from: {outline_text}\n");
|
Some(selection.start.row..selection.end.row),
|
||||||
format!("{fence}{breadcrumb}{selected_text}\n```")
|
);
|
||||||
} else {
|
|
||||||
format!("{fence}{selected_text}\n```")
|
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!("{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()
|
||||||
|
};
|
||||||
|
creases.push((text, crease_title));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
if creases.is_empty() {
|
||||||
let crease_title = if let Some(path) = filename {
|
return;
|
||||||
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
|
// Activate the panel
|
||||||
if !panel.focus_handle(cx).contains_focused(cx) {
|
if !panel.focus_handle(cx).contains_focused(cx) {
|
||||||
workspace.toggle_panel_focus::<AssistantPanel>(cx);
|
workspace.toggle_panel_focus::<AssistantPanel>(cx);
|
||||||
|
@ -3283,39 +3296,40 @@ impl ContextEditor {
|
||||||
context.update(cx, |context, cx| {
|
context.update(cx, |context, cx| {
|
||||||
context.editor.update(cx, |editor, cx| {
|
context.editor.update(cx, |editor, cx| {
|
||||||
editor.insert("\n", cx);
|
editor.insert("\n", cx);
|
||||||
|
for (text, crease_title) in creases {
|
||||||
|
let point = editor.selections.newest::<Point>(cx).head();
|
||||||
|
let start_row = MultiBufferRow(point.row);
|
||||||
|
|
||||||
let point = editor.selections.newest::<Point>(cx).head();
|
editor.insert(&text, cx);
|
||||||
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);
|
||||||
|
|
||||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
editor.insert("\n", 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,
|
||||||
let fold_placeholder = quote_selection_fold_placeholder(
|
cx.view().downgrade(),
|
||||||
crease_title,
|
);
|
||||||
cx.view().downgrade(),
|
let crease = Crease::new(
|
||||||
);
|
anchor_before..anchor_after,
|
||||||
let crease = Crease::new(
|
fold_placeholder,
|
||||||
anchor_before..anchor_after,
|
render_quote_selection_output_toggle,
|
||||||
fold_placeholder,
|
|_, _, _| Empty.into_any(),
|
||||||
render_quote_selection_output_toggle,
|
);
|
||||||
|_, _, _| Empty.into_any(),
|
editor.insert_creases(vec![crease], cx);
|
||||||
);
|
editor.fold_at(
|
||||||
editor.insert_creases(vec![crease], cx);
|
&FoldAt {
|
||||||
editor.fold_at(
|
buffer_row: start_row,
|
||||||
&FoldAt {
|
},
|
||||||
buffer_row: start_row,
|
cx,
|
||||||
},
|
);
|
||||||
cx,
|
}
|
||||||
);
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue