editor: Improve minimap performance (#33067)

This PR aims to improve the minimap performace. This is primarily
achieved by disabling/removing stuff that is not shown in the minimal as
well as by assuring the display map is not updated during minimap
prepaint.

This should already be much better in parts, as the block map as well as
the fold map will be less frequently updated due to the minimap
prepainting (optimally, they should never be, but I think we're not
quite there yet).
For this, I had to remove block rendering support for the minimap, which
is not as bad as it sounds: Practically, we were currently not rendering
most blocks anyway, there were issues due to this (e.g. scrolling any
visible block offscreen in the main editor causes scroll jumps
currently) and in the long run, the minimap will most likely need its
own block map or a different approach anyway. The existing
implementation caused resizes to occur very frequently for practically
no benefit. Can pull this out into a separate PR if requested, most
likely makes the other changes here easier to discuss.

This is WIP as we are still hitting some code path here we definitely
should not be hitting. E.g. there seems to be a rerender roughly every
second if the window is unfocused but visible which does not happen when
the minimap is disabled.

While this primarily focuses on the minimap, it also touches a few other
small parts not related to the minimap where I noticed we were doing too
much stuff during prepaint. Happy for any feedback there aswell.

Putting this up here already so we have a place to discuss the changes
early if needed.

Release Notes:

- Improved performance with the minimap enabled.
- Fixed an issue where interacting with blocks in the editor would
sometimes not properly work with the minimap enabled.
This commit is contained in:
Finn Evers 2025-07-14 23:29:27 +02:00 committed by GitHub
parent 363a265051
commit 26ba6e7e00
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 207 additions and 184 deletions

View file

@ -660,7 +660,6 @@ impl InlineAssistant {
height: Some(prompt_editor_height),
render: build_assist_editor_renderer(prompt_editor),
priority: 0,
render_in_minimap: false,
},
BlockProperties {
style: BlockStyle::Sticky,
@ -675,7 +674,6 @@ impl InlineAssistant {
.into_any_element()
}),
priority: 0,
render_in_minimap: false,
},
];
@ -1451,7 +1449,6 @@ impl InlineAssistant {
.into_any_element()
}),
priority: 0,
render_in_minimap: false,
});
}

View file

@ -1256,7 +1256,6 @@ impl TextThreadEditor {
),
priority: usize::MAX,
render: render_block(MessageMetadata::from(message)),
render_in_minimap: false,
};
let mut new_blocks = vec![];
let mut block_index_to_message = vec![];
@ -1858,7 +1857,6 @@ impl TextThreadEditor {
.into_any_element()
}),
priority: 0,
render_in_minimap: false,
})
})
.collect::<Vec<_>>();

View file

@ -144,7 +144,6 @@ impl editor::DiagnosticRenderer for DiagnosticRenderer {
style: BlockStyle::Flex,
render: Arc::new(move |bcx| block.render_block(editor.clone(), bcx)),
priority: 1,
render_in_minimap: false,
}
})
.collect()

View file

@ -656,7 +656,6 @@ impl ProjectDiagnosticsEditor {
block.render_block(editor.clone(), bcx)
}),
priority: 1,
render_in_minimap: false,
}
});
let block_ids = this.editor.update(cx, |editor, cx| {

View file

@ -271,7 +271,6 @@ impl DisplayMap {
height: Some(height),
style,
priority,
render_in_minimap: true,
}
}),
);
@ -1663,7 +1662,6 @@ pub mod tests {
height: Some(height),
render: Arc::new(|_| div().into_any()),
priority,
render_in_minimap: true,
}
})
.collect::<Vec<_>>();
@ -2029,7 +2027,6 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}],
cx,
);
@ -2227,7 +2224,6 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
placement: BlockPlacement::Below(
@ -2237,7 +2233,6 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
],
cx,
@ -2344,7 +2339,6 @@ pub mod tests {
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}],
cx,
)
@ -2420,7 +2414,6 @@ pub mod tests {
style: BlockStyle::Fixed,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}],
cx,
);

View file

@ -193,7 +193,6 @@ pub struct CustomBlock {
style: BlockStyle,
render: Arc<Mutex<RenderBlock>>,
priority: usize,
pub(crate) render_in_minimap: bool,
}
#[derive(Clone)]
@ -205,7 +204,6 @@ pub struct BlockProperties<P> {
pub style: BlockStyle,
pub render: RenderBlock,
pub priority: usize,
pub render_in_minimap: bool,
}
impl<P: Debug> Debug for BlockProperties<P> {
@ -1044,7 +1042,6 @@ impl BlockMapWriter<'_> {
render: Arc::new(Mutex::new(block.render)),
style: block.style,
priority: block.priority,
render_in_minimap: block.render_in_minimap,
});
self.0.custom_blocks.insert(block_ix, new_block.clone());
self.0.custom_blocks_by_id.insert(id, new_block);
@ -1079,7 +1076,6 @@ impl BlockMapWriter<'_> {
style: block.style,
render: block.render.clone(),
priority: block.priority,
render_in_minimap: block.render_in_minimap,
};
let new_block = Arc::new(new_block);
*block = new_block.clone();
@ -1976,7 +1972,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -1984,7 +1979,6 @@ mod tests {
height: Some(2),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -1992,7 +1986,6 @@ mod tests {
height: Some(3),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
]);
@ -2217,7 +2210,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2225,7 +2217,6 @@ mod tests {
height: Some(2),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2233,7 +2224,6 @@ mod tests {
height: Some(3),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
]);
@ -2322,7 +2312,6 @@ mod tests {
render: Arc::new(|_| div().into_any()),
height: Some(1),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2330,7 +2319,6 @@ mod tests {
render: Arc::new(|_| div().into_any()),
height: Some(1),
priority: 0,
render_in_minimap: true,
},
]);
@ -2370,7 +2358,6 @@ mod tests {
height: Some(4),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}])[0];
let blocks_snapshot = block_map.read(wraps_snapshot, Default::default());
@ -2424,7 +2411,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2432,7 +2418,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2440,7 +2425,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
]);
let blocks_snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
@ -2455,7 +2439,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2463,7 +2446,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2471,7 +2453,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
]);
let blocks_snapshot = block_map.read(wraps_snapshot.clone(), Default::default());
@ -2571,7 +2552,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2579,7 +2559,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2587,7 +2566,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
]);
let excerpt_blocks_3 = writer.insert(vec![
@ -2597,7 +2575,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
BlockProperties {
style: BlockStyle::Fixed,
@ -2605,7 +2582,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
},
]);
@ -2653,7 +2629,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}]);
let blocks_snapshot = block_map.read(wrap_snapshot.clone(), Patch::default());
let blocks = blocks_snapshot
@ -3011,7 +2986,6 @@ mod tests {
height: Some(height),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}
})
.collect::<Vec<_>>();
@ -3032,7 +3006,6 @@ mod tests {
style: props.style,
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}));
for (block_properties, block_id) in block_properties.iter().zip(block_ids) {
@ -3557,7 +3530,6 @@ mod tests {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}])[0];
let blocks_snapshot = block_map.read(wraps_snapshot.clone(), Default::default());

View file

@ -1795,6 +1795,7 @@ impl Editor {
);
let full_mode = mode.is_full();
let is_minimap = mode.is_minimap();
let diagnostics_max_severity = if full_mode {
EditorSettings::get_global(cx)
.diagnostics_max_severity
@ -1855,13 +1856,19 @@ impl Editor {
let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
let blink_manager = cx.new(|cx| {
let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
if is_minimap {
blink_manager.disable(cx);
}
blink_manager
});
let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
.then(|| language_settings::SoftWrap::None);
let mut project_subscriptions = Vec::new();
if mode.is_full() {
if full_mode {
if let Some(project) = project.as_ref() {
project_subscriptions.push(cx.subscribe_in(
project,
@ -1972,18 +1979,23 @@ impl Editor {
let inlay_hint_settings =
inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
let focus_handle = cx.focus_handle();
cx.on_focus(&focus_handle, window, Self::handle_focus)
.detach();
cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
.detach();
cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
.detach();
cx.on_blur(&focus_handle, window, Self::handle_blur)
.detach();
cx.observe_pending_input(window, Self::observe_pending_input)
.detach();
if !is_minimap {
cx.on_focus(&focus_handle, window, Self::handle_focus)
.detach();
cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
.detach();
cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
.detach();
cx.on_blur(&focus_handle, window, Self::handle_blur)
.detach();
cx.observe_pending_input(window, Self::observe_pending_input)
.detach();
}
let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
let show_indent_guides = if matches!(
mode,
EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
) {
Some(false)
} else {
None
@ -2049,10 +2061,10 @@ impl Editor {
minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
show_gutter: mode.is_full(),
show_line_numbers: None,
show_gutter: full_mode,
show_line_numbers: (!full_mode).then_some(false),
use_relative_line_numbers: None,
disable_expand_excerpt_buttons: false,
disable_expand_excerpt_buttons: !full_mode,
show_git_diff_gutter: None,
show_code_actions: None,
show_runnables: None,
@ -2086,7 +2098,7 @@ impl Editor {
document_highlights_task: None,
linked_editing_range_task: None,
pending_rename: None,
searchable: true,
searchable: !is_minimap,
cursor_shape: EditorSettings::get_global(cx)
.cursor_shape
.unwrap_or_default(),
@ -2094,9 +2106,9 @@ impl Editor {
autoindent_mode: Some(AutoindentMode::EachLine),
collapse_matches: false,
workspace: None,
input_enabled: true,
use_modal_editing: mode.is_full(),
read_only: mode.is_minimap(),
input_enabled: !is_minimap,
use_modal_editing: full_mode,
read_only: is_minimap,
use_autoclose: true,
use_auto_surround: true,
auto_replace_emoji_shortcode: false,
@ -2112,11 +2124,10 @@ impl Editor {
edit_prediction_preview: EditPredictionPreview::Inactive {
released_too_fast: false,
},
inline_diagnostics_enabled: mode.is_full(),
diagnostics_enabled: mode.is_full(),
inline_diagnostics_enabled: full_mode,
diagnostics_enabled: full_mode,
inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
gutter_hovered: false,
pixel_position_of_newest_cursor: None,
last_bounds: None,
@ -2139,9 +2150,10 @@ impl Editor {
show_git_blame_inline: false,
show_selection_menu: None,
show_git_blame_inline_delay_task: None,
git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
git_blame_inline_enabled: full_mode
&& ProjectSettings::get_global(cx).git.inline_blame_enabled(),
render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
serialize_dirty_buffers: !mode.is_minimap()
serialize_dirty_buffers: !is_minimap
&& ProjectSettings::get_global(cx)
.session
.restore_unsaved_buffers,
@ -2152,27 +2164,31 @@ impl Editor {
breakpoint_store,
gutter_breakpoint_indicator: (None, None),
hovered_diff_hunk_row: None,
_subscriptions: vec![
cx.observe(&buffer, Self::on_buffer_changed),
cx.subscribe_in(&buffer, window, Self::on_buffer_event),
cx.observe_in(&display_map, window, Self::on_display_map_changed),
cx.observe(&blink_manager, |_, _, cx| cx.notify()),
cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
cx.observe_window_activation(window, |editor, window, cx| {
let active = window.is_window_active();
editor.blink_manager.update(cx, |blink_manager, cx| {
if active {
blink_manager.enable(cx);
} else {
blink_manager.disable(cx);
}
});
if active {
editor.show_mouse_cursor(cx);
}
}),
],
_subscriptions: (!is_minimap)
.then(|| {
vec![
cx.observe(&buffer, Self::on_buffer_changed),
cx.subscribe_in(&buffer, window, Self::on_buffer_event),
cx.observe_in(&display_map, window, Self::on_display_map_changed),
cx.observe(&blink_manager, |_, _, cx| cx.notify()),
cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
cx.observe_window_activation(window, |editor, window, cx| {
let active = window.is_window_active();
editor.blink_manager.update(cx, |blink_manager, cx| {
if active {
blink_manager.enable(cx);
} else {
blink_manager.disable(cx);
}
});
if active {
editor.show_mouse_cursor(cx);
}
}),
]
})
.unwrap_or_default(),
tasks_update_task: None,
pull_diagnostics_task: Task::ready(()),
colors: None,
@ -2203,6 +2219,11 @@ impl Editor {
selection_drag_state: SelectionDragState::None,
folding_newlines: Task::ready(()),
};
if is_minimap {
return editor;
}
if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
editor
._subscriptions
@ -10445,7 +10466,6 @@ impl Editor {
cloned_prompt.clone().into_any_element()
}),
priority: 0,
render_in_minimap: true,
}];
let focus_handle = bp_prompt.focus_handle(cx);
@ -16141,7 +16161,6 @@ impl Editor {
}
}),
priority: 0,
render_in_minimap: true,
}],
Some(Autoscroll::fit()),
cx,
@ -18044,7 +18063,7 @@ impl Editor {
parent: cx.weak_entity(),
},
self.buffer.clone(),
self.project.clone(),
None,
Some(self.display_map.clone()),
window,
cx,
@ -19928,14 +19947,12 @@ impl Editor {
}
fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let new_severity = if self.diagnostics_enabled() {
EditorSettings::get_global(cx)
if self.diagnostics_enabled() {
let new_severity = EditorSettings::get_global(cx)
.diagnostics_max_severity
.unwrap_or(DiagnosticSeverity::Hint)
} else {
DiagnosticSeverity::Off
};
self.set_max_diagnostics_severity(new_severity, cx);
.unwrap_or(DiagnosticSeverity::Hint);
self.set_max_diagnostics_severity(new_severity, cx);
}
self.tasks_update_task = Some(self.refresh_runnables(window, cx));
self.update_edit_prediction_settings(cx);
self.refresh_inline_completion(true, false, window, cx);

View file

@ -5081,7 +5081,6 @@ fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) {
height: Some(1),
render: Arc::new(|_| div().into_any()),
priority: 0,
render_in_minimap: true,
}],
Some(Autoscroll::fit()),
cx,
@ -5124,7 +5123,6 @@ async fn test_selections_and_replace_blocks(cx: &mut TestAppContext) {
style: BlockStyle::Sticky,
render: Arc::new(|_| gpui::div().into_any_element()),
priority: 0,
render_in_minimap: true,
}],
None,
cx,

View file

@ -2094,16 +2094,19 @@ impl EditorElement {
window: &mut Window,
cx: &mut App,
) -> HashMap<DisplayRow, AnyElement> {
if self.editor.read(cx).mode().is_minimap() {
return HashMap::default();
}
let max_severity = match ProjectSettings::get_global(cx)
.diagnostics
.inline
.max_severity
.unwrap_or_else(|| self.editor.read(cx).diagnostics_max_severity)
.into_lsp()
let max_severity = match self
.editor
.read(cx)
.inline_diagnostics_enabled()
.then(|| {
ProjectSettings::get_global(cx)
.diagnostics
.inline
.max_severity
.unwrap_or_else(|| self.editor.read(cx).diagnostics_max_severity)
.into_lsp()
})
.flatten()
{
Some(max_severity) => max_severity,
None => return HashMap::default(),
@ -2619,9 +2622,6 @@ impl EditorElement {
window: &mut Window,
cx: &mut App,
) -> Option<Vec<IndentGuideLayout>> {
if self.editor.read(cx).mode().is_minimap() {
return None;
}
let indent_guides = self.editor.update(cx, |editor, cx| {
editor.indent_guides(visible_buffer_range, snapshot, cx)
})?;
@ -3085,9 +3085,9 @@ impl EditorElement {
window: &mut Window,
cx: &mut App,
) -> Arc<HashMap<MultiBufferRow, LineNumberLayout>> {
let include_line_numbers = snapshot.show_line_numbers.unwrap_or_else(|| {
EditorSettings::get_global(cx).gutter.line_numbers && snapshot.mode.is_full()
});
let include_line_numbers = snapshot
.show_line_numbers
.unwrap_or_else(|| EditorSettings::get_global(cx).gutter.line_numbers);
if !include_line_numbers {
return Arc::default();
}
@ -3400,22 +3400,18 @@ impl EditorElement {
div()
.size_full()
.children(
(!snapshot.mode.is_minimap() || custom.render_in_minimap).then(|| {
custom.render(&mut BlockContext {
window,
app: cx,
anchor_x,
margins: editor_margins,
line_height,
em_width,
block_id,
selected,
max_width: text_hitbox.size.width.max(*scroll_width),
editor_style: &self.style,
})
}),
)
.child(custom.render(&mut BlockContext {
window,
app: cx,
anchor_x,
margins: editor_margins,
line_height,
em_width,
block_id,
selected,
max_width: text_hitbox.size.width.max(*scroll_width),
editor_style: &self.style,
}))
.into_any()
}
@ -6776,7 +6772,7 @@ impl EditorElement {
}
fn paint_mouse_listeners(&mut self, layout: &EditorLayout, window: &mut Window, cx: &mut App) {
if self.editor.read(cx).mode.is_minimap() {
if layout.mode.is_minimap() {
return;
}
@ -7903,9 +7899,14 @@ impl Element for EditorElement {
line_height: Some(self.style.text.line_height),
..Default::default()
};
let focus_handle = self.editor.focus_handle(cx);
window.set_view_id(self.editor.entity_id());
window.set_focus_handle(&focus_handle, cx);
let is_minimap = self.editor.read(cx).mode.is_minimap();
if !is_minimap {
let focus_handle = self.editor.focus_handle(cx);
window.set_view_id(self.editor.entity_id());
window.set_focus_handle(&focus_handle, cx);
}
let rem_size = self.rem_size(cx);
window.with_rem_size(rem_size, |window| {
@ -8343,18 +8344,22 @@ impl Element for EditorElement {
window,
cx,
);
let new_renrerer_widths = line_layouts
.iter()
.flat_map(|layout| &layout.fragments)
.filter_map(|fragment| {
if let LineFragment::Element { id, size, .. } = fragment {
Some((*id, size.width))
} else {
None
}
});
if self.editor.update(cx, |editor, cx| {
editor.update_renderer_widths(new_renrerer_widths, cx)
let new_renderer_widths = (!is_minimap).then(|| {
line_layouts
.iter()
.flat_map(|layout| &layout.fragments)
.filter_map(|fragment| {
if let LineFragment::Element { id, size, .. } = fragment {
Some((*id, size.width))
} else {
None
}
})
});
if new_renderer_widths.is_some_and(|new_renderer_widths| {
self.editor.update(cx, |editor, cx| {
editor.update_renderer_widths(new_renderer_widths, cx)
})
}) {
// If the fold widths have changed, we need to prepaint
// the element again to account for any changes in
@ -8417,27 +8422,31 @@ impl Element for EditorElement {
let sticky_header_excerpt_id =
sticky_header_excerpt.as_ref().map(|top| top.excerpt.id);
let blocks = window.with_element_namespace("blocks", |window| {
self.render_blocks(
start_row..end_row,
&snapshot,
&hitbox,
&text_hitbox,
editor_width,
&mut scroll_width,
&editor_margins,
em_width,
gutter_dimensions.full_width(),
line_height,
&mut line_layouts,
&local_selections,
&selected_buffer_ids,
is_row_soft_wrapped,
sticky_header_excerpt_id,
window,
cx,
)
});
let blocks = (!is_minimap)
.then(|| {
window.with_element_namespace("blocks", |window| {
self.render_blocks(
start_row..end_row,
&snapshot,
&hitbox,
&text_hitbox,
editor_width,
&mut scroll_width,
&editor_margins,
em_width,
gutter_dimensions.full_width(),
line_height,
&mut line_layouts,
&local_selections,
&selected_buffer_ids,
is_row_soft_wrapped,
sticky_header_excerpt_id,
window,
cx,
)
})
})
.unwrap_or_else(|| Ok((Vec::default(), HashMap::default())));
let (mut blocks, row_block_types) = match blocks {
Ok(blocks) => blocks,
Err(resized_blocks) => {
@ -8969,19 +8978,21 @@ impl Element for EditorElement {
window: &mut Window,
cx: &mut App,
) {
let focus_handle = self.editor.focus_handle(cx);
let key_context = self
.editor
.update(cx, |editor, cx| editor.key_context(window, cx));
if !layout.mode.is_minimap() {
let focus_handle = self.editor.focus_handle(cx);
let key_context = self
.editor
.update(cx, |editor, cx| editor.key_context(window, cx));
window.set_key_context(key_context);
window.handle_input(
&focus_handle,
ElementInputHandler::new(bounds, self.editor.clone()),
cx,
);
self.register_actions(window, cx);
self.register_key_listeners(window, cx, layout);
window.set_key_context(key_context);
window.handle_input(
&focus_handle,
ElementInputHandler::new(bounds, self.editor.clone()),
cx,
);
self.register_actions(window, cx);
self.register_key_listeners(window, cx, layout);
}
let text_style = TextStyleRefinement {
font_size: Some(self.style.text.font_size),
@ -10290,7 +10301,6 @@ mod tests {
height: Some(3),
render: Arc::new(|cx| div().h(3. * cx.window.line_height()).into_any()),
priority: 0,
render_in_minimap: true,
}],
None,
cx,

View file

@ -297,7 +297,6 @@ fn conflicts_updated(
move |cx| render_conflict_buttons(&conflict, excerpt_id, editor_handle.clone(), cx)
}),
priority: 0,
render_in_minimap: true,
})
}
let new_block_ids = editor.insert_blocks(blocks, None, cx);

View file

@ -90,7 +90,6 @@ impl EditorBlock {
style: BlockStyle::Sticky,
render: Self::create_output_area_renderer(execution_view.clone(), on_close.clone()),
priority: 0,
render_in_minimap: false,
};
let block_id = editor.insert_blocks([block], None, cx)[0];

View file

@ -37,6 +37,48 @@ development build, run Zed with the following environment variable set:
ZED_DEVELOPMENT_USE_KEYCHAIN=1
```
## Performance Measurements
Zed includes a frame time measurement system that can be used to profile how long it takes to render each frame. This is particularly useful when comparing rendering performance between different versions or when optimizing frame rendering code.
### Using ZED_MEASUREMENTS
To enable performance measurements, set the `ZED_MEASUREMENTS` environment variable:
```sh
export ZED_MEASUREMENTS=1
```
When enabled, Zed will print frame rendering timing information to stderr, showing how long each frame takes to render.
### Performance Comparison Workflow
Here's a typical workflow for comparing frame rendering performance between different versions:
1. **Enable measurements:**
```sh
export ZED_MEASUREMENTS=1
```
2. **Test the first version:**
- Checkout the commit you want to measure
- Run Zed in release mode and use it for 5-10 seconds: `cargo run --release &> version-a`
3. **Test the second version:**
- Checkout another commit you want to compare
- Run Zed in release mode and use it for 5-10 seconds: `cargo run --release &> version-b`
4. **Generate comparison:**
```sh
script/histogram version-a version-b
```
The `script/histogram` tool can accept as many measurement files as you like and will generate a histogram visualization comparing the frame rendering performance data between the provided versions.
## Contributor links
- [CONTRIBUTING.md](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md)