@@ -14,6 +14,7 @@ use std::{
cmp, io,
iter::{self, FromIterator, Peekable},
ops::{Range, Sub},
+ str,
sync::Arc,
time::{Duration, Instant, SystemTime},
};
@@ -754,9 +755,47 @@ impl MultiBufferSnapshot {
&'a self,
position: T,
) -> impl Iterator<Item = char> + 'a {
- // TODO
- let offset = position.to_offset(self);
- self.as_singleton().unwrap().reversed_chars_at(offset)
+ let mut offset = position.to_offset(self);
+ let mut cursor = self.excerpts.cursor::<usize>();
+ cursor.seek(&offset, Bias::Left, &());
+ let mut excerpt_chunks = cursor.item().map(|excerpt| {
+ let start_after_header = cursor.start() + excerpt.header_height as usize;
+ let mut end_before_footer = cursor.start() + excerpt.text_summary.bytes;
+ if excerpt.has_trailing_newline {
+ end_before_footer -= 1;
+ }
+
+ let start = excerpt.range.start.to_offset(&excerpt.buffer);
+ let end =
+ start + (cmp::min(offset, end_before_footer).saturating_sub(start_after_header));
+ excerpt.buffer.reversed_chunks_in_range(start..end)
+ });
+ iter::from_fn(move || {
+ if offset == *cursor.start() {
+ cursor.prev(&());
+ let excerpt = cursor.item()?;
+ excerpt_chunks = Some(
+ excerpt
+ .buffer
+ .reversed_chunks_in_range(excerpt.range.clone()),
+ );
+ }
+
+ let excerpt = cursor.item().unwrap();
+ if offset <= cursor.start() + excerpt.header_height as usize {
+ let header_height = offset - cursor.start();
+ offset -= header_height;
+ Some(unsafe { str::from_utf8_unchecked(&NEWLINES[..header_height]) })
+ } else if offset == cursor.end(&()) && excerpt.has_trailing_newline {
+ offset -= 1;
+ Some("\n")
+ } else {
+ let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap();
+ offset -= chunk.len();
+ Some(chunk)
+ }
+ })
+ .flat_map(|c| c.chars().rev())
}
pub fn chars_at<'a, T: ToOffset>(&'a self, position: T) -> impl Iterator<Item = char> + 'a {
@@ -1593,7 +1632,7 @@ impl<'a> Iterator for MultiBufferChunks<'a> {
if self.header_height > 0 {
let chunk = Chunk {
text: unsafe {
- std::str::from_utf8_unchecked(&NEWLINES[..self.header_height as usize])
+ str::from_utf8_unchecked(&NEWLINES[..self.header_height as usize])
},
..Default::default()
};
@@ -2152,6 +2191,14 @@ mod tests {
start_ix..end_ix
);
}
+
+ for _ in 0..10 {
+ let end_ix = snapshot.clip_offset(rng.gen_range(0..=snapshot.len()), Bias::Right);
+ assert_eq!(
+ expected_text[..end_ix].chars().rev().collect::<String>(),
+ snapshot.reversed_chars_at(end_ix).collect::<String>()
+ );
+ }
}
let snapshot = list.read(cx).snapshot(cx);
@@ -1332,6 +1332,11 @@ impl BufferSnapshot {
self.visible_text.reversed_chars_at(offset)
}
+ pub fn reversed_chunks_in_range<T: ToOffset>(&self, range: Range<T>) -> rope::Chunks {
+ let range = range.start.to_offset(self)..range.end.to_offset(self);
+ self.visible_text.reversed_chunks_in_range(range)
+ }
+
pub fn bytes_in_range<'a, T: ToOffset>(&'a self, range: Range<T>) -> rope::Bytes<'a> {
let start = range.start.to_offset(self);
let end = range.end.to_offset(self);