Detailed changes
@@ -1097,7 +1097,7 @@ impl DisplaySnapshot {
details: &TextLayoutDetails,
) -> u32 {
let layout_line = self.layout_row(display_row, details);
- layout_line.index_for_x(x) as u32
+ layout_line.closest_index_for_x(x) as u32
}
pub fn grapheme_at(&self, mut point: DisplayPoint) -> Option<SharedString> {
@@ -8668,7 +8668,7 @@ impl LineWithInvisibles {
let fragment_end_x = fragment_start_x + shaped_line.width;
if x < fragment_end_x {
return Some(
- fragment_start_index + shaped_line.index_for_x(x - fragment_start_x),
+ fragment_start_index + shaped_line.index_for_x(x - fragment_start_x)?,
);
}
fragment_start_x = fragment_end_x;
@@ -372,7 +372,7 @@ impl SelectionsCollection {
let is_empty = positions.start == positions.end;
let line_len = display_map.line_len(row);
let line = display_map.layout_row(row, text_layout_details);
- let start_col = line.index_for_x(positions.start) as u32;
+ let start_col = line.closest_index_for_x(positions.start) as u32;
let (start, end) = if is_empty {
let point = DisplayPoint::new(row, std::cmp::min(start_col, line_len));
@@ -382,7 +382,7 @@ impl SelectionsCollection {
return None;
}
let start = DisplayPoint::new(row, start_col);
- let end_col = line.index_for_x(positions.end) as u32;
+ let end_col = line.closest_index_for_x(positions.end) as u32;
let end = DisplayPoint::new(row, end_col);
(start, end)
};
@@ -178,7 +178,7 @@ impl TextInput {
if position.y > bounds.bottom() {
return self.content.len();
}
- line.index_for_x(position.x - bounds.left())
+ line.closest_index_for_x(position.x - bounds.left())
}
fn select_to(&mut self, offset: usize, cx: &mut Context<Self>) {
@@ -380,7 +380,7 @@ impl EntityInputHandler for TextInput {
let last_layout = self.last_layout.as_ref()?;
assert_eq!(last_layout.text, self.content);
- let utf8_index = last_layout.index_for_x(point.x - line_point.x);
+ let utf8_index = last_layout.index_for_x(point.x - line_point.x)?;
Some(self.offset_to_utf16(utf8_index))
}
}
@@ -54,9 +54,25 @@ pub struct ShapedGlyph {
}
impl LineLayout {
+ /// The index for the character at the given x coordinate
+ pub fn index_for_x(&self, x: Pixels) -> Option<usize> {
+ if x >= self.width {
+ None
+ } else {
+ for run in self.runs.iter().rev() {
+ for glyph in run.glyphs.iter().rev() {
+ if glyph.position.x <= x {
+ return Some(glyph.index);
+ }
+ }
+ }
+ Some(0)
+ }
+ }
+
/// closest_index_for_x returns the character boundary closest to the given x coordinate
/// (e.g. to handle aligning up/down arrow keys)
- pub fn index_for_x(&self, x: Pixels) -> usize {
+ pub fn closest_index_for_x(&self, x: Pixels) -> usize {
let mut prev_index = 0;
let mut prev_x = px(0.);
@@ -262,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<Pixels>,
+ line_height: Pixels,
+ ) -> Result<usize, usize> {
+ 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<Pixels>,
+ line_height: Pixels,
+ ) -> Result<usize, usize> {
+ self._index_for_position(position, line_height, true)
+ }
+
+ fn _index_for_position(
&self,
mut position: Point<Pixels>,
line_height: Pixels,
+ closest: bool,
) -> Result<usize, usize> {
let wrapped_line_ix = (position.y / line_height) as usize;
@@ -305,9 +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))
+ 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())
+ }
}
}
@@ -371,10 +371,12 @@ impl Vim {
loop {
let laid_out_line = map.layout_row(row, &text_layout_details);
- let start =
- DisplayPoint::new(row, laid_out_line.index_for_x(positions.start) as u32);
+ let start = DisplayPoint::new(
+ row,
+ laid_out_line.closest_index_for_x(positions.start) as u32,
+ );
let mut end =
- DisplayPoint::new(row, laid_out_line.index_for_x(positions.end) as u32);
+ DisplayPoint::new(row, laid_out_line.closest_index_for_x(positions.end) as u32);
if end <= start {
if start.column() == map.line_len(start.row()) {
end = start;