Fix several small performance inefficiencies in hot paths (#61275)

# Objective

Land five small, independent performance fixes found during an audit of
hot paths (anchor resolution, line shaping, worktree scanning, and
sorting in multibuffers).

## Solution

Each fix is its own commit, so **this PR is best reviewed
commit-by-commit** — every commit message contains the full reasoning
for that change:

- `text`: Avoid redundant rope traversal in `Anchor → usize` conversion
— call `offset_for_anchor` directly instead of `summary_for_anchor`,
which recomputed the same byte offset with ~4 extra O(log n) tree walks.
This is the hottest anchor-resolution path.
- `editor`: Avoid double allocation per shaped line —
`line.as_str().into()` instead of `line.clone().into()`, which allocated
twice per visible line, every frame.
- `text`: Use `sort_unstable_by_key` in operation queue insertion —
Lamport timestamps are unique keys and duplicates are deduped right
after, so stability buys nothing.
- `multi_buffer`: Sort with an explicit comparator instead of
`sort_unstable_by_key`, which cloned a `PathKey` (`Arc` refcount bump)
on every comparison.
- `worktree`: Replace O(n²) `Vec::remove` in the deferred-directory pass
with an O(1) `None` assignment — the vec is already
`Vec<Option<ScanJob>>` and is consumed with `.flatten()`.

## Testing

- No behavior changes intended; all changes are mechanical and tests
affected crates pass: `text`, `editor`, `multi_buffer`, `worktree`.

## 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 adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Improved editor performance through several micro-optimizations in
anchor resolution, line shaping, and worktree scanning.
This commit is contained in:
Miguel Raz Guzmán Macedo authored and GitHub committed 2026-07-19 05:36:35 +00:00
1 parent c5830a9378
commit 78652e2f50
5 files changed
+8 -9

No files matched your search

+1 -1
View File
@@ -7099,7 +7099,7 @@ impl LineWithInvisibles {
&Self::split_runs_by_bg_segments(&styles, segments, min_contrast, len)
};
let shaped_line = window.text_system().shape_line(
line.clone().into(),
line.as_str().into(),
font_size,
text_runs,
None,
+1 -1
View File
@@ -2553,7 +2553,7 @@ impl MultiBuffer {
*non_text_state_update_count += 1;
}
paths_to_edit.sort_unstable_by_key(|(path, _, _, _)| path.clone());
paths_to_edit.sort_unstable_by(|a, b| a.0.cmp(&b.0));
let mut edits = Vec::new();
let mut new_excerpts = SumTree::default();
+1 -1
View File
@@ -47,7 +47,7 @@ impl<T: Operation> OperationQueue<T> {
}
pub fn insert(&mut self, mut ops: Vec<T>) {
ops.sort_by_key(|op| op.lamport_timestamp());
ops.sort_unstable_by_key(|op| op.lamport_timestamp());
ops.dedup_by_key(|op| op.lamport_timestamp());
self.0.edit(
ops.into_iter()
+2 -2
View File
@@ -3428,7 +3428,7 @@ impl ToOffset for usize {
impl ToOffset for Anchor {
#[inline]
fn to_offset(&self, snapshot: &BufferSnapshot) -> usize {
snapshot.summary_for_anchor(self)
snapshot.offset_for_anchor(self)
}
}
@@ -3570,7 +3570,7 @@ impl FromAnchor for PointUtf16 {
impl FromAnchor for usize {
#[inline]
fn from_anchor(anchor: &Anchor, snapshot: &BufferSnapshot) -> Self {
snapshot.summary_for_anchor(anchor)
snapshot.offset_for_anchor(anchor)
}
}
+3 -4
View File
@@ -5402,13 +5402,12 @@ impl BackgroundScanner {
for entry in &mut new_entries {
state.reuse_entry_id(entry);
if entry.is_dir() {
if self.should_scan_directory(&state, entry) {
job_ix += 1;
} else {
if !self.should_scan_directory(&state, entry) {
log::debug!("defer scanning directory {:?}", entry.path);
entry.kind = EntryKind::UnloadedDir;
new_jobs.remove(job_ix);
new_jobs[job_ix] = None;
}
job_ix += 1;
}
if entry.is_always_included {
state