mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-07 20:39:04 +03:00
Pass hover position as an anchor (#11578)
It's too easily to accidentally pass a point from one snapshot into another Release Notes: - Fixed a panic in show hover
This commit is contained in:
parent
a89dc8c42e
commit
b0494d1c05
@ -638,7 +638,11 @@ impl EditorElement {
|
||||
editor.update_hovered_link(point_for_position, &position_map.snapshot, modifiers, cx);
|
||||
|
||||
if let Some(point) = point_for_position.as_valid() {
|
||||
hover_at(editor, Some((point, &position_map.snapshot)), cx);
|
||||
let anchor = position_map
|
||||
.snapshot
|
||||
.buffer_snapshot
|
||||
.anchor_before(point.to_offset(&position_map.snapshot, Bias::Left));
|
||||
hover_at(editor, Some(anchor), cx);
|
||||
Self::update_visible_cursor(editor, point, position_map, cx);
|
||||
} else {
|
||||
hover_at(editor, None, cx);
|
||||
|
@ -10,9 +10,10 @@ use gpui::{
|
||||
ParentElement, Pixels, SharedString, Size, StatefulInteractiveElement, Styled, Task,
|
||||
ViewContext, WeakView,
|
||||
};
|
||||
use language::{markdown, Bias, DiagnosticEntry, Language, LanguageRegistry, ParsedMarkdown};
|
||||
use language::{markdown, DiagnosticEntry, Language, LanguageRegistry, ParsedMarkdown};
|
||||
|
||||
use lsp::DiagnosticSeverity;
|
||||
use multi_buffer::ToOffset;
|
||||
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart};
|
||||
use settings::Settings;
|
||||
use smol::stream::StreamExt;
|
||||
@ -30,21 +31,16 @@ pub const HOVER_POPOVER_GAP: Pixels = px(10.);
|
||||
|
||||
/// Bindable action which uses the most recent selection head to trigger a hover
|
||||
pub fn hover(editor: &mut Editor, _: &Hover, cx: &mut ViewContext<Editor>) {
|
||||
let head = editor.selections.newest_display(cx).head();
|
||||
let snapshot = editor.snapshot(cx);
|
||||
show_hover(editor, head, &snapshot, true, cx);
|
||||
let head = editor.selections.newest_anchor().head();
|
||||
show_hover(editor, head, true, cx);
|
||||
}
|
||||
|
||||
/// The internal hover action dispatches between `show_hover` or `hide_hover`
|
||||
/// depending on whether a point to hover over is provided.
|
||||
pub fn hover_at(
|
||||
editor: &mut Editor,
|
||||
point: Option<(DisplayPoint, &EditorSnapshot)>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
pub fn hover_at(editor: &mut Editor, anchor: Option<Anchor>, cx: &mut ViewContext<Editor>) {
|
||||
if EditorSettings::get_global(cx).hover_popover_enabled {
|
||||
if let Some((point, snapshot)) = point {
|
||||
show_hover(editor, point, snapshot, false, cx);
|
||||
if let Some(anchor) = anchor {
|
||||
show_hover(editor, anchor, false, cx);
|
||||
} else {
|
||||
hide_hover(editor, cx);
|
||||
}
|
||||
@ -164,8 +160,7 @@ pub fn hide_hover(editor: &mut Editor, cx: &mut ViewContext<Editor>) -> bool {
|
||||
/// Triggered by the `Hover` action when the cursor may be over a symbol.
|
||||
fn show_hover(
|
||||
editor: &mut Editor,
|
||||
point: DisplayPoint,
|
||||
snapshot: &EditorSnapshot,
|
||||
anchor: Anchor,
|
||||
ignore_timeout: bool,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
@ -173,27 +168,21 @@ fn show_hover(
|
||||
return;
|
||||
}
|
||||
|
||||
let multibuffer_offset = point.to_offset(&snapshot.display_snapshot, Bias::Left);
|
||||
let snapshot = editor.snapshot(cx);
|
||||
|
||||
let (buffer, buffer_position) = if let Some(output) = editor
|
||||
.buffer
|
||||
.read(cx)
|
||||
.text_anchor_for_position(multibuffer_offset, cx)
|
||||
{
|
||||
output
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let (buffer, buffer_position) =
|
||||
if let Some(output) = editor.buffer.read(cx).text_anchor_for_position(anchor, cx) {
|
||||
output
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let excerpt_id = if let Some((excerpt_id, _, _)) = editor
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.excerpt_containing(multibuffer_offset, cx)
|
||||
{
|
||||
excerpt_id
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let excerpt_id =
|
||||
if let Some((excerpt_id, _, _)) = editor.buffer().read(cx).excerpt_containing(anchor, cx) {
|
||||
excerpt_id
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let project = if let Some(project) = editor.project.clone() {
|
||||
project
|
||||
@ -211,9 +200,10 @@ fn show_hover(
|
||||
.as_text_range()
|
||||
.map(|range| {
|
||||
let hover_range = range.to_offset(&snapshot.buffer_snapshot);
|
||||
let offset = anchor.to_offset(&snapshot.buffer_snapshot);
|
||||
// LSP returns a hover result for the end index of ranges that should be hovered, so we need to
|
||||
// use an inclusive range here to check if we should dismiss the popover
|
||||
(hover_range.start..=hover_range.end).contains(&multibuffer_offset)
|
||||
(hover_range.start..=hover_range.end).contains(&offset)
|
||||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
@ -225,11 +215,6 @@ fn show_hover(
|
||||
}
|
||||
}
|
||||
|
||||
// Get input anchor
|
||||
let anchor = snapshot
|
||||
.buffer_snapshot
|
||||
.anchor_at(multibuffer_offset, Bias::Left);
|
||||
|
||||
// Don't request again if the location is the same as the previous request
|
||||
if let Some(triggered_from) = &editor.hover_state.triggered_from {
|
||||
if triggered_from
|
||||
@ -239,7 +224,6 @@ fn show_hover(
|
||||
return;
|
||||
}
|
||||
}
|
||||
let snapshot = snapshot.clone();
|
||||
|
||||
let task = cx.spawn(|this, mut cx| {
|
||||
async move {
|
||||
@ -273,7 +257,7 @@ fn show_hover(
|
||||
// If there's a diagnostic, assign it on the hover state and notify
|
||||
let local_diagnostic = snapshot
|
||||
.buffer_snapshot
|
||||
.diagnostics_in_range::<_, usize>(multibuffer_offset..multibuffer_offset, false)
|
||||
.diagnostics_in_range::<_, usize>(anchor..anchor, false)
|
||||
// Find the entry with the most specific range
|
||||
.min_by_key(|entry| entry.range.end - entry.range.start)
|
||||
.map(|entry| DiagnosticEntry {
|
||||
@ -641,6 +625,7 @@ mod tests {
|
||||
use lsp::LanguageServerId;
|
||||
use project::{HoverBlock, HoverBlockKind};
|
||||
use smol::stream::StreamExt;
|
||||
use text::Bias;
|
||||
use unindent::Unindent;
|
||||
use util::test::marked_text_ranges;
|
||||
|
||||
@ -667,7 +652,10 @@ mod tests {
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
hover_at(editor, Some((hover_point, &snapshot)), cx)
|
||||
let anchor = snapshot
|
||||
.buffer_snapshot
|
||||
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
|
||||
hover_at(editor, Some(anchor), cx)
|
||||
});
|
||||
assert!(!cx.editor(|editor, _| editor.hover_state.visible()));
|
||||
|
||||
@ -716,7 +704,10 @@ mod tests {
|
||||
.handle_request::<lsp::request::HoverRequest, _, _>(|_, _| async move { Ok(None) });
|
||||
cx.update_editor(|editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
hover_at(editor, Some((hover_point, &snapshot)), cx)
|
||||
let anchor = snapshot
|
||||
.buffer_snapshot
|
||||
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
|
||||
hover_at(editor, Some(anchor), cx)
|
||||
});
|
||||
cx.background_executor
|
||||
.advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
|
||||
|
Loading…
Reference in New Issue
Block a user