Preserve sections generated by slash commands when reloading a context (#13199)

Release Notes:

- N/A
This commit is contained in:
Antonio Scandurra 2024-06-18 14:49:53 +02:00 committed by GitHub
parent 195a270e18
commit e4ba336971
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 250 additions and 348 deletions

View file

@ -15,9 +15,8 @@ use anyhow::{anyhow, Result};
use assistant_slash_command::{SlashCommand, SlashCommandOutput, SlashCommandOutputSection};
use client::telemetry::Telemetry;
use collections::{BTreeSet, HashMap, HashSet};
use editor::actions::ShowCompletions;
use editor::{
actions::{FoldAt, MoveToEndOfLine, Newline, UnfoldAt},
actions::{FoldAt, MoveToEndOfLine, Newline, ShowCompletions, UnfoldAt},
display_map::{BlockDisposition, BlockId, BlockProperties, BlockStyle, Crease, ToDisplayPoint},
scroll::{Autoscroll, AutoscrollStrategy},
Anchor, Editor, EditorEvent, RowExt, ToOffset as _, ToPoint,
@ -36,7 +35,7 @@ use gpui::{
WindowContext,
};
use language::{
language_settings::SoftWrap, AnchorRangeExt, AutoindentMode, Buffer, LanguageRegistry,
language_settings::SoftWrap, AnchorRangeExt as _, AutoindentMode, Buffer, LanguageRegistry,
LspAdapterDelegate, OffsetRangeExt as _, Point, ToOffset as _,
};
use multi_buffer::MultiBufferRow;
@ -1013,6 +1012,7 @@ pub struct Context {
edit_suggestions: Vec<EditSuggestion>,
pending_slash_commands: Vec<PendingSlashCommand>,
edits_since_last_slash_command_parse: language::Subscription,
slash_command_output_sections: Vec<SlashCommandOutputSection<language::Anchor>>,
message_anchors: Vec<MessageAnchor>,
messages_metadata: HashMap<MessageId, MessageMetadata>,
next_message_id: MessageId,
@ -1054,6 +1054,7 @@ impl Context {
next_message_id: Default::default(),
edit_suggestions: Vec::new(),
pending_slash_commands: Vec::new(),
slash_command_output_sections: Vec::new(),
edits_since_last_slash_command_parse,
summary: None,
pending_summary: Task::ready(None),
@ -1090,11 +1091,12 @@ impl Context {
}
fn serialize(&self, cx: &AppContext) -> SavedContext {
let buffer = self.buffer.read(cx);
SavedContext {
id: self.id.clone(),
zed: "context".into(),
version: SavedContext::VERSION.into(),
text: self.buffer.read(cx).text(),
text: buffer.text(),
message_metadata: self.messages_metadata.clone(),
messages: self
.messages(cx)
@ -1108,6 +1110,22 @@ impl Context {
.as_ref()
.map(|summary| summary.text.clone())
.unwrap_or_default(),
slash_command_output_sections: self
.slash_command_output_sections
.iter()
.filter_map(|section| {
let range = section.range.to_offset(buffer);
if section.range.start.is_valid(buffer) && !range.is_empty() {
Some(SlashCommandOutputSection {
range,
icon: section.icon,
label: section.label.clone(),
})
} else {
None
}
})
.collect(),
}
}
@ -1159,6 +1177,19 @@ impl Context {
next_message_id,
edit_suggestions: Vec::new(),
pending_slash_commands: Vec::new(),
slash_command_output_sections: saved_context
.slash_command_output_sections
.into_iter()
.map(|section| {
let buffer = buffer.read(cx);
SlashCommandOutputSection {
range: buffer.anchor_after(section.range.start)
..buffer.anchor_before(section.range.end),
icon: section.icon,
label: section.label,
}
})
.collect(),
edits_since_last_slash_command_parse,
summary: Some(Summary {
text: saved_context.summary,
@ -1457,10 +1488,17 @@ impl Context {
.map(|section| SlashCommandOutputSection {
range: buffer.anchor_after(start + section.range.start)
..buffer.anchor_before(start + section.range.end),
render_placeholder: section.render_placeholder,
icon: section.icon,
label: section.label,
})
.collect::<Vec<_>>();
sections.sort_by(|a, b| a.range.cmp(&b.range, buffer));
this.slash_command_output_sections
.extend(sections.iter().cloned());
this.slash_command_output_sections
.sort_by(|a, b| a.range.cmp(&b.range, buffer));
ContextEvent::SlashCommandFinished {
output_range: buffer.anchor_after(start)
..buffer.anchor_before(new_end),
@ -2224,6 +2262,7 @@ impl ContextEditor {
cx.subscribe(&editor, Self::handle_editor_event),
];
let sections = context.read(cx).slash_command_output_sections.clone();
let mut this = Self {
context,
editor,
@ -2237,6 +2276,7 @@ impl ContextEditor {
_subscriptions,
};
this.update_message_headers(cx);
this.insert_slash_command_output_sections(sections, cx);
this
}
@ -2631,21 +2671,27 @@ impl ContextEditor {
FoldPlaceholder {
render: Arc::new({
let editor = cx.view().downgrade();
let render_placeholder = section.render_placeholder.clone();
move |fold_id, fold_range, cx| {
let icon = section.icon;
let label = section.label.clone();
move |fold_id, fold_range, _cx| {
let editor = editor.clone();
let unfold = Arc::new(move |cx: &mut WindowContext| {
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();
});
render_placeholder(fold_id.into(), unfold, cx)
ButtonLike::new(fold_id)
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ElevatedSurface)
.child(Icon::new(icon))
.child(Label::new(label.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,