editor: Fix inline blame show/hide not working until buffer interaction (#32683)

We recently fixed the issue of `cx.notify` on every mouse move event
https://github.com/zed-industries/zed/pull/32408. As this perf bug was
there for a long time, we made some not-optimal choices for checking
things like if the mouse is hovering over an element in the prepaint
phase rather than the `mouse_move` listener.

After the mentioned fix, it regressed these code paths as prepaint is
not being called for every other frame, and hence the mouse hovering
logic never triggers. This bug is directly noticeable when the
"cursor_blink" setting is turned off, which notifies the editor on every
second.

This PR fixes that for git inline blame popover by moving logic to
show/hide in `mouse_move` instead of prepaint phase. `cx.notify` is only
get called only when popover is shown or hidden.

Release Notes:

- Fixed git inline blame not correctly showing in Editor on hover when
`cursor_blink` is `false`.
This commit is contained in:
Smit Barmase 2025-06-13 17:53:13 +05:30 committed by GitHub
parent d5b8c21a75
commit aa1cb9c1e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 171 additions and 175 deletions

View file

@ -899,7 +899,6 @@ struct InlineBlamePopoverState {
struct InlineBlamePopover {
position: gpui::Point<Pixels>,
show_task: Option<Task<()>>,
hide_task: Option<Task<()>>,
popover_bounds: Option<Bounds<Pixels>>,
popover_state: InlineBlamePopoverState,
@ -1007,6 +1006,7 @@ pub struct Editor {
mouse_context_menu: Option<MouseContextMenu>,
completion_tasks: Vec<(CompletionId, Task<()>)>,
inline_blame_popover: Option<InlineBlamePopover>,
inline_blame_popover_show_task: Option<Task<()>>,
signature_help_state: SignatureHelpState,
auto_signature_help: Option<bool>,
find_all_references_task_sources: Vec<Anchor>,
@ -1938,6 +1938,7 @@ impl Editor {
mouse_context_menu: None,
completion_tasks: Vec::new(),
inline_blame_popover: None,
inline_blame_popover_show_task: None,
signature_help_state: SignatureHelpState::default(),
auto_signature_help: None,
find_all_references_task_sources: Vec::new(),
@ -6276,71 +6277,65 @@ impl Editor {
) {
if let Some(state) = &mut self.inline_blame_popover {
state.hide_task.take();
cx.notify();
} else {
let delay = EditorSettings::get_global(cx).hover_popover_delay;
let blame_entry = blame_entry.clone();
let show_task = cx.spawn(async move |editor, cx| {
cx.background_executor()
.timer(std::time::Duration::from_millis(delay))
.await;
editor
.update(cx, |editor, cx| {
if let Some(state) = &mut editor.inline_blame_popover {
state.show_task = None;
cx.notify();
}
editor.inline_blame_popover_show_task.take();
let Some(blame) = editor.blame.as_ref() else {
return;
};
let blame = blame.read(cx);
let details = blame.details_for_entry(&blame_entry);
let markdown = cx.new(|cx| {
Markdown::new(
details
.as_ref()
.map(|message| message.message.clone())
.unwrap_or_default(),
None,
None,
cx,
)
});
editor.inline_blame_popover = Some(InlineBlamePopover {
position,
hide_task: None,
popover_bounds: None,
popover_state: InlineBlamePopoverState {
scroll_handle: ScrollHandle::new(),
commit_message: details,
markdown,
},
});
cx.notify();
})
.ok();
});
let Some(blame) = self.blame.as_ref() else {
return;
};
let blame = blame.read(cx);
let details = blame.details_for_entry(&blame_entry);
let markdown = cx.new(|cx| {
Markdown::new(
details
.as_ref()
.map(|message| message.message.clone())
.unwrap_or_default(),
None,
None,
cx,
)
});
self.inline_blame_popover = Some(InlineBlamePopover {
position,
show_task: Some(show_task),
hide_task: None,
popover_bounds: None,
popover_state: InlineBlamePopoverState {
scroll_handle: ScrollHandle::new(),
commit_message: details,
markdown,
},
});
self.inline_blame_popover_show_task = Some(show_task);
}
}
fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
self.inline_blame_popover_show_task.take();
if let Some(state) = &mut self.inline_blame_popover {
if state.show_task.is_some() {
self.inline_blame_popover.take();
cx.notify();
} else {
let hide_task = cx.spawn(async move |editor, cx| {
cx.background_executor()
.timer(std::time::Duration::from_millis(100))
.await;
editor
.update(cx, |editor, cx| {
editor.inline_blame_popover.take();
cx.notify();
})
.ok();
});
state.hide_task = Some(hide_task);
}
let hide_task = cx.spawn(async move |editor, cx| {
cx.background_executor()
.timer(std::time::Duration::from_millis(100))
.await;
editor
.update(cx, |editor, cx| {
editor.inline_blame_popover.take();
cx.notify();
})
.ok();
});
state.hide_task = Some(hide_task);
}
}