Implement SelectNext

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2021-11-25 15:44:06 +01:00
parent bf7acb5f34
commit 10b3fae2c3
6 changed files with 247 additions and 63 deletions

View file

@ -606,9 +606,8 @@ impl Buffer {
self.text_for_range(range).flat_map(str::chars)
}
pub fn bytes_at<T: ToOffset>(&self, position: T) -> impl Iterator<Item = u8> + '_ {
let offset = position.to_offset(self);
self.visible_text.bytes_at(offset)
pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> rope::Bytes {
self.content().bytes_in_range(range)
}
pub fn contains_str_at<T>(&self, position: T, needle: &str) -> bool
@ -618,7 +617,9 @@ impl Buffer {
let position = position.to_offset(self);
position == self.clip_offset(position, Bias::Left)
&& self
.bytes_at(position)
.bytes_in_range(position..self.len())
.flatten()
.copied()
.take(needle.len())
.eq(needle.bytes())
}
@ -1581,6 +1582,10 @@ impl Snapshot {
self.visible_text.max_point()
}
pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> rope::Bytes {
self.content().bytes_in_range(range)
}
pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> Chunks {
self.content().text_for_range(range)
}
@ -1716,6 +1721,12 @@ impl<'a> Content<'a> {
self.visible_text.reversed_chars_at(offset)
}
pub fn bytes_in_range<T: ToOffset>(&self, range: Range<T>) -> rope::Bytes<'a> {
let start = range.start.to_offset(self);
let end = range.end.to_offset(self);
self.visible_text.bytes_in_range(start..end)
}
pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> Chunks<'a> {
let start = range.start.to_offset(self);
let end = range.end.to_offset(self);

View file

@ -3,7 +3,7 @@ use crate::PointUtf16;
use super::Point;
use arrayvec::ArrayString;
use smallvec::SmallVec;
use std::{cmp, fmt, mem, ops::Range, str};
use std::{cmp, fmt, io, mem, ops::Range, str};
use sum_tree::{Bias, Dimension, SumTree};
#[cfg(test)]
@ -137,8 +137,8 @@ impl Rope {
.flat_map(|chunk| chunk.chars().rev())
}
pub fn bytes_at(&self, start: usize) -> impl Iterator<Item = u8> + '_ {
self.chunks_in_range(start..self.len()).flat_map(str::bytes)
pub fn bytes_in_range(&self, range: Range<usize>) -> Bytes {
Bytes::new(self, range)
}
pub fn chunks<'a>(&'a self) -> Chunks<'a> {
@ -444,6 +444,59 @@ impl<'a> Iterator for Chunks<'a> {
}
}
pub struct Bytes<'a> {
chunks: sum_tree::Cursor<'a, Chunk, usize>,
range: Range<usize>,
}
impl<'a> Bytes<'a> {
pub fn new(rope: &'a Rope, range: Range<usize>) -> Self {
let mut chunks = rope.chunks.cursor();
chunks.seek(&range.start, Bias::Right, &());
Self { chunks, range }
}
pub fn peek(&self) -> Option<&'a [u8]> {
let chunk = self.chunks.item()?;
let chunk_start = *self.chunks.start();
if self.range.end <= chunk_start {
return None;
}
let start = self.range.start.saturating_sub(chunk_start);
let end = self.range.end - chunk_start;
Some(&chunk.0.as_bytes()[start..chunk.0.len().min(end)])
}
}
impl<'a> Iterator for Bytes<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
let result = self.peek();
if result.is_some() {
self.chunks.next(&());
}
result
}
}
impl<'a> io::Read for Bytes<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if let Some(chunk) = self.peek() {
let len = cmp::min(buf.len(), chunk.len());
buf[..len].copy_from_slice(&chunk[..len]);
self.range.start += len;
if len == chunk.len() {
self.chunks.next(&());
}
Ok(len)
} else {
Ok(0)
}
}
}
#[derive(Clone, Debug, Default)]
struct Chunk(ArrayString<{ 2 * CHUNK_BASE }>);
@ -767,7 +820,7 @@ mod tests {
use super::*;
use crate::random_char_iter::RandomCharIter;
use rand::prelude::*;
use std::{cmp::Ordering, env};
use std::{cmp::Ordering, env, io::Read};
use Bias::{Left, Right};
#[test]
@ -843,10 +896,16 @@ mod tests {
for _ in 0..5 {
let end_ix = clip_offset(&expected, rng.gen_range(0..=expected.len()), Right);
let start_ix = clip_offset(&expected, rng.gen_range(0..=end_ix), Left);
assert_eq!(
actual.chunks_in_range(start_ix..end_ix).collect::<String>(),
&expected[start_ix..end_ix]
);
let actual_text = actual.chunks_in_range(start_ix..end_ix).collect::<String>();
assert_eq!(actual_text, &expected[start_ix..end_ix]);
let mut actual_text = String::new();
actual
.bytes_in_range(start_ix..end_ix)
.read_to_string(&mut actual_text)
.unwrap();
assert_eq!(actual_text, &expected[start_ix..end_ix]);
assert_eq!(
actual