mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-31 19:05:00 +07:00
Batch excerpt insertions per file when opening commit view (#57330)
When viewing the diff for a commit where one of the files has a large number (hundreds or thousands) of diff hunks, we can get a hang on the main thread, since there's a large amount of work to recompute diff transforms for thousands of excerpts. This PR makes it so that we batch the addition of excerpts, with yield points in between batches so the UI remains responsive. We should have something similar for the project diff, but that's a bit trickier; will address it in a separate PR. Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Improved performance when opening the commit view with files that have many diff hunks.
This commit is contained in:
parent
216980f671
commit
a8cdf1d869
1 changed files with 50 additions and 29 deletions
|
|
@ -3,6 +3,7 @@ use buffer_diff::BufferDiff;
|
|||
use collections::HashMap;
|
||||
use editor::display_map::{BlockPlacement, BlockProperties, BlockStyle};
|
||||
use editor::{Addon, Editor, EditorEvent, ExcerptRange, MultiBuffer, multibuffer_context_lines};
|
||||
use futures_lite::future::yield_now;
|
||||
use git::repository::{CommitDetails, CommitDiff, RepoPath, is_binary_content};
|
||||
use git::status::{FileStatus, StatusCode, TrackedStatus};
|
||||
use git::{
|
||||
|
|
@ -392,38 +393,58 @@ impl CommitView {
|
|||
Some(build_buffer_diff(old_text, &buffer, &language_registry, cx).await?)
|
||||
};
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
this.multibuffer.update(cx, |multibuffer, cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let path = snapshot.file().unwrap().path().clone();
|
||||
let excerpt_ranges = if is_binary {
|
||||
let (excerpt_ranges, path) = cx.update(|cx| {
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
let path = PathKey::with_sort_prefix(
|
||||
FILE_NAMESPACE_SORT_PREFIX,
|
||||
snapshot.file().unwrap().path().clone(),
|
||||
);
|
||||
let ranges = if is_binary {
|
||||
vec![language::Point::zero()..snapshot.max_point()]
|
||||
} else if let Some(buffer_diff) = &buffer_diff {
|
||||
let diff_snapshot = buffer_diff.read(cx).snapshot(cx);
|
||||
let mut hunks = diff_snapshot.hunks(&snapshot).peekable();
|
||||
if hunks.peek().is_none() {
|
||||
vec![language::Point::zero()..snapshot.max_point()]
|
||||
} else if let Some(buffer_diff) = &buffer_diff {
|
||||
let diff_snapshot = buffer_diff.read(cx).snapshot(cx);
|
||||
let mut hunks = diff_snapshot.hunks(&snapshot).peekable();
|
||||
if hunks.peek().is_none() {
|
||||
vec![language::Point::zero()..snapshot.max_point()]
|
||||
} else {
|
||||
hunks
|
||||
.map(|hunk| hunk.buffer_range.to_point(&snapshot))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
} else {
|
||||
vec![language::Point::zero()..snapshot.max_point()]
|
||||
};
|
||||
|
||||
let _is_newly_added = multibuffer.set_excerpts_for_path(
|
||||
PathKey::with_sort_prefix(FILE_NAMESPACE_SORT_PREFIX, path),
|
||||
buffer,
|
||||
excerpt_ranges,
|
||||
multibuffer_context_lines(cx),
|
||||
cx,
|
||||
);
|
||||
if let Some(buffer_diff) = buffer_diff {
|
||||
multibuffer.add_diff(buffer_diff, cx);
|
||||
hunks
|
||||
.map(|hunk| hunk.buffer_range.to_point(&snapshot))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
});
|
||||
})?;
|
||||
} else {
|
||||
vec![language::Point::zero()..snapshot.max_point()]
|
||||
};
|
||||
(ranges, path)
|
||||
});
|
||||
|
||||
// Batch the insertion of excerpts and yield between batches, to avoid blocking the main thread when a single file has many hunks.
|
||||
const EXCERPT_BATCH_SIZE: usize = 10;
|
||||
let total = excerpt_ranges.len();
|
||||
let mut batch_end = 0;
|
||||
while batch_end < total {
|
||||
let is_first_batch = batch_end == 0;
|
||||
batch_end = (batch_end + EXCERPT_BATCH_SIZE).min(total);
|
||||
let ranges = excerpt_ranges[..batch_end].to_vec();
|
||||
this.update(cx, |this, cx| {
|
||||
this.multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer.set_excerpts_for_path(
|
||||
path.clone(),
|
||||
buffer.clone(),
|
||||
ranges,
|
||||
multibuffer_context_lines(cx),
|
||||
cx,
|
||||
);
|
||||
if is_first_batch {
|
||||
if let Some(buffer_diff) = buffer_diff.clone() {
|
||||
multibuffer.add_diff(buffer_diff, cx);
|
||||
}
|
||||
}
|
||||
});
|
||||
})?;
|
||||
if batch_end < total {
|
||||
yield_now().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.update(cx, |this, cx| {
|
||||
|
|
|
|||
Loading…
Reference in a new issue