diff --git a/crates/gpui_elements/src/editable_text/element.rs b/crates/gpui_elements/src/editable_text/element.rs index 21044ffd63..2f4a28f3a9 100644 --- a/crates/gpui_elements/src/editable_text/element.rs +++ b/crates/gpui_elements/src/editable_text/element.rs @@ -305,7 +305,6 @@ impl Element for EditableTextElement { size.height += line_size.height; size.width = size.width.max(line_size.width).ceil(); - let num_visual_lines = line.wrap_boundaries().len() + 1; let mut line_len = line.len(); if line_len < text_len { // to offset for new-line characters that are @@ -313,14 +312,14 @@ impl Element for EditableTextElement { line_len += 1; } - lines.push(TextLineSegment { + let segment = TextLineSegment { text_range: line_start..line_start + line_len, wrapped_line: Some(Arc::new(line)), pos_y, - num_visual_lines, - }); + }; line_start += line_len; - pos_y += num_visual_lines; + pos_y += segment.row_count(); + lines.push(segment); } let layout_data = TextInputLayoutData { @@ -435,7 +434,7 @@ impl Element for EditableTextElement { for segment in &state.layout_data.lines { let line_distance_from_top = segment.pos_y * line_height; let line_y = line_distance_from_top + scroll_offset.y; - let line_bottom = line_y + line_height * segment.num_visual_lines as f32; + let line_bottom = line_y + line_height * segment.row_count() as f32; let line_visible = line_bottom >= Pixels::ZERO && line_y <= inner_bounds.size.height; if !line_visible { continue; @@ -670,7 +669,7 @@ fn build_quad_over_text( let end_pos = wrapped .position_for_index(subrange_end, line_height) .unwrap_or_else(|| { - let last_line_y = line_height * (segment.num_visual_lines - 1) as f32; + let last_line_y = line_height * (segment.row_count() - 1) as f32; point(wrapped.width(), last_line_y) }); diff --git a/crates/gpui_elements/src/editable_text/state.rs b/crates/gpui_elements/src/editable_text/state.rs index 4ed64b0a86..1f6a332000 100644 --- a/crates/gpui_elements/src/editable_text/state.rs +++ b/crates/gpui_elements/src/editable_text/state.rs @@ -49,6 +49,7 @@ pub(super) struct TextInputLayoutData { /// Cached so IME `bounds_for_range` / `character_index_for_point` can evaluate without re-shaping. pub lines: Vec, } +/// A segment of text that is a single logical/document line but can take up multiple rows due to wrapping. pub(super) struct TextLineSegment { /// The utf8 byte range in the content string that this line covers. pub text_range: Range, @@ -58,13 +59,11 @@ pub(super) struct TextLineSegment { /// The y-coordinate of this segment which can be multiplied by the line_height /// to get its pixel location relative to the bounds of the text area. pub pos_y: usize, - /// The number of segments up to and including this segment in the literal line that has been wrapped. - /// There may be other segments after this one with a larger counter. - /// TODO: Deprecated in favor of `wrap_boundaries` - pub num_visual_lines: usize, } impl TextLineSegment { - pub fn wrap_boundaries(&self) -> usize { + /// The number of visual lines this segment encapsulates, + /// since it can occupy multiple rows due to wrapping. + pub fn row_count(&self) -> usize { let count = self .wrapped_line .as_ref() @@ -134,7 +133,7 @@ impl EditableTextState { impl EditableTextState { /// Returns the utf-8 character position of the start of the line that contains the provided pixel-point. - pub fn index_for_pixel_point(&self, point: Point, line_height: Pixels) -> usize { + fn index_for_pixel_point(&self, point: Point, line_height: Pixels) -> usize { let storage_len_utf8 = self.storage.content_utf8().len(); if storage_len_utf8 == 0 { return 0; @@ -142,7 +141,7 @@ impl EditableTextState { for line in &self.layout_data.lines { let y_offset = line.pos_y * line_height; - let line_height_total = line_height * line.num_visual_lines as f32; + let line_height_total = line_height * line.row_count() as f32; if point.y >= y_offset && point.y < y_offset + line_height_total { if line.text_range.is_empty() { @@ -166,9 +165,7 @@ impl EditableTextState { storage_len_utf8 } -} -impl EditableTextState { fn ime_resolve_range(&self, range_utf16: Option>) -> Range { // Use a series of fallbacks to pick the range to operate on. // Fallback order: IME provided range, active IME marked range, selection @@ -344,7 +341,7 @@ impl EditableTextState { return (segment_index, Point::default()); } - segment_index += segment.wrap_boundaries(); + segment_index += segment.row_count(); } (segment_index.saturating_sub(1), Point::default()) @@ -361,7 +358,7 @@ impl EditableTextState { let mut current_visual_line = 0; for segment in &self.layout_data.lines { - let wrap_boundary_len = segment.wrap_boundaries(); + let wrap_boundary_len = segment.row_count(); if line_index < current_visual_line + wrap_boundary_len { let visual_line_within_layout = line_index - current_visual_line; @@ -514,7 +511,7 @@ impl EntityInputHandler for EditableTextState { let end_pos = wrapped .position_for_index(local_end, line_height) .unwrap_or_else(|| { - let last_line_y = line_height * (line.num_visual_lines - 1) as f32; + let last_line_y = line_height * (line.row_count() - 1) as f32; point(wrapped.width(), last_line_y) });