Use Rope instead of String for buffer diff base (#11300)

As an attempt to do things better when showing diff hunks, store diff
base as Rope, not String, to have cheaper clones when the diff base text
is reused, e.g. creating another buffer with the diff base text for hunk
diff expanding.

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2024-05-03 11:18:43 +03:00 committed by GitHub
parent 5f0046b923
commit b523ee6980
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 131 additions and 65 deletions

View file

@ -78,7 +78,7 @@ pub enum Capability {
/// syntax trees, git status, and diagnostics.
pub struct Buffer {
text: TextBuffer,
diff_base: Option<String>,
diff_base: Option<Rope>,
git_diff: git::diff::BufferDiff,
file: Option<Arc<dyn File>>,
/// The mtime of the file when this buffer was last loaded from
@ -512,6 +512,25 @@ impl Buffer {
)
}
/// Create a new buffer with the given base text that has proper line endings and other normalization applied.
pub fn local_normalized(
base_text_normalized: Rope,
line_ending: LineEnding,
cx: &mut ModelContext<Self>,
) -> Self {
Self::build(
TextBuffer::new_normalized(
0,
cx.entity_id().as_non_zero_u64().into(),
line_ending,
base_text_normalized,
),
None,
None,
Capability::ReadWrite,
)
}
/// Create a new buffer that is a replica of a remote buffer.
pub fn remote(
remote_id: BufferId,
@ -540,7 +559,7 @@ impl Buffer {
let buffer = TextBuffer::new(replica_id, buffer_id, message.base_text);
let mut this = Self::build(
buffer,
message.diff_base.map(|text| text.into_boxed_str().into()),
message.diff_base.map(|text| text.into()),
file,
capability,
);
@ -632,7 +651,7 @@ impl Buffer {
/// Builds a [Buffer] with the given underlying [TextBuffer], diff base, [File] and [Capability].
pub fn build(
buffer: TextBuffer,
diff_base: Option<String>,
diff_base: Option<Rope>,
file: Option<Arc<dyn File>>,
capability: Capability,
) -> Self {
@ -868,13 +887,13 @@ impl Buffer {
}
/// Returns the current diff base, see [Buffer::set_diff_base].
pub fn diff_base(&self) -> Option<&str> {
self.diff_base.as_deref()
pub fn diff_base(&self) -> Option<&Rope> {
self.diff_base.as_ref()
}
/// Sets the text that will be used to compute a Git diff
/// against the buffer text.
pub fn set_diff_base(&mut self, diff_base: Option<String>, cx: &mut ModelContext<Self>) {
pub fn set_diff_base(&mut self, diff_base: Option<Rope>, cx: &mut ModelContext<Self>) {
self.diff_base = diff_base;
self.diff_base_version += 1;
if let Some(recalc_task) = self.git_diff_recalc(cx) {