From 93bc6616c697bee1ecf178e41597f0b294b0826b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 4 Dec 2025 16:41:48 +0100 Subject: [PATCH] editor: Improve performance of `update_visible_edit_prediction` (#44161) One half of https://github.com/zed-industries/zed/issues/42861 This basically reduces the main thread work for large enough json (and other) files from multiple milliseconds (15ms was observed in that test case) down to microseconds (100ms here). Release Notes: - Improved cursor movement performance when edit predictions are enabled --- crates/editor/src/editor.rs | 15 ++++++++---- crates/multi_buffer/src/multi_buffer.rs | 32 +++++++++++++++++++------ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 05287847190691221e6f948ba53efecc7269e9be..4b352e2d8298f3c9ae2c0d38bd6b443d62a61996 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -182,7 +182,7 @@ use std::{ iter::{self, Peekable}, mem, num::NonZeroU32, - ops::{Deref, DerefMut, Not, Range, RangeInclusive}, + ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive}, path::{Path, PathBuf}, rc::Rc, sync::Arc, @@ -8073,10 +8073,17 @@ impl Editor { if self.edit_prediction_indent_conflict { let cursor_point = cursor.to_point(&multibuffer); + let mut suggested_indent = None; + multibuffer.suggested_indents_callback( + cursor_point.row..cursor_point.row + 1, + |_, indent| { + suggested_indent = Some(indent); + ControlFlow::Break(()) + }, + cx, + ); - let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx); - - if let Some((_, indent)) = indents.iter().next() + if let Some(indent) = suggested_indent && indent.len == cursor_point.column { self.edit_prediction_indent_conflict = false; diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index 02adb79e70452a524152d62a71138b75561f9f33..af36aaadf02b53224c4ef0bcf0a17d3643ab8f0f 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -43,7 +43,7 @@ use std::{ io, iter::{self, FromIterator}, mem, - ops::{self, AddAssign, Range, RangeBounds, Sub, SubAssign}, + ops::{self, AddAssign, ControlFlow, Range, RangeBounds, Sub, SubAssign}, rc::Rc, str, sync::Arc, @@ -4618,7 +4618,24 @@ impl MultiBufferSnapshot { cx: &App, ) -> BTreeMap { let mut result = BTreeMap::new(); + self.suggested_indents_callback( + rows, + |row, indent| { + result.insert(row, indent); + ControlFlow::Continue(()) + }, + cx, + ); + result + } + // move this to be a generator once those are a thing + pub fn suggested_indents_callback( + &self, + rows: impl IntoIterator, + mut cb: impl FnMut(MultiBufferRow, IndentSize) -> ControlFlow<()>, + cx: &App, + ) { let mut rows_for_excerpt = Vec::new(); let mut cursor = self.cursor::(); let mut rows = rows.into_iter().peekable(); @@ -4662,16 +4679,17 @@ impl MultiBufferSnapshot { let buffer_indents = region .buffer .suggested_indents(buffer_rows, single_indent_size); - let multibuffer_indents = buffer_indents.into_iter().map(|(row, indent)| { - ( + for (row, indent) in buffer_indents { + if cb( MultiBufferRow(start_multibuffer_row + row - start_buffer_row), indent, ) - }); - result.extend(multibuffer_indents); + .is_break() + { + return; + } + } } - - result } pub fn indent_size_for_line(&self, row: MultiBufferRow) -> IndentSize {