diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index a2e693fcd3..24a7c490f9 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1335,8 +1335,11 @@ impl Element for EditorElement { .map(|indicator| (newest_selection_head.row(), indicator)); } - hover = view.hover_state.popover.clone().and_then(|hover| { + hover = view.hover_state.info_popover.clone().and_then(|hover| { let (point, rendered) = hover.render(&snapshot, style.clone(), cx); + // The scroll position is a fractional point, the whole number of which represents + // the top of the window in terms of display rows. + // Ensure the hover point is above the scroll position if point.row() >= snapshot.scroll_position().y() as u32 { if line_layouts.len() > (point.row() - start_row) as usize { return Some((point, rendered)); diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index 7ae9e01b09..a2e99275ac 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -32,6 +32,21 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(hover_at); } +#[derive(Default)] +pub struct HoverState { + pub info_popover: Option, + pub diagnostic_popover: Option, + pub triggered_from: Option, + pub symbol_range: Option>, + pub task: Option>>, +} + +impl HoverState { + pub fn visible(&self) -> bool { + self.info_popover.is_some() + } +} + /// Bindable action which uses the most recent selection head to trigger a hover pub fn hover(editor: &mut Editor, _: &Hover, cx: &mut ViewContext) { let head = editor.selections.newest_display(cx).head(); @@ -57,8 +72,8 @@ pub fn hide_hover(editor: &mut Editor, cx: &mut ViewContext) -> bool { let mut did_hide = false; // only notify the context once - if editor.hover_state.popover.is_some() { - editor.hover_state.popover = None; + if editor.hover_state.info_popover.is_some() { + editor.hover_state.info_popover = None; did_hide = true; cx.notify(); } @@ -167,6 +182,16 @@ fn show_hover( }) }); + if let Some(delay) = delay { + delay.await; + } + + // If there's a diagnostic, assign it on the hover state and notify + let diagnostic = snapshot + .buffer_snapshot + .diagnostics_in_range::<_, usize>(multibuffer_offset..multibuffer_offset, false) + .next(); + // Construct new hover popover from hover request let hover_popover = hover_request.await.ok().flatten().and_then(|hover_result| { if hover_result.contents.is_empty() { @@ -194,17 +219,13 @@ fn show_hover( }); } - Some(HoverPopover { + Some(InfoPopover { project: project.clone(), anchor: range.start.clone(), contents: hover_result.contents, }) }); - if let Some(delay) = delay { - delay.await; - } - if let Some(this) = this.upgrade(&cx) { this.update(&mut cx, |this, cx| { if hover_popover.is_some() { @@ -216,7 +237,7 @@ fn show_hover( cx, ); } - this.hover_state.popover = hover_popover; + this.hover_state.info_popover = hover_popover; cx.notify(); } else { if this.hover_state.visible() { @@ -237,35 +258,21 @@ fn show_hover( editor.hover_state.task = Some(task); } -#[derive(Default)] -pub struct HoverState { - pub popover: Option, - pub triggered_from: Option, - pub symbol_range: Option>, - pub task: Option>>, -} - -impl HoverState { - pub fn visible(&self) -> bool { - self.popover.is_some() - } -} - #[derive(Debug, Clone)] -pub struct HoverPopover { +pub struct InfoPopover { pub project: ModelHandle, pub anchor: Anchor, pub contents: Vec, } -impl HoverPopover { +impl InfoPopover { pub fn render( &self, snapshot: &EditorSnapshot, style: EditorStyle, cx: &mut RenderContext, ) -> (DisplayPoint, ElementBox) { - let element = MouseEventHandler::new::(0, cx, |_, cx| { + let element = MouseEventHandler::new::(0, cx, |_, cx| { let mut flex = Flex::new(Axis::Vertical).scrollable::(1, None, cx); flex.extend(self.contents.iter().map(|content| { let project = self.project.read(cx); @@ -316,6 +323,9 @@ impl HoverPopover { } } +#[derive(Debug, Clone)] +pub struct DiagnosticPopover {} + #[cfg(test)] mod tests { use futures::StreamExt; @@ -382,7 +392,7 @@ mod tests { cx.editor(|editor, _| { assert!(editor.hover_state.visible()); assert_eq!( - editor.hover_state.popover.clone().unwrap().contents, + editor.hover_state.info_popover.clone().unwrap().contents, vec![ HoverBlock { text: "Some basic docs".to_string(), @@ -446,7 +456,7 @@ mod tests { cx.editor(|editor, _| { assert!(editor.hover_state.visible()); assert_eq!( - editor.hover_state.popover.clone().unwrap().contents, + editor.hover_state.info_popover.clone().unwrap().contents, vec![ HoverBlock { text: "Some other basic docs".to_string(),