diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 049d304750..9542eaddc6 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 04b8494a88..ab9aa2ccf3 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 8fdc17de07..a6067eb68d 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 a4be21ddf3..5ebb12b64d 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 affeab57c7..bd45178e97 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 fbaeae322b..b1e756fe6f 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 caae5838ce..3ce9f01dda 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(|view, cx| view.replace_text_in_range(replacement_range, text, cx)); + 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(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>; }