From 96538354b30ea3f809d813fbcf83c8c664a972dc Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 20 May 2021 12:22:33 +0200 Subject: [PATCH] Express rightmost_point in terms of chars as opposed to bytes --- zed/src/editor/buffer/mod.rs | 91 +++++--------------------- zed/src/editor/buffer/rope.rs | 45 ++++++++----- zed/src/editor/display_map/fold_map.rs | 19 ++++-- 3 files changed, 57 insertions(+), 98 deletions(-) diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index a86182fbae89b1dfb90ad202a14ae81d0ce54bd5..ab91ef83894a691c0ad4d588d0c42312d96204da 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -616,14 +616,6 @@ impl Buffer { (row_end_offset - row_start_offset) as u32 } - pub fn rightmost_point(&self) -> Point { - self.visible_text.summary().rightmost_point - } - - pub fn rightmost_point_in_range(&self, range: Range) -> Point { - self.text_summary_for_range(range).rightmost_point - } - pub fn max_point(&self) -> Point { self.visible_text.max_point() } @@ -2360,7 +2352,6 @@ mod tests { use std::{ cell::RefCell, cmp::Ordering, - collections::BTreeMap, fs, rc::Rc, sync::atomic::{self, AtomicUsize}, @@ -2468,33 +2459,11 @@ mod tests { reference_string = buffer.text(); } - { - let line_lengths = line_lengths_in_range(&buffer, 0..buffer.len()); - - for (len, rows) in &line_lengths { - for row in rows { - assert_eq!(buffer.line_len(*row), *len); - } - } - - let (longest_column, longest_rows) = - line_lengths.iter().next_back().unwrap(); - let rightmost_point = buffer.rightmost_point(); - assert_eq!(rightmost_point.column, *longest_column); - assert!(longest_rows.contains(&rightmost_point.row)); - } - - for _ in 0..5 { - let range = buffer.random_byte_range(0, rng); - let line_lengths = line_lengths_in_range(&buffer, range.clone()); - let (longest_column, longest_rows) = - line_lengths.iter().next_back().unwrap(); - let range_sum = buffer.text_summary_for_range(range.clone()); - assert_eq!(range_sum.rightmost_point.column, *longest_column); - assert!(longest_rows.contains(&range_sum.rightmost_point.row)); - let range_text = &buffer.text()[range]; - assert_eq!(range_sum.bytes, range_text.len()); - } + let range = buffer.random_byte_range(0, rng); + assert_eq!( + buffer.text_summary_for_range(range.clone()), + TextSummary::from(&reference_string[range]) + ); if rng.gen_bool(0.3) { buffer_versions.push(buffer.clone()); @@ -2545,25 +2514,6 @@ mod tests { }); } - #[gpui::test] - fn test_rightmost_point(ctx: &mut gpui::MutableAppContext) { - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); - assert_eq!(buffer.rightmost_point().row, 0); - buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap(); - assert_eq!(buffer.rightmost_point().row, 0); - buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); - assert_eq!(buffer.rightmost_point().row, 2); - buffer.edit(vec![18..18], "\npqrs", None).unwrap(); - assert_eq!(buffer.rightmost_point().row, 2); - buffer.edit(vec![10..12], "", None).unwrap(); - assert_eq!(buffer.rightmost_point().row, 0); - buffer.edit(vec![24..24], "tuv", None).unwrap(); - assert_eq!(buffer.rightmost_point().row, 4); - buffer - }); - } - #[gpui::test] fn test_text_summary_for_range(ctx: &mut gpui::MutableAppContext) { ctx.add_model(|ctx| { @@ -2573,7 +2523,8 @@ mod tests { TextSummary { bytes: 2, lines: Point::new(1, 0), - first_line_len: 1, + first_line_chars: 1, + last_line_chars: 0, rightmost_point: Point::new(0, 1), } ); @@ -2582,7 +2533,8 @@ mod tests { TextSummary { bytes: 11, lines: Point::new(3, 0), - first_line_len: 1, + first_line_chars: 1, + last_line_chars: 0, rightmost_point: Point::new(2, 4), } ); @@ -2591,7 +2543,8 @@ mod tests { TextSummary { bytes: 20, lines: Point::new(4, 1), - first_line_len: 2, + first_line_chars: 2, + last_line_chars: 1, rightmost_point: Point::new(3, 6), } ); @@ -2600,7 +2553,8 @@ mod tests { TextSummary { bytes: 22, lines: Point::new(4, 3), - first_line_len: 2, + first_line_chars: 2, + last_line_chars: 3, rightmost_point: Point::new(3, 6), } ); @@ -2609,7 +2563,8 @@ mod tests { TextSummary { bytes: 15, lines: Point::new(2, 3), - first_line_len: 4, + first_line_chars: 4, + last_line_chars: 3, rightmost_point: Point::new(1, 6), } ); @@ -3388,20 +3343,4 @@ mod tests { } } } - - fn line_lengths_in_range(buffer: &Buffer, range: Range) -> BTreeMap> { - let mut lengths = BTreeMap::new(); - for (row, line) in buffer.text()[range.start..range.end].lines().enumerate() { - lengths - .entry(line.len() as u32) - .or_insert(HashSet::default()) - .insert(row as u32); - } - if lengths.is_empty() { - let mut rows = HashSet::default(); - rows.insert(0); - lengths.insert(0, rows); - } - lengths - } } diff --git a/zed/src/editor/buffer/rope.rs b/zed/src/editor/buffer/rope.rs index ddf1a92cbfb4a2b8647cf5b011e142acba60d8a4..d03afaf2a72fe57838a26a038eb1b1cf3da8870a 100644 --- a/zed/src/editor/buffer/rope.rs +++ b/zed/src/editor/buffer/rope.rs @@ -390,32 +390,41 @@ impl sum_tree::Item for Chunk { pub struct TextSummary { pub bytes: usize, pub lines: Point, - pub first_line_len: u32, + pub first_line_chars: u32, + pub last_line_chars: u32, pub rightmost_point: Point, } impl<'a> From<&'a str> for TextSummary { fn from(text: &'a str) -> Self { let mut lines = Point::new(0, 0); - let mut first_line_len = 0; + let mut first_line_chars = 0; + let mut last_line_chars = 0; let mut rightmost_point = Point::new(0, 0); - for (i, line) in text.split('\n').enumerate() { - if i > 0 { + for c in text.chars() { + if c == '\n' { lines.row += 1; + lines.column = 0; + last_line_chars = 0; + } else { + lines.column += c.len_utf8() as u32; + last_line_chars += 1; } - lines.column = line.len() as u32; - if i == 0 { - first_line_len = lines.column; + + if lines.row == 0 { + first_line_chars = last_line_chars; } - if lines.column > rightmost_point.column { - rightmost_point = lines; + + if last_line_chars > rightmost_point.column { + rightmost_point = Point::new(lines.row, last_line_chars); } } TextSummary { bytes: text.len(), lines, - first_line_len, + first_line_chars, + last_line_chars, rightmost_point, } } @@ -431,16 +440,22 @@ impl sum_tree::Summary for TextSummary { impl<'a> std::ops::AddAssign<&'a Self> for TextSummary { fn add_assign(&mut self, other: &'a Self) { - let joined_line_len = self.lines.column + other.first_line_len; - if joined_line_len > self.rightmost_point.column { - self.rightmost_point = Point::new(self.lines.row, joined_line_len); + let joined_chars = self.last_line_chars + other.first_line_chars; + if joined_chars > self.rightmost_point.column { + self.rightmost_point = Point::new(self.lines.row, joined_chars); } if other.rightmost_point.column > self.rightmost_point.column { - self.rightmost_point = self.lines + &other.rightmost_point; + self.rightmost_point = self.lines + other.rightmost_point; } if self.lines.row == 0 { - self.first_line_len += other.first_line_len; + self.first_line_chars += other.first_line_chars; + } + + if other.lines.row == 0 { + self.last_line_chars += other.first_line_chars; + } else { + self.last_line_chars = other.last_line_chars; } self.bytes += other.bytes; diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 3560fd187918517e2ab8fedb9174b2243cf6a6a9..05b92da04f09a5bd53c08652ee63beaaecc55eb1 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -330,15 +330,17 @@ impl FoldMap { if fold.end > fold.start { let display_text = "…"; - let extent = Point::new(0, display_text.len() as u32); + let chars = display_text.chars().count() as u32; + let lines = Point::new(0, display_text.len() as u32); new_transforms.push( Transform { summary: TransformSummary { display: TextSummary { bytes: display_text.len(), - lines: extent, - first_line_len: extent.column, - rightmost_point: extent, + lines, + first_line_chars: chars, + last_line_chars: chars, + rightmost_point: Point::new(0, chars), }, buffer: buffer.text_summary_for_range(fold.start..fold.end), }, @@ -990,6 +992,7 @@ mod tests { let rightmost_point = map.rightmost_point(app.as_ref()); let mut display_point = DisplayPoint::new(0, 0); let mut display_offset = DisplayOffset(0); + let mut char_column = 0; for c in expected_text.chars() { let buffer_point = map.to_buffer_point(display_point, app.as_ref()); let buffer_offset = buffer_point.to_offset(buffer); @@ -1015,14 +1018,16 @@ mod tests { if c == '\n' { *display_point.row_mut() += 1; *display_point.column_mut() = 0; + char_column = 0; } else { *display_point.column_mut() += c.len_utf8() as u32; + char_column += 1; } display_offset.0 += c.len_utf8(); - if display_point.column() > rightmost_point.column() { + if char_column > rightmost_point.column() { panic!( - "invalid rightmost point {:?}, found point {:?}", - rightmost_point, display_point + "invalid rightmost point {:?}, found point {:?} (char column: {})", + rightmost_point, display_point, char_column ); } }