diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 1fcc90a863c0e545f67d23f99c896e3a8cb13787..101b424e4e99c7fdb4ce536d3635db61d8b3bc8e 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -5107,6 +5107,7 @@ impl EditorElement { snapshot, visible_display_row_range.clone(), max_size, + &editor.text_layout_details(window), window, cx, ) diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index e6eb5c1ea28c07248ef663097cac2c586b7db107..6227d90e9be7a5fbbe98b9dd8900860c219d07d2 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -3,6 +3,7 @@ use crate::{ EditorSnapshot, GlobalDiagnosticRenderer, Hover, display_map::{InlayOffset, ToDisplayPoint, invisibles::is_invisible}, hover_links::{InlayHighlight, RangeInEditor}, + movement::TextLayoutDetails, scroll::ScrollAmount, }; use anyhow::Context as _; @@ -766,9 +767,13 @@ impl HoverState { snapshot: &EditorSnapshot, visible_rows: Range, max_size: Size, + text_layout_details: &TextLayoutDetails, window: &mut Window, cx: &mut Context, ) -> Option<(DisplayPoint, Vec)> { + if !self.visible() { + return None; + } // If there is a diagnostic, position the popovers based on that. // Otherwise use the start of the hover range let anchor = self @@ -791,11 +796,29 @@ impl HoverState { } }) })?; - let point = anchor.to_display_point(&snapshot.display_snapshot); - - // Don't render if the relevant point isn't on screen - if !self.visible() || !visible_rows.contains(&point.row()) { - return None; + let mut point = anchor.to_display_point(&snapshot.display_snapshot); + + // Clamp the point within the visible rows in case the popup source spans multiple lines + if point.row() < visible_rows.start { + point = crate::movement::down_by_rows( + &snapshot.display_snapshot, + point, + (visible_rows.start - point.row()).0, + text::SelectionGoal::None, + true, + text_layout_details, + ) + .0; + } else if visible_rows.end <= point.row() { + point = crate::movement::up_by_rows( + &snapshot.display_snapshot, + point, + (visible_rows.end - point.row()).0, + text::SelectionGoal::None, + true, + text_layout_details, + ) + .0; } let mut elements = Vec::new(); diff --git a/crates/gpui/src/executor.rs b/crates/gpui/src/executor.rs index 644bee6b8d6cc2de6bd2c698d0fe170b8e8c2f56..b820e120dd738df8a39d3a40379414984942f158 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -281,7 +281,8 @@ impl BackgroundExecutor { }); let mut cx = std::task::Context::from_waker(&waker); - let mut test_should_end_by = Instant::now() + Duration::from_secs(500); + let duration = Duration::from_secs(500); + let mut test_should_end_by = Instant::now() + duration; loop { match future.as_mut().poll(&mut cx) { @@ -319,7 +320,7 @@ impl BackgroundExecutor { test_should_end_by.saturating_duration_since(Instant::now()), ); if Instant::now() > test_should_end_by { - panic!("test timed out with allow_parking") + panic!("test timed out after {duration:?} with allow_parking") } } }