Account for element's bounds in Editor::bounds_for_range

Max Brunsfeld and Marshall created

Co-authored-by: Marshall <marshall@zed.dev>

Change summary

crates/editor2/src/editor.rs             | 40 ++++++++++++++++++++-----
crates/gpui2/src/window.rs               |  3 -
crates/gpui2/src/window_input_handler.rs |  2 
test.rs                                  | 24 +++++++-------
4 files changed, 46 insertions(+), 23 deletions(-)

Detailed changes

crates/editor2/src/editor.rs 🔗

@@ -39,10 +39,10 @@ use futures::FutureExt;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use git::diff_hunk_to_display;
 use gpui::{
-    action, actions, div, px, relative, AnyElement, AppContext, BackgroundExecutor, ClipboardItem,
-    Context, DispatchContext, Div, Element, Entity, EventEmitter, FocusHandle, FontStyle,
-    FontWeight, HighlightStyle, Hsla, InputHandler, Model, Pixels, PlatformInputHandler, Render,
-    Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakView,
+    action, actions, div, point, px, relative, AnyElement, AppContext, BackgroundExecutor, Bounds,
+    ClipboardItem, Context, DispatchContext, Div, Element, Entity, EventEmitter, FocusHandle,
+    FontStyle, FontWeight, HighlightStyle, Hsla, InputHandler, Model, Pixels, PlatformInputHandler,
+    Render, Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakView,
     WindowContext,
 };
 use highlight_matching_bracket::refresh_matching_bracket_highlights;
@@ -9750,14 +9750,38 @@ impl InputHandler for Editor {
     }
 
     fn bounds_for_range(
-        &self,
+        &mut self,
         range_utf16: Range<usize>,
         element_bounds: gpui::Bounds<Pixels>,
         cx: &mut ViewContext<Self>,
     ) -> Option<gpui::Bounds<Pixels>> {
-        // todo!()
-        // See how we did it before: `rect_for_range`
-        None
+        let text_layout_details = self.text_layout_details(cx);
+        let style = &text_layout_details.editor_style;
+        let font_id = cx.text_system().font_id(&style.text.font()).unwrap();
+        let font_size = style.text.font_size.to_pixels(cx.rem_size());
+        let line_height = style.text.line_height_in_pixels(cx.rem_size());
+        let em_width = cx
+            .text_system()
+            .typographic_bounds(font_id, font_size, 'm')
+            .unwrap()
+            .size
+            .width;
+
+        let snapshot = self.snapshot(cx);
+        let scroll_position = snapshot.scroll_position();
+        let scroll_left = scroll_position.x * em_width;
+
+        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
+        let end = OffsetUtf16(range_utf16.end).to_display_point(&snapshot);
+        let start_y = line_height * (start.row() as f32 - scroll_position.y);
+        let end_y = line_height * (end.row() as f32 - scroll_position.y);
+        let start_x = snapshot.x_for_point(start, &text_layout_details) - scroll_left;
+        let end_x = snapshot.x_for_point(end, &text_layout_details) - scroll_left;
+
+        Some(Bounds::from_corners(
+            element_bounds.origin + point(start_x, start_y),
+            element_bounds.origin + point(end_x, end_y),
+        ))
     }
 }
 

crates/gpui2/src/window.rs 🔗

@@ -8,8 +8,7 @@ use crate::{
     PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
     RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
     SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline,
-    UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowInputHandler, WindowOptions,
-    SUBPIXEL_VARIANTS,
+    UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
 };
 use anyhow::{anyhow, Result};
 use collections::HashMap;

crates/gpui2/src/window_input_handler.rs 🔗

@@ -159,7 +159,7 @@ pub trait InputHandler: Sized {
         cx: &mut ViewContext<Self>,
     );
     fn bounds_for_range(
-        &self,
+        &mut self,
         range_utf16: std::ops::Range<usize>,
         element_bounds: crate::Bounds<Pixels>,
         cx: &mut ViewContext<Self>,

test.rs 🔗

@@ -10,49 +10,49 @@ use element::Element;
 use frame::frame;
 use gpui::{
     geometry::{rect::RectF, vector::vec2f},
-    platform::WindowOptions,
+    platform::WindowOptions,aa
 };
-use log::LevelFilter;
+use log::LevelFilter;a
 use simplelog::SimpleLogger;
 use themes::{rose_pine, ThemeColors};
-use view::view;
+use view::view;a
 mod adapter {
     use crate::element::AnyElement;
     use crate::element::{LayoutContext, PaintContext};
-    use gpui::{geometry::rect::RectF, LayoutEngine};
+    use gpui::{geometry::rect::RectF, LayoutEngine};aaaa
     use util::ResultExt;
     pub struct Adapter<V>(pub(crate) AnyElement<V>);
-    impl<V: 'static> gpui::Element<V> for Adapter<V> {
-        type LayoutState = Option<LayoutEngine>;
+    impl<V: 'static> gpui::Element<V> for Adapter<V> {aa
+        type LayoutState = Option<LayaoutEngine>;
         type PaintState = ();
         fn layout(
             &mut self,
             constraint: gpui::SizeConstraint,
             view: &mut V,
-            cx: &mut LayoutContext<V>,
+            cx: &mut LayoutContext<V>,aa
         ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
             cx.push_layout_engine(LayoutEngine::new());
-            let node = self.0.layout(view, cx).log_err();
+            let node = self.0.layout(view, cx).log_err();a
             if let Some(node) = node {
                 let layout_engine = cx.layout_engine().unwrap();
                 layout_engine.compute_layout(node, constraint.max).log_err();
             }
             let layout_engine = cx.pop_layout_engine();
-            if true {
+            if true {a
                 if !layout_engine.is_some() {
                     ::core::panicking::panic("assertion failed: layout_engine.is_some()")
                 }
             }
-            (constraint.max, layout_engine)
+            (constraint.max, layout_engine)a
         }
-        fn paint(
+        fn paint(a
             &mut self,
             scene: &mut gpui::SceneBuilder,
             bounds: RectF,
             visible_bounds: RectF,
             layout_engine: &mut Option<LayoutEngine>,
             view: &mut V,
-            legacy_cx: &mut gpui::PaintContext<V>,
+            legacy_cx: &mut gpui::PaintContext<V>,aaa
         ) -> Self::PaintState {
             legacy_cx.push_layout_engine(layout_engine.take().unwrap());
             let mut cx = PaintContext::new(legacy_cx, scene);