Implement SelectNext
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
bf7acb5f34
commit
10b3fae2c3
6 changed files with 247 additions and 63 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue