Add Rope::iter_chars_with_point()
This commit is contained in:
parent
f92e86601e
commit
c2f71aac22
306
core/src/rope.rs
306
core/src/rope.rs
|
|
@ -213,6 +213,12 @@ impl Rope {
|
||||||
CharIterator::new(self)
|
CharIterator::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the chars of the text which also contains the
|
||||||
|
/// current line and column.
|
||||||
|
pub fn iter_chars_with_point(self: &Rc<Self>) -> CharWithPointIterator {
|
||||||
|
CharWithPointIterator::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Concatenate two Ropes without rebalancing.
|
/// Concatenate two Ropes without rebalancing.
|
||||||
///
|
///
|
||||||
/// Combines to ropes by creating a new parent node and adding `left` and
|
/// Combines to ropes by creating a new parent node and adding `left` and
|
||||||
|
|
@ -283,20 +289,44 @@ impl Iterator for NodeIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CharIterator {
|
pub struct CharIterator(CharWithPointIterator);
|
||||||
node_iterator: NodeIterator,
|
|
||||||
current_text: Option<String>,
|
|
||||||
str_index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CharIterator {
|
impl CharIterator {
|
||||||
|
fn new(rope: &Rc<Rope>) -> Self {
|
||||||
|
CharIterator(CharWithPointIterator::new(rope))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for CharIterator {
|
||||||
|
type Item = char;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self {
|
||||||
|
CharIterator(inner) => inner.next().map(|p| p.character)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CharWithPointIterator {
|
||||||
|
node_iterator: NodeIterator,
|
||||||
|
current_text: Option<String>,
|
||||||
|
str_index: usize,
|
||||||
|
line_num: usize,
|
||||||
|
char_num: usize,
|
||||||
|
eol: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CharWithPointIterator {
|
||||||
fn new(rope: &Rc<Rope>) -> Self {
|
fn new(rope: &Rc<Rope>) -> Self {
|
||||||
let mut node_iterator = NodeIterator::new(rope.clone());
|
let mut node_iterator = NodeIterator::new(rope.clone());
|
||||||
let current_text = Self::next_string(&mut node_iterator);
|
let current_text = Self::next_string(&mut node_iterator);
|
||||||
CharIterator {
|
CharWithPointIterator {
|
||||||
node_iterator,
|
node_iterator,
|
||||||
current_text,
|
current_text,
|
||||||
str_index: 0,
|
str_index: 0,
|
||||||
|
char_num: 0,
|
||||||
|
line_num: 0,
|
||||||
|
eol: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,18 +339,41 @@ impl CharIterator {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_point(&self) -> (usize, usize) {
|
||||||
|
(self.line_num, self.char_num)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for CharIterator {
|
pub struct CharWithPoint {
|
||||||
type Item = char;
|
pub character: char,
|
||||||
|
pub line: usize,
|
||||||
|
pub column: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for CharWithPointIterator {
|
||||||
|
type Item = CharWithPoint;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.current_text
|
self.current_text
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|text| {
|
.and_then(|text| {
|
||||||
let c = text.chars().nth(self.str_index);
|
let next_char = text.chars().nth(self.str_index);
|
||||||
self.str_index += 1;
|
self.str_index += 1;
|
||||||
c
|
if let Some(c) = next_char {
|
||||||
|
if self.eol {
|
||||||
|
self.char_num = 1;
|
||||||
|
self.line_num += 1;
|
||||||
|
} else {
|
||||||
|
self.char_num += 1
|
||||||
|
}
|
||||||
|
self.eol = c == '\n';
|
||||||
|
}
|
||||||
|
next_char.map(|c| CharWithPoint {
|
||||||
|
character: c,
|
||||||
|
line: self.line_num,
|
||||||
|
column: self.char_num,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
self.current_text = Self::next_string(&mut self.node_iterator);
|
self.current_text = Self::next_string(&mut self.node_iterator);
|
||||||
|
|
@ -581,13 +634,232 @@ mod tests {
|
||||||
fn delete_at_char_index() {
|
fn delete_at_char_index() {
|
||||||
let target = Rope::new("The quick brown fox jumps over the lazy dog.");
|
let target = Rope::new("The quick brown fox jumps over the lazy dog.");
|
||||||
let test = target.delete_at_char_index(10, 6);
|
let test = target.delete_at_char_index(10, 6);
|
||||||
assert_eq!(target.iter_chars().collect::<String>(), "The quick brown fox jumps over the lazy dog.");
|
assert_eq!(
|
||||||
assert_eq!(test.iter_chars().collect::<String>(), "The quick fox jumps over the lazy dog.");
|
target.iter_chars().collect::<String>(),
|
||||||
|
"The quick brown fox jumps over the lazy dog."
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
test.iter_chars().collect::<String>(),
|
||||||
|
"The quick fox jumps over the lazy dog."
|
||||||
|
);
|
||||||
let test = target.delete_at_char_index(0, 4);
|
let test = target.delete_at_char_index(0, 4);
|
||||||
assert_eq!(target.iter_chars().collect::<String>(), "The quick brown fox jumps over the lazy dog.");
|
assert_eq!(
|
||||||
assert_eq!(test.iter_chars().collect::<String>(), "quick brown fox jumps over the lazy dog.");
|
target.iter_chars().collect::<String>(),
|
||||||
let test = target.delete_at_char_index("The quick brown fox jumps over the lazy dog.".len()-5, 5);
|
"The quick brown fox jumps over the lazy dog."
|
||||||
assert_eq!(target.iter_chars().collect::<String>(), "The quick brown fox jumps over the lazy dog.");
|
);
|
||||||
assert_eq!(test.iter_chars().collect::<String>(), "The quick brown fox jumps over the lazy");
|
assert_eq!(
|
||||||
|
test.iter_chars().collect::<String>(),
|
||||||
|
"quick brown fox jumps over the lazy dog."
|
||||||
|
);
|
||||||
|
let test = target
|
||||||
|
.delete_at_char_index("The quick brown fox jumps over the lazy dog.".len() - 5, 5);
|
||||||
|
assert_eq!(
|
||||||
|
target.iter_chars().collect::<String>(),
|
||||||
|
"The quick brown fox jumps over the lazy dog."
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
test.iter_chars().collect::<String>(),
|
||||||
|
"The quick brown fox jumps over the lazy"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn char_iterator_reports_correct_point() {
|
||||||
|
// Build a rope from fragments so we get a proper tree structure.
|
||||||
|
let target = Rope::new("This")
|
||||||
|
.concat(Rope::new(" is the first "))
|
||||||
|
.concat(Rope::new("line.\n"))
|
||||||
|
.concat(Rope::new("This is the "))
|
||||||
|
.concat(Rope::new("second line.\nThis is the third line."))
|
||||||
|
.concat(Rope::new("\n"))
|
||||||
|
.concat(Rope::new(
|
||||||
|
"This is the fourth line.\nThis is the fifth line.\nThis is ",
|
||||||
|
))
|
||||||
|
.concat(Rope::new("the"))
|
||||||
|
.concat(Rope::new(" sixth"))
|
||||||
|
.concat(Rope::new(" line."))
|
||||||
|
.concat(Rope::new("\nThis"))
|
||||||
|
.concat(Rope::new(" is the seventh line."));
|
||||||
|
let expected_values = vec![
|
||||||
|
('T', 0, 1),
|
||||||
|
('h', 0, 2),
|
||||||
|
('i', 0, 3),
|
||||||
|
('s', 0, 4),
|
||||||
|
(' ', 0, 5),
|
||||||
|
('i', 0, 6),
|
||||||
|
('s', 0, 7),
|
||||||
|
(' ', 0, 8),
|
||||||
|
('t', 0, 9),
|
||||||
|
('h', 0, 10),
|
||||||
|
('e', 0, 11),
|
||||||
|
(' ', 0, 12),
|
||||||
|
('f', 0, 13),
|
||||||
|
('i', 0, 14),
|
||||||
|
('r', 0, 15),
|
||||||
|
('s', 0, 16),
|
||||||
|
('t', 0, 17),
|
||||||
|
(' ', 0, 18),
|
||||||
|
('l', 0, 19),
|
||||||
|
('i', 0, 20),
|
||||||
|
('n', 0, 21),
|
||||||
|
('e', 0, 22),
|
||||||
|
('.', 0, 23),
|
||||||
|
('\n', 0, 24),
|
||||||
|
('T', 1, 1),
|
||||||
|
('h', 1, 2),
|
||||||
|
('i', 1, 3),
|
||||||
|
('s', 1, 4),
|
||||||
|
(' ', 1, 5),
|
||||||
|
('i', 1, 6),
|
||||||
|
('s', 1, 7),
|
||||||
|
(' ', 1, 8),
|
||||||
|
('t', 1, 9),
|
||||||
|
('h', 1, 10),
|
||||||
|
('e', 1, 11),
|
||||||
|
(' ', 1, 12),
|
||||||
|
('s', 1, 13),
|
||||||
|
('e', 1, 14),
|
||||||
|
('c', 1, 15),
|
||||||
|
('o', 1, 16),
|
||||||
|
('n', 1, 17),
|
||||||
|
('d', 1, 18),
|
||||||
|
(' ', 1, 19),
|
||||||
|
('l', 1, 20),
|
||||||
|
('i', 1, 21),
|
||||||
|
('n', 1, 22),
|
||||||
|
('e', 1, 23),
|
||||||
|
('.', 1, 24),
|
||||||
|
('\n', 1, 25),
|
||||||
|
('T', 2, 1),
|
||||||
|
('h', 2, 2),
|
||||||
|
('i', 2, 3),
|
||||||
|
('s', 2, 4),
|
||||||
|
(' ', 2, 5),
|
||||||
|
('i', 2, 6),
|
||||||
|
('s', 2, 7),
|
||||||
|
(' ', 2, 8),
|
||||||
|
('t', 2, 9),
|
||||||
|
('h', 2, 10),
|
||||||
|
('e', 2, 11),
|
||||||
|
(' ', 2, 12),
|
||||||
|
('t', 2, 13),
|
||||||
|
('h', 2, 14),
|
||||||
|
('i', 2, 15),
|
||||||
|
('r', 2, 16),
|
||||||
|
('d', 2, 17),
|
||||||
|
(' ', 2, 18),
|
||||||
|
('l', 2, 19),
|
||||||
|
('i', 2, 20),
|
||||||
|
('n', 2, 21),
|
||||||
|
('e', 2, 22),
|
||||||
|
('.', 2, 23),
|
||||||
|
('\n', 2, 24),
|
||||||
|
('T', 3, 1),
|
||||||
|
('h', 3, 2),
|
||||||
|
('i', 3, 3),
|
||||||
|
('s', 3, 4),
|
||||||
|
(' ', 3, 5),
|
||||||
|
('i', 3, 6),
|
||||||
|
('s', 3, 7),
|
||||||
|
(' ', 3, 8),
|
||||||
|
('t', 3, 9),
|
||||||
|
('h', 3, 10),
|
||||||
|
('e', 3, 11),
|
||||||
|
(' ', 3, 12),
|
||||||
|
('f', 3, 13),
|
||||||
|
('o', 3, 14),
|
||||||
|
('u', 3, 15),
|
||||||
|
('r', 3, 16),
|
||||||
|
('t', 3, 17),
|
||||||
|
('h', 3, 18),
|
||||||
|
(' ', 3, 19),
|
||||||
|
('l', 3, 20),
|
||||||
|
('i', 3, 21),
|
||||||
|
('n', 3, 22),
|
||||||
|
('e', 3, 23),
|
||||||
|
('.', 3, 24),
|
||||||
|
('\n', 3, 25),
|
||||||
|
('T', 4, 1),
|
||||||
|
('h', 4, 2),
|
||||||
|
('i', 4, 3),
|
||||||
|
('s', 4, 4),
|
||||||
|
(' ', 4, 5),
|
||||||
|
('i', 4, 6),
|
||||||
|
('s', 4, 7),
|
||||||
|
(' ', 4, 8),
|
||||||
|
('t', 4, 9),
|
||||||
|
('h', 4, 10),
|
||||||
|
('e', 4, 11),
|
||||||
|
(' ', 4, 12),
|
||||||
|
('f', 4, 13),
|
||||||
|
('i', 4, 14),
|
||||||
|
('f', 4, 15),
|
||||||
|
('t', 4, 16),
|
||||||
|
('h', 4, 17),
|
||||||
|
(' ', 4, 18),
|
||||||
|
('l', 4, 19),
|
||||||
|
('i', 4, 20),
|
||||||
|
('n', 4, 21),
|
||||||
|
('e', 4, 22),
|
||||||
|
('.', 4, 23),
|
||||||
|
('\n', 4, 24),
|
||||||
|
('T', 5, 1),
|
||||||
|
('h', 5, 2),
|
||||||
|
('i', 5, 3),
|
||||||
|
('s', 5, 4),
|
||||||
|
(' ', 5, 5),
|
||||||
|
('i', 5, 6),
|
||||||
|
('s', 5, 7),
|
||||||
|
(' ', 5, 8),
|
||||||
|
('t', 5, 9),
|
||||||
|
('h', 5, 10),
|
||||||
|
('e', 5, 11),
|
||||||
|
(' ', 5, 12),
|
||||||
|
('s', 5, 13),
|
||||||
|
('i', 5, 14),
|
||||||
|
('x', 5, 15),
|
||||||
|
('t', 5, 16),
|
||||||
|
('h', 5, 17),
|
||||||
|
(' ', 5, 18),
|
||||||
|
('l', 5, 19),
|
||||||
|
('i', 5, 20),
|
||||||
|
('n', 5, 21),
|
||||||
|
('e', 5, 22),
|
||||||
|
('.', 5, 23),
|
||||||
|
('\n', 5, 24),
|
||||||
|
('T', 6, 1),
|
||||||
|
('h', 6, 2),
|
||||||
|
('i', 6, 3),
|
||||||
|
('s', 6, 4),
|
||||||
|
(' ', 6, 5),
|
||||||
|
('i', 6, 6),
|
||||||
|
('s', 6, 7),
|
||||||
|
(' ', 6, 8),
|
||||||
|
('t', 6, 9),
|
||||||
|
('h', 6, 10),
|
||||||
|
('e', 6, 11),
|
||||||
|
(' ', 6, 12),
|
||||||
|
('s', 6, 13),
|
||||||
|
('e', 6, 14),
|
||||||
|
('v', 6, 15),
|
||||||
|
('e', 6, 16),
|
||||||
|
('n', 6, 17),
|
||||||
|
('t', 6, 18),
|
||||||
|
('h', 6, 19),
|
||||||
|
(' ', 6, 20),
|
||||||
|
('l', 6, 21),
|
||||||
|
('i', 6, 22),
|
||||||
|
('n', 6, 23),
|
||||||
|
('e', 6, 24),
|
||||||
|
('.', 6, 25),
|
||||||
|
('\n', 7, 26),
|
||||||
|
];
|
||||||
|
for (found, (expected_char, expected_line, expected_column)) in
|
||||||
|
target.iter_chars_with_point().zip(expected_values)
|
||||||
|
{
|
||||||
|
assert_eq!(found.character, expected_char);
|
||||||
|
assert_eq!(found.line, expected_line);
|
||||||
|
assert_eq!(found.column, expected_column);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue