Reduce display_map snapshot creation (#39354)

Re-applies https://github.com/zed-industries/zed/pull/30840

This PR re-applies the initial
[PR](https://github.com/zed-industries/zed/pull/30840). As it was closed
because it was hard to land, because of the many conflicts. This PR
re-applies the changes for it.

In several cases we were creating multiple display_map
snapshots within the same root-level function call.
Creating a display_map snapshot is quite slow, and in some
cases we were creating the snapshot multiple times.

Release Notes:

- N/A
This commit is contained in:
Remco Smits
2025-10-17 21:56:57 +02:00
committed by GitHub
parent ef5b8c6fed
commit 7e97fcaacb
60 changed files with 853 additions and 426 deletions
@@ -652,7 +652,9 @@ impl ContextPickerCompletionProvider {
.active_item(cx)
.and_then(|item| item.downcast::<Editor>())
.is_some_and(|editor| {
editor.update(cx, |editor, cx| editor.has_non_empty_selection(cx))
editor.update(cx, |editor, cx| {
editor.has_non_empty_selection(&editor.display_snapshot(cx))
})
});
if has_selection {
entries.push(ContextPickerEntry::Action(
+31 -10
View File
@@ -452,7 +452,10 @@ fn update_editor_selection(
window: &mut Window,
cx: &mut Context<Editor>,
) {
let newest_cursor = editor.selections.newest::<Point>(cx).head();
let newest_cursor = editor
.selections
.newest::<Point>(&editor.display_snapshot(cx))
.head();
if !diff_hunks.iter().any(|hunk| {
hunk.row_range
@@ -1895,7 +1898,9 @@ mod tests {
);
assert_eq!(
editor
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(1, 0)..Point::new(1, 0)
);
@@ -1909,7 +1914,9 @@ mod tests {
);
assert_eq!(
editor
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(3, 0)..Point::new(3, 0)
);
@@ -1930,7 +1937,9 @@ mod tests {
);
assert_eq!(
editor
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(3, 0)..Point::new(3, 0)
);
@@ -1962,7 +1971,9 @@ mod tests {
);
assert_eq!(
editor
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(3, 0)..Point::new(3, 0)
);
@@ -2119,7 +2130,9 @@ mod tests {
);
assert_eq!(
editor1
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(1, 0)..Point::new(1, 0)
);
@@ -2160,7 +2173,9 @@ mod tests {
);
assert_eq!(
editor1
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(3, 0)..Point::new(3, 0)
);
@@ -2181,7 +2196,9 @@ mod tests {
);
assert_eq!(
editor1
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(3, 0)..Point::new(3, 0)
);
@@ -2207,7 +2224,9 @@ mod tests {
);
assert_eq!(
editor1
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(3, 0)..Point::new(3, 0)
);
@@ -2240,7 +2259,9 @@ mod tests {
);
assert_eq!(
editor2
.update(cx, |editor, cx| editor.selections.newest::<Point>(cx))
.update(cx, |editor, cx| editor
.selections
.newest::<Point>(&editor.display_snapshot(cx)))
.range(),
Point::new(0, 0)..Point::new(0, 0)
);
+6 -2
View File
@@ -606,7 +606,11 @@ pub(crate) fn available_context_picker_entries(
.read(cx)
.active_item(cx)
.and_then(|item| item.downcast::<Editor>())
.is_some_and(|editor| editor.update(cx, |editor, cx| editor.has_non_empty_selection(cx)));
.is_some_and(|editor| {
editor.update(cx, |editor, cx| {
editor.has_non_empty_selection(&editor.display_snapshot(cx))
})
});
if has_selection {
entries.push(ContextPickerEntry::Action(
ContextPickerAction::AddSelections,
@@ -725,7 +729,7 @@ pub(crate) fn selection_ranges(
};
editor.update(cx, |editor, cx| {
let selections = editor.selections.all_adjusted(cx);
let selections = editor.selections.all_adjusted(&editor.display_snapshot(cx));
let buffer = editor.buffer().clone().read(cx);
let snapshot = buffer.snapshot(cx);
+12 -5
View File
@@ -363,9 +363,12 @@ impl InlineAssistant {
cx: &mut App,
) {
let (snapshot, initial_selections, newest_selection) = editor.update(cx, |editor, cx| {
let selections = editor.selections.all::<Point>(cx);
let newest_selection = editor.selections.newest::<Point>(cx);
(editor.snapshot(window, cx), selections, newest_selection)
let snapshot = editor.snapshot(window, cx);
let selections = editor.selections.all::<Point>(&snapshot.display_snapshot);
let newest_selection = editor
.selections
.newest::<Point>(&snapshot.display_snapshot);
(snapshot, selections, newest_selection)
});
// Check if there is already an inline assistant that contains the
@@ -798,7 +801,9 @@ impl InlineAssistant {
if editor.read(cx).selections.count() == 1 {
let (selection, buffer) = editor.update(cx, |editor, cx| {
(
editor.selections.newest::<usize>(cx),
editor
.selections
.newest::<usize>(&editor.display_snapshot(cx)),
editor.buffer().read(cx).snapshot(cx),
)
});
@@ -829,7 +834,9 @@ impl InlineAssistant {
if editor.read(cx).selections.count() == 1 {
let (selection, buffer) = editor.update(cx, |editor, cx| {
(
editor.selections.newest::<usize>(cx),
editor
.selections
.newest::<usize>(&editor.display_snapshot(cx)),
editor.buffer().read(cx).snapshot(cx),
)
});
+32 -13
View File
@@ -431,9 +431,9 @@ impl TextThreadEditor {
}
fn cursors(&self, cx: &mut App) -> Vec<usize> {
let selections = self
.editor
.update(cx, |editor, cx| editor.selections.all::<usize>(cx));
let selections = self.editor.update(cx, |editor, cx| {
editor.selections.all::<usize>(&editor.display_snapshot(cx))
});
selections
.into_iter()
.map(|selection| selection.head())
@@ -446,7 +446,10 @@ impl TextThreadEditor {
editor.transact(window, cx, |editor, window, cx| {
editor.change_selections(Default::default(), window, cx, |s| s.try_cancel());
let snapshot = editor.buffer().read(cx).snapshot(cx);
let newest_cursor = editor.selections.newest::<Point>(cx).head();
let newest_cursor = editor
.selections
.newest::<Point>(&editor.display_snapshot(cx))
.head();
if newest_cursor.column > 0
|| snapshot
.chars_at(newest_cursor)
@@ -1248,11 +1251,19 @@ impl TextThreadEditor {
let context_editor = context_editor_view.read(cx).editor.clone();
context_editor.update(cx, |context_editor, cx| {
if context_editor.selections.newest::<Point>(cx).is_empty() {
let display_map = context_editor.display_snapshot(cx);
if context_editor
.selections
.newest::<Point>(&display_map)
.is_empty()
{
let snapshot = context_editor.buffer().read(cx).snapshot(cx);
let (_, _, snapshot) = snapshot.as_singleton()?;
let head = context_editor.selections.newest::<Point>(cx).head();
let head = context_editor
.selections
.newest::<Point>(&display_map)
.head();
let offset = snapshot.point_to_offset(head);
let surrounding_code_block_range = find_surrounding_code_block(snapshot, offset)?;
@@ -1269,7 +1280,7 @@ impl TextThreadEditor {
(!text.is_empty()).then_some((text, true))
} else {
let selection = context_editor.selections.newest_adjusted(cx);
let selection = context_editor.selections.newest_adjusted(&display_map);
let buffer = context_editor.buffer().read(cx).snapshot(cx);
let selected_text = buffer.text_for_range(selection.range()).collect::<String>();
@@ -1457,7 +1468,7 @@ impl TextThreadEditor {
let selections = editor.update(cx, |editor, cx| {
editor
.selections
.all_adjusted(cx)
.all_adjusted(&editor.display_snapshot(cx))
.into_iter()
.filter_map(|s| {
(!s.is_empty())
@@ -1489,7 +1500,10 @@ impl TextThreadEditor {
self.editor.update(cx, |editor, cx| {
editor.insert("\n", window, cx);
for (text, crease_title) in creases {
let point = editor.selections.newest::<Point>(cx).head();
let point = editor
.selections
.newest::<Point>(&editor.display_snapshot(cx))
.head();
let start_row = MultiBufferRow(point.row);
editor.insert(&text, window, cx);
@@ -1561,7 +1575,9 @@ impl TextThreadEditor {
cx: &mut Context<Self>,
) -> (String, CopyMetadata, Vec<text::Selection<usize>>) {
let (mut selection, creases) = self.editor.update(cx, |editor, cx| {
let mut selection = editor.selections.newest_adjusted(cx);
let mut selection = editor
.selections
.newest_adjusted(&editor.display_snapshot(cx));
let snapshot = editor.buffer().read(cx).snapshot(cx);
selection.goal = SelectionGoal::None;
@@ -1680,7 +1696,10 @@ impl TextThreadEditor {
if images.is_empty() {
self.editor.update(cx, |editor, cx| {
let paste_position = editor.selections.newest::<usize>(cx).head();
let paste_position = editor
.selections
.newest::<usize>(&editor.display_snapshot(cx))
.head();
editor.paste(action, window, cx);
if let Some(metadata) = metadata {
@@ -1727,13 +1746,13 @@ impl TextThreadEditor {
editor.transact(window, cx, |editor, _window, cx| {
let edits = editor
.selections
.all::<usize>(cx)
.all::<usize>(&editor.display_snapshot(cx))
.into_iter()
.map(|selection| (selection.start..selection.end, "\n"));
editor.edit(edits, cx);
let snapshot = editor.buffer().read(cx).snapshot(cx);
for selection in editor.selections.all::<usize>(cx) {
for selection in editor.selections.all::<usize>(&editor.display_snapshot(cx)) {
image_positions.push(snapshot.anchor_before(selection.end));
}
});