From d273fa6dd0bf063765318582c61d4120a0b211d6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 8 Nov 2023 13:52:42 -0800 Subject: [PATCH 1/7] Fix DisplaySnapshot::x_for_point always returning 0 Co-authored-by: Marshall --- crates/editor2/src/display_map.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/editor2/src/display_map.rs b/crates/editor2/src/display_map.rs index 808f0d340a4807b64732c85ef6eb258def3c7f12..f808ffa7026f496faa0429b6fa7f8af1468e2bcc 100644 --- a/crates/editor2/src/display_map.rs +++ b/crates/editor2/src/display_map.rs @@ -572,7 +572,6 @@ impl DisplaySnapshot { ) -> Line { let mut runs = Vec::new(); let mut line = String::new(); - let mut ended_in_newline = false; let range = display_row..display_row + 1; for chunk in self.highlighted_chunks(range, false, &editor_style) { @@ -588,17 +587,18 @@ impl DisplaySnapshot { } else { Cow::Borrowed(&editor_style.text) }; - ended_in_newline = chunk.chunk.ends_with("\n"); runs.push(text_style.to_run(chunk.chunk.len())) } - // our pixel positioning logic assumes each line ends in \n, - // this is almost always true except for the last line which - // may have no trailing newline. - if !ended_in_newline && display_row == self.max_point().row() { - line.push_str("\n"); - runs.push(editor_style.text.to_run("\n".len())); + if line.ends_with('\n') { + line.pop(); + if let Some(last_run) = runs.last_mut() { + last_run.len -= 1; + if last_run.len == 0 { + runs.pop(); + } + } } let font_size = editor_style.text.font_size.to_pixels(*rem_size); From 1a37d9edc654b91ff36a59ed9a530eb0f55f8549 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 8 Nov 2023 15:48:55 -0800 Subject: [PATCH 2/7] Register text input handlers via new element hook Provide element bounds to the input handler's `bounds_for_rect` method. Co-authored-by: Marshall --- crates/editor2/src/editor.rs | 3 +- crates/editor2/src/element.rs | 21 ++-- crates/gpui2/src/element.rs | 25 +++- crates/gpui2/src/platform.rs | 2 +- crates/gpui2/src/platform/mac/window.rs | 6 +- crates/gpui2/src/window.rs | 31 ++--- crates/gpui2/src/window_input_handler.rs | 138 ++++++++++++++++++----- 7 files changed, 160 insertions(+), 66 deletions(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 049d304750fa9d8d3ca3c8d99f89158e567aa1ef..9542eaddc631f7132142e87bb7e1a8e704bdfc8e 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -9752,8 +9752,9 @@ impl InputHandler for Editor { fn bounds_for_range( &self, range_utf16: Range, + element_bounds: gpui::Bounds, cx: &mut ViewContext, - ) -> Option> { + ) -> Option> { // todo!() // See how we did it before: `rect_for_range` None diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 04b8494a888bcc8333de24effa8edf675ba02866..ab9aa2ccf3adbf1b9fa244d65d841c184d77c4cc 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -17,10 +17,11 @@ use collections::{BTreeMap, HashMap}; use gpui::{ black, hsla, point, px, relative, size, transparent_black, Action, AnyElement, BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, DispatchContext, DispatchPhase, - Edges, Element, ElementId, Entity, GlobalElementId, Hsla, KeyDownEvent, KeyListener, KeyMatch, - Line, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, - ScrollWheelEvent, ShapedGlyph, Size, Style, TextRun, TextStyle, TextSystem, ViewContext, - WindowContext, + Edges, Element, ElementId, Entity, FocusHandle, GlobalElementId, Hsla, InputHandler, + InputHandlerView, KeyDownEvent, KeyListener, KeyMatch, Line, LineLayout, Modifiers, + MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, ScrollWheelEvent, + ShapedGlyph, Size, Style, TextRun, TextStyle, TextSystem, ViewContext, WindowContext, + WrappedLineLayout, }; use itertools::Itertools; use language::language_settings::ShowWhitespaceSetting; @@ -2502,10 +2503,6 @@ impl Element for EditorElement { size: layout.text_size, }; - if editor.focus_handle.is_focused(cx) { - cx.handle_text_input(); - } - cx.with_content_mask(ContentMask { bounds }, |cx| { self.paint_mouse_listeners( bounds, @@ -2521,6 +2518,14 @@ impl Element for EditorElement { self.paint_text(text_bounds, &layout, editor, cx); }); } + + fn handle_text_input<'a>( + &self, + editor: &'a mut Editor, + cx: &mut ViewContext, + ) -> Option<(Box, &'a FocusHandle)> { + Some((Box::new(cx.view()), &editor.focus_handle)) + } } // impl EditorElement { diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 8fdc17de07296d95def915f3a605f3988913eb2a..a6067eb68d68168e73991941678b2280b8115546 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -1,4 +1,7 @@ -use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, ViewContext}; +use crate::{ + BorrowWindow, Bounds, ElementId, FocusHandle, InputHandlerView, LayoutId, Pixels, ViewContext, + WindowInputHandler, +}; use derive_more::{Deref, DerefMut}; pub(crate) use smallvec::SmallVec; use std::{any::Any, mem}; @@ -31,6 +34,14 @@ pub trait Element { element_state: &mut Self::ElementState, cx: &mut ViewContext, ); + + fn handle_text_input<'a>( + &self, + _view_state: &'a mut V, + _cx: &mut ViewContext, + ) -> Option<(Box, &'a FocusHandle)> { + None + } } #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)] @@ -154,6 +165,18 @@ where mut frame_state, } => { let bounds = cx.layout_bounds(layout_id); + if let Some((input_handler, focus_handle)) = + self.element.handle_text_input(view_state, cx) + { + if focus_handle.is_focused(cx) { + cx.window.requested_input_handler = Some(Box::new(WindowInputHandler { + cx: cx.app.this.clone(), + window: cx.window_handle(), + input_handler, + element_bounds: bounds, + })); + } + } if let Some(id) = self.element.id() { cx.with_element_state(id, |element_state, cx| { let mut element_state = element_state.unwrap(); diff --git a/crates/gpui2/src/platform.rs b/crates/gpui2/src/platform.rs index a4be21ddf36ff93c3c3b3fd9434cd3168e803bb6..5ebb12b64d174103dc078ee3aa433761ca5033f7 100644 --- a/crates/gpui2/src/platform.rs +++ b/crates/gpui2/src/platform.rs @@ -305,7 +305,7 @@ pub trait PlatformInputHandler { new_selected_range: Option>, ); fn unmark_text(&mut self); - fn bounds_for_range(&self, range_utf16: Range) -> Option>; + fn bounds_for_range(&self, range_utf16: Range) -> Option>; } #[derive(Debug)] diff --git a/crates/gpui2/src/platform/mac/window.rs b/crates/gpui2/src/platform/mac/window.rs index affeab57c7523b120033d373cfcba48c1f3691a1..bd45178e97400de28729da3cce532b034d23fc87 100644 --- a/crates/gpui2/src/platform/mac/window.rs +++ b/crates/gpui2/src/platform/mac/window.rs @@ -1484,10 +1484,10 @@ extern "C" fn first_rect_for_character_range( |bounds| { NSRect::new( NSPoint::new( - frame.origin.x + bounds.origin.x as f64, - frame.origin.y + frame.size.height - bounds.origin.y as f64, + frame.origin.x + bounds.origin.x.0 as f64, + frame.origin.y + frame.size.height - bounds.origin.y.0 as f64, ), - NSSize::new(bounds.size.width as f64, bounds.size.height as f64), + NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), ) }, ) diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index fbaeae322b7180bd52f808ad9801998138bb895d..b1e756fe6f72dc86d772c616c3e723cbbd2c5572 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -2,14 +2,14 @@ use crate::{ px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, - GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, InputHandler, IsZero, KeyListener, - KeyMatch, KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, - PlatformDisplay, 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, + GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, + KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, + MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, + 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, }; use anyhow::{anyhow, Result}; use collections::HashMap; @@ -212,7 +212,7 @@ pub struct Window { default_prevented: bool, mouse_position: Point, requested_cursor_style: Option, - requested_input_handler: Option>, + pub(crate) requested_input_handler: Option>, scale_factor: f32, bounds: WindowBounds, bounds_observers: SubscriberSet<(), AnyObserver>, @@ -2168,19 +2168,6 @@ impl<'a, V: 'static> ViewContext<'a, V> { } } -impl ViewContext<'_, V> -where - V: InputHandler + 'static, -{ - pub fn handle_text_input(&mut self) { - self.window.requested_input_handler = Some(Box::new(WindowInputHandler { - cx: self.app.this.clone(), - window: self.window_handle(), - handler: self.view().downgrade(), - })); - } -} - impl ViewContext<'_, V> where V: EventEmitter, diff --git a/crates/gpui2/src/window_input_handler.rs b/crates/gpui2/src/window_input_handler.rs index caae5838ce46171a1584b272d7e916d100e13881..3ce9f01ddaabcc8c7c1e1de952ac88062937e012 100644 --- a/crates/gpui2/src/window_input_handler.rs +++ b/crates/gpui2/src/window_input_handler.rs @@ -1,65 +1,142 @@ -use crate::{AnyWindowHandle, AppCell, Context, PlatformInputHandler, ViewContext, WeakView}; +use crate::{ + AnyWindowHandle, AppCell, Bounds, Context, Pixels, PlatformInputHandler, View, ViewContext, + WindowContext, +}; use std::{ops::Range, rc::Weak}; -pub struct WindowInputHandler -where - V: InputHandler, -{ +pub struct WindowInputHandler { pub cx: Weak, + pub input_handler: Box, pub window: AnyWindowHandle, - pub handler: WeakView, + pub element_bounds: Bounds, } -impl PlatformInputHandler for WindowInputHandler { - fn selected_text_range(&self) -> Option> { - self.update(|view, cx| view.selected_text_range(cx)) - .flatten() +pub trait InputHandlerView { + fn text_for_range(&self, range: Range, cx: &mut WindowContext) -> Option; + fn selected_text_range(&self, cx: &mut WindowContext) -> Option>; + fn marked_text_range(&self, cx: &mut WindowContext) -> Option>; + fn unmark_text(&self, cx: &mut WindowContext); + fn replace_text_in_range( + &self, + range: Option>, + text: &str, + cx: &mut WindowContext, + ); + fn replace_and_mark_text_in_range( + &self, + range: Option>, + new_text: &str, + new_selected_range: Option>, + cx: &mut WindowContext, + ); + fn bounds_for_range( + &self, + range_utf16: std::ops::Range, + element_bounds: crate::Bounds, + cx: &mut WindowContext, + ) -> Option>; +} + +impl InputHandlerView for View { + fn text_for_range(&self, range: Range, cx: &mut WindowContext) -> Option { + self.update(cx, |this, cx| this.text_for_range(range, cx)) } - fn marked_text_range(&self) -> Option> { - self.update(|view, cx| view.marked_text_range(cx)).flatten() + fn selected_text_range(&self, cx: &mut WindowContext) -> Option> { + self.update(cx, |this, cx| this.selected_text_range(cx)) } - fn text_for_range(&self, range_utf16: std::ops::Range) -> Option { - self.update(|view, cx| view.text_for_range(range_utf16, cx)) - .flatten() + fn marked_text_range(&self, cx: &mut WindowContext) -> Option> { + self.update(cx, |this, cx| this.marked_text_range(cx)) + } + + fn unmark_text(&self, cx: &mut WindowContext) { + self.update(cx, |this, cx| this.unmark_text(cx)) } fn replace_text_in_range( - &mut self, - replacement_range: Option>, + &self, + range: Option>, text: &str, + cx: &mut WindowContext, + ) { + self.update(cx, |this, cx| this.replace_text_in_range(range, text, cx)) + } + + fn replace_and_mark_text_in_range( + &self, + range: Option>, + new_text: &str, + new_selected_range: Option>, + cx: &mut WindowContext, ) { - self.update(|view, cx| view.replace_text_in_range(replacement_range, text, cx)); + self.update(cx, |this, cx| { + this.replace_and_mark_text_in_range(range, new_text, new_selected_range, cx) + }) + } + + fn bounds_for_range( + &self, + range_utf16: std::ops::Range, + element_bounds: crate::Bounds, + cx: &mut WindowContext, + ) -> Option> { + self.update(cx, |this, cx| { + this.bounds_for_range(range_utf16, element_bounds, cx) + }) + } +} + +impl PlatformInputHandler for WindowInputHandler { + fn selected_text_range(&self) -> Option> { + self.update(|handler, cx| handler.selected_text_range(cx)) + .flatten() + } + + fn marked_text_range(&self) -> Option> { + self.update(|handler, cx| handler.marked_text_range(cx)) + .flatten() + } + + fn text_for_range(&self, range_utf16: Range) -> Option { + self.update(|handler, cx| handler.text_for_range(range_utf16, cx)) + .flatten() + } + + fn replace_text_in_range(&mut self, replacement_range: Option>, text: &str) { + self.update(|handler, cx| handler.replace_text_in_range(replacement_range, text, cx)); } fn replace_and_mark_text_in_range( &mut self, - range_utf16: Option>, + range_utf16: Option>, new_text: &str, - new_selected_range: Option>, + new_selected_range: Option>, ) { - self.update(|view, cx| { - view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx) + self.update(|handler, cx| { + handler.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx) }); } fn unmark_text(&mut self) { - self.update(|view, cx| view.unmark_text(cx)); + self.update(|handler, cx| handler.unmark_text(cx)); } - fn bounds_for_range(&self, range_utf16: std::ops::Range) -> Option> { - self.update(|view, cx| view.bounds_for_range(range_utf16, cx)) + fn bounds_for_range(&self, range_utf16: Range) -> Option> { + self.update(|handler, cx| handler.bounds_for_range(range_utf16, self.element_bounds, cx)) .flatten() } } -impl WindowInputHandler { - fn update(&self, f: impl FnOnce(&mut V, &mut ViewContext) -> T) -> Option { +impl WindowInputHandler { + fn update( + &self, + f: impl FnOnce(&dyn InputHandlerView, &mut WindowContext) -> R, + ) -> Option { let cx = self.cx.upgrade()?; let mut cx = cx.borrow_mut(); - cx.update_window(self.window, |_, cx| self.handler.update(cx, f).ok()) - .ok()? + cx.update_window(self.window, |_, cx| f(&*self.input_handler, cx)) + .ok() } } @@ -84,6 +161,7 @@ pub trait InputHandler: Sized { fn bounds_for_range( &self, range_utf16: std::ops::Range, + element_bounds: crate::Bounds, cx: &mut ViewContext, - ) -> Option>; + ) -> Option>; } From 7a8f2192516a28e4ffc0d89449270d09d3e404d8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 8 Nov 2023 16:02:10 -0800 Subject: [PATCH 3/7] Account for element's bounds in Editor::bounds_for_range Co-authored-by: Marshall --- 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(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 9542eaddc631f7132142e87bb7e1a8e704bdfc8e..9d7c0b7fa3130f99b6337bfd14fa30e209db5e34 100644 --- a/crates/editor2/src/editor.rs +++ b/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, element_bounds: gpui::Bounds, cx: &mut ViewContext, ) -> Option> { - // 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), + )) } } diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index b1e756fe6f72dc86d772c616c3e723cbbd2c5572..9a1e8916c44267ecadfebbe64eed44f91da75a41 100644 --- a/crates/gpui2/src/window.rs +++ b/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; diff --git a/crates/gpui2/src/window_input_handler.rs b/crates/gpui2/src/window_input_handler.rs index 3ce9f01ddaabcc8c7c1e1de952ac88062937e012..d09a842a6bea35f772f23e22da11461db59e7b8f 100644 --- a/crates/gpui2/src/window_input_handler.rs +++ b/crates/gpui2/src/window_input_handler.rs @@ -159,7 +159,7 @@ pub trait InputHandler: Sized { cx: &mut ViewContext, ); fn bounds_for_range( - &self, + &mut self, range_utf16: std::ops::Range, element_bounds: crate::Bounds, cx: &mut ViewContext, diff --git a/test.rs b/test.rs index 4a7b9faa8ff9b56cc0779b79f5152b3b1694c2c7..36996263b0f053922598402b86f77382b687ea57 100644 --- a/test.rs +++ b/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(pub(crate) AnyElement); - impl gpui::Element for Adapter { - type LayoutState = Option; + impl gpui::Element for Adapter {aa + type LayoutState = Option; type PaintState = (); fn layout( &mut self, constraint: gpui::SizeConstraint, view: &mut V, - cx: &mut LayoutContext, + cx: &mut LayoutContext,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, view: &mut V, - legacy_cx: &mut gpui::PaintContext, + legacy_cx: &mut gpui::PaintContext,aaa ) -> Self::PaintState { legacy_cx.push_layout_engine(layout_engine.take().unwrap()); let mut cx = PaintContext::new(legacy_cx, scene); From b77fab0fae3b5f799f1cfef52da9590a6cdd3031 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 8 Nov 2023 16:24:11 -0800 Subject: [PATCH 4/7] :art: --- crates/gpui2/src/window_input_handler.rs | 52 ++++++++++++------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/crates/gpui2/src/window_input_handler.rs b/crates/gpui2/src/window_input_handler.rs index d09a842a6bea35f772f23e22da11461db59e7b8f..f3ff33f3c03457dcca78b60a6c586787fddf9d74 100644 --- a/crates/gpui2/src/window_input_handler.rs +++ b/crates/gpui2/src/window_input_handler.rs @@ -37,6 +37,32 @@ pub trait InputHandlerView { ) -> Option>; } +pub trait InputHandler: Sized { + fn text_for_range(&self, range: Range, cx: &mut ViewContext) -> Option; + fn selected_text_range(&self, cx: &mut ViewContext) -> Option>; + fn marked_text_range(&self, cx: &mut ViewContext) -> Option>; + fn unmark_text(&mut self, cx: &mut ViewContext); + fn replace_text_in_range( + &mut self, + range: Option>, + text: &str, + cx: &mut ViewContext, + ); + fn replace_and_mark_text_in_range( + &mut self, + range: Option>, + new_text: &str, + new_selected_range: Option>, + cx: &mut ViewContext, + ); + fn bounds_for_range( + &mut self, + range_utf16: std::ops::Range, + element_bounds: crate::Bounds, + cx: &mut ViewContext, + ) -> Option>; +} + impl InputHandlerView for View { fn text_for_range(&self, range: Range, cx: &mut WindowContext) -> Option { self.update(cx, |this, cx| this.text_for_range(range, cx)) @@ -139,29 +165,3 @@ impl WindowInputHandler { .ok() } } - -pub trait InputHandler: Sized { - fn text_for_range(&self, range: Range, cx: &mut ViewContext) -> Option; - fn selected_text_range(&self, cx: &mut ViewContext) -> Option>; - fn marked_text_range(&self, cx: &mut ViewContext) -> Option>; - fn unmark_text(&mut self, cx: &mut ViewContext); - fn replace_text_in_range( - &mut self, - range: Option>, - text: &str, - cx: &mut ViewContext, - ); - fn replace_and_mark_text_in_range( - &mut self, - range: Option>, - new_text: &str, - new_selected_range: Option>, - cx: &mut ViewContext, - ); - fn bounds_for_range( - &mut self, - range_utf16: std::ops::Range, - element_bounds: crate::Bounds, - cx: &mut ViewContext, - ) -> Option>; -} From 9a41c587797327550ef986c61d61ea79f7b34c01 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 8 Nov 2023 19:25:12 -0500 Subject: [PATCH 5/7] Hard-code the gutter margin temporarily --- crates/editor2/src/editor.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 9d7c0b7fa3130f99b6337bfd14fa30e209db5e34..618157fb96379abffa3c9dd8ad1c3b5a5cb5b44d 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -9771,11 +9771,14 @@ impl InputHandler for Editor { let scroll_position = snapshot.scroll_position(); let scroll_left = scroll_position.x * em_width; + // todo!() How do we actually get the gutter margin here? + let gutter_margin = px(84.46154); + 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 start_x = snapshot.x_for_point(start, &text_layout_details) - scroll_left + gutter_margin; let end_x = snapshot.x_for_point(end, &text_layout_details) - scroll_left; Some(Bounds::from_corners( From 86865431b98b0cc62aef5b35185228b5953be0e1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 8 Nov 2023 17:01:50 -0800 Subject: [PATCH 6/7] Assign gutter widht on editor view when painting element --- crates/editor2/src/editor.rs | 8 ++++---- crates/editor2/src/element.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 618157fb96379abffa3c9dd8ad1c3b5a5cb5b44d..8cc58a87bff325a7544de8236cd0d7f3464a9680 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -674,6 +674,7 @@ pub struct Editor { next_inlay_id: usize, _subscriptions: Vec, pixel_position_of_newest_cursor: Option>, + gutter_width: Pixels, style: Option, } @@ -1984,6 +1985,7 @@ impl Editor { inlay_hint_cache: InlayHintCache::new(inlay_hint_settings), gutter_hovered: false, pixel_position_of_newest_cursor: None, + gutter_width: Default::default(), style: None, _subscriptions: vec![ cx.observe(&buffer, Self::on_buffer_changed), @@ -9771,14 +9773,12 @@ impl InputHandler for Editor { let scroll_position = snapshot.scroll_position(); let scroll_left = scroll_position.x * em_width; - // todo!() How do we actually get the gutter margin here? - let gutter_margin = px(84.46154); - 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 + gutter_margin; + let start_x = + snapshot.x_for_point(start, &text_layout_details) - scroll_left + self.gutter_width; let end_x = snapshot.x_for_point(end, &text_layout_details) - scroll_left; Some(Bounds::from_corners( diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index ab9aa2ccf3adbf1b9fa244d65d841c184d77c4cc..0e53aa449d4d5bcc13626cf014f92511776f7481 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -1468,6 +1468,7 @@ impl EditorElement { gutter_margin = Pixels::ZERO; }; + editor.gutter_width = gutter_width; let text_width = bounds.size.width - gutter_width; let overscroll = size(em_width, px(0.)); let snapshot = { From 277fbda35696802d4fb4ab6b2ce28009a1bec795 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 8 Nov 2023 17:27:32 -0800 Subject: [PATCH 7/7] Fix vertical position in first_rect_for_character_range --- crates/editor2/src/editor.rs | 28 +++++++++++-------------- crates/gpui2/src/platform/mac/window.rs | 4 +++- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 8cc58a87bff325a7544de8236cd0d7f3464a9680..2b64aa2e8b4c8c96adecfb7ec42a467790d6d227 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -39,11 +39,11 @@ use futures::FutureExt; use fuzzy::{StringMatch, StringMatchCandidate}; use git::diff_hunk_to_display; use gpui::{ - 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, + action, actions, div, point, px, relative, size, 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; use hover_popover::{hide_hover, HoverState}; @@ -9774,17 +9774,13 @@ impl InputHandler for Editor { 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 + self.gutter_width; - 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), - )) + let x = snapshot.x_for_point(start, &text_layout_details) - scroll_left + self.gutter_width; + let y = line_height * (start.row() as f32 - scroll_position.y); + + Some(Bounds { + origin: element_bounds.origin + point(x, y), + size: size(em_width, line_height), + }) } } diff --git a/crates/gpui2/src/platform/mac/window.rs b/crates/gpui2/src/platform/mac/window.rs index bd45178e97400de28729da3cce532b034d23fc87..d07df3d94b352bced85f5dfaa853ff788faf5876 100644 --- a/crates/gpui2/src/platform/mac/window.rs +++ b/crates/gpui2/src/platform/mac/window.rs @@ -1485,7 +1485,9 @@ extern "C" fn first_rect_for_character_range( NSRect::new( NSPoint::new( frame.origin.x + bounds.origin.x.0 as f64, - frame.origin.y + frame.size.height - bounds.origin.y.0 as f64, + frame.origin.y + frame.size.height + - bounds.origin.y.0 as f64 + - bounds.size.height.0 as f64, ), NSSize::new(bounds.size.width.0 as f64, bounds.size.height.0 as f64), )