From e1af35aa154ddc10faf4e9a5aac37ae543b1f6ac Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 31 Jan 2025 15:03:56 +0800 Subject: [PATCH] gpui: Add `closest_index_for_position` method (#23668) Closes #ISSUE Release Notes: - N/A ------------ I just make a little change to improve `index_for_position` to support return closest index for position. I need this method to measure for position cursor in multi-line mode TextInput. https://github.com/longbridge/gpui-component/pull/583 https://github.com/user-attachments/assets/c69d098e-d2cb-4053-b739-6c7dd666e769 Before this change, GPUI have `LineLayout::closest_index_for_x` method for unwrapped line case. https://github.com/zed-industries/zed/blob/d1be419fff415329b38f26aff90488700702c82a/crates/gpui/src/text_system/line_layout.rs#L58-L94 This change is equivalent to making `index_for_position` have a corresponding method to get the closest index like `index_for_x`. --- crates/gpui/src/text_system/line_layout.rs | 38 +++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/text_system/line_layout.rs b/crates/gpui/src/text_system/line_layout.rs index b483949d731dc2938388e9f10328cfb39dbb8217..360042d98e16584648c52f4ca111a306bbbb8151 100644 --- a/crates/gpui/src/text_system/line_layout.rs +++ b/crates/gpui/src/text_system/line_layout.rs @@ -278,10 +278,34 @@ impl WrappedLineLayout { } /// The index corresponding to a given position in this layout for the given line height. + /// + /// See also [`Self::closest_index_for_position`]. pub fn index_for_position( + &self, + position: Point, + line_height: Pixels, + ) -> Result { + self._index_for_position(position, line_height, false) + } + + /// The closest index to a given position in this layout for the given line height. + /// + /// Closest means the character boundary closest to the given position. + /// + /// See also [`LineLayout::closest_index_for_x`]. + pub fn closest_index_for_position( + &self, + position: Point, + line_height: Pixels, + ) -> Result { + self._index_for_position(position, line_height, true) + } + + fn _index_for_position( &self, mut position: Point, line_height: Pixels, + closest: bool, ) -> Result { let wrapped_line_ix = (position.y / line_height) as usize; @@ -321,10 +345,16 @@ impl WrappedLineLayout { } else if position_in_unwrapped_line.x >= wrapped_line_end_x { Err(wrapped_line_end_index) } else { - Ok(self - .unwrapped_layout - .index_for_x(position_in_unwrapped_line.x) - .unwrap()) + if closest { + Ok(self + .unwrapped_layout + .closest_index_for_x(position_in_unwrapped_line.x)) + } else { + Ok(self + .unwrapped_layout + .index_for_x(position_in_unwrapped_line.x) + .unwrap()) + } } }