use std::mem; use std::cmp::{min, max}; use super::line_formatter::{LineFormatter, RoundingBehavior}; use string_utils::is_line_ending; use super::line::{Line, LineEnding, LineGraphemeIter, str_to_line_ending}; pub enum BufferNodeData { Leaf(Line), Branch(Box, Box), } pub struct BufferNode { pub data: BufferNodeData, pub tree_height: usize, pub grapheme_count: usize, pub line_count: usize, pub vis_dim: (usize, usize), // Height, width } impl BufferNode { pub fn new(f: &T) -> BufferNode { let line = Line::new(); let dim = f.dimensions(&line); BufferNode { data: BufferNodeData::Leaf(line), tree_height: 1, grapheme_count: 0, line_count: 1, vis_dim: dim, } } pub fn new_from_line(f: &T, line: Line) -> BufferNode { let gc = line.grapheme_count(); let dim = f.dimensions(&line); BufferNode { data: BufferNodeData::Leaf(line), tree_height: 1, grapheme_count: gc, line_count: 1, vis_dim: dim, } } fn update_height(&mut self) { match self.data { BufferNodeData::Leaf(_) => { self.tree_height = 1; }, BufferNodeData::Branch(ref left, ref right) => { self.tree_height = max(left.tree_height, right.tree_height) + 1; } } } fn update_stats(&mut self, f: &T) { self.update_height(); match self.data { BufferNodeData::Leaf(ref line) => { self.grapheme_count = line.grapheme_count(); self.line_count = 1; self.vis_dim = f.dimensions(line); }, BufferNodeData::Branch(ref left, ref right) => { self.grapheme_count = left.grapheme_count + right.grapheme_count; self.line_count = left.line_count + right.line_count; self.vis_dim = (left.vis_dim.0 + right.vis_dim.0, max(left.vis_dim.1, right.vis_dim.1)); } } } /// Rotates the tree under the node left fn rotate_left(&mut self, f: &T) { let mut temp = BufferNode::new(f); if let BufferNodeData::Branch(_, ref mut right) = self.data { mem::swap(&mut temp, &mut (**right)); if let BufferNodeData::Branch(ref mut left, _) = temp.data { mem::swap(&mut (**left), &mut (**right)); } else { panic!("rotate_left(): attempting to rotate node without branching right child."); } } else { panic!("rotate_left(): attempting to rotate leaf node."); } if let BufferNodeData::Branch(ref mut left, _) = temp.data { mem::swap(&mut (**left), self); left.update_stats(f); } mem::swap(&mut temp, self); self.update_stats(f); } /// Rotates the tree under the node right fn rotate_right(&mut self, f: &T) { let mut temp = BufferNode::new(f); if let BufferNodeData::Branch(ref mut left, _) = self.data { mem::swap(&mut temp, &mut (**left)); if let BufferNodeData::Branch(_, ref mut right) = temp.data { mem::swap(&mut (**right), &mut (**left)); } else { panic!("rotate_right(): attempting to rotate node without branching left child."); } } else { panic!("rotate_right(): attempting to rotate leaf node."); } if let BufferNodeData::Branch(_, ref mut right) = temp.data { mem::swap(&mut (**right), self); right.update_stats(f); } mem::swap(&mut temp, self); self.update_stats(f); } /// Rebalances the tree under the node fn rebalance(&mut self, f: &T) { loop { let mut rot: isize; if let BufferNodeData::Branch(ref mut left, ref mut right) = self.data { let height_diff = (left.tree_height as isize) - (right.tree_height as isize); // Left side higher than right side if height_diff > 1 { let mut child_rot = false; if let BufferNodeData::Branch(ref lc, ref rc) = left.data { if lc.tree_height < rc.tree_height { child_rot = true; } } if child_rot { left.rotate_left(f); } rot = 1; } // Right side higher then left side else if height_diff < -1 { let mut child_rot = false; if let BufferNodeData::Branch(ref lc, ref rc) = right.data { if lc.tree_height > rc.tree_height { child_rot = true; } } if child_rot { right.rotate_right(f); } rot = -1; } // Balanced, stop else { break; } } else { // Leaf node, stop break; } if rot == 1 { self.rotate_right(f); } else if rot == -1 { self.rotate_left(f); } } } pub fn get_grapheme_recursive<'a>(&'a self, index: usize) -> &'a str { match self.data { BufferNodeData::Leaf(ref line) => { return line.grapheme_at_index(index); }, BufferNodeData::Branch(ref left, ref right) => { if index < left.grapheme_count { return left.get_grapheme_recursive(index); } else { return right.get_grapheme_recursive(index - left.grapheme_count); } } } } pub fn get_line_recursive<'a>(&'a self, index: usize) -> &'a Line { match self.data { BufferNodeData::Leaf(ref line) => { if index != 0 { panic!("get_line_recursive(): at leaf, but index is not zero. This should never happen!"); } return line; }, BufferNodeData::Branch(ref left, ref right) => { if index < left.line_count { return left.get_line_recursive(index); } else { return right.get_line_recursive(index - left.line_count); } } } } pub fn index_to_line_col_recursive(&self, index: usize) -> (usize, usize) { match self.data { BufferNodeData::Leaf(_) => { return (0, min(index, self.grapheme_count)); }, BufferNodeData::Branch(ref left, ref right) => { if index < left.grapheme_count { return left.index_to_line_col_recursive(index); } else { let (v, h) = right.index_to_line_col_recursive((index - left.grapheme_count)); return (v + left.line_count, h); } } } } pub fn line_col_to_index_recursive(&self, pos: (usize, usize)) -> usize { match self.data { BufferNodeData::Leaf(ref line) => { if pos.0 != 0 { return self.grapheme_count; } if pos.1 >= self.grapheme_count { if line.ending != LineEnding::None { return self.grapheme_count - 1; } else { return self.grapheme_count; } } else { return pos.1; } }, BufferNodeData::Branch(ref left, ref right) => { if pos.0 < left.line_count { return left.line_col_to_index_recursive(pos); } else { return left.grapheme_count + right.line_col_to_index_recursive((pos.0 - left.line_count, pos.1)); } } } } pub fn index_to_v2d_recursive(&self, f: &T, index: usize) -> (usize, usize) { match self.data { BufferNodeData::Leaf(ref line) => { return f.index_to_v2d(line, index); }, BufferNodeData::Branch(ref left, ref right) => { if index < left.grapheme_count { return left.index_to_v2d_recursive(f, index); } else { let (y, x) = right.index_to_v2d_recursive(f, (index - left.grapheme_count)); return (y + left.vis_dim.0, x); } } } } pub fn v2d_to_index_recursive(&self, f: &T, pos: (usize, usize), rounding: (RoundingBehavior, RoundingBehavior)) -> usize { match self.data { BufferNodeData::Leaf(ref line) => { let mut r = f.v2d_to_index(line, pos, rounding); // TODO: is this the right thing to do? The idea is that // the non-leaf branch code should put us in the right leaf // anyway, and returning an index equal to the leaf's // grapheme count is putting it on the next line instead of // this one. if r == self.grapheme_count && self.grapheme_count > 0 { r -= 1; } return r; }, BufferNodeData::Branch(ref left, ref right) => { if rounding.0 == RoundingBehavior::Round { // TODO return 0; } else if rounding.0 == RoundingBehavior::Floor { if pos.0 < left.vis_dim.0 { return left.v2d_to_index_recursive(f, pos, rounding); } else { return left.grapheme_count + right.v2d_to_index_recursive(f, (pos.0 - left.vis_dim.0, pos.1), rounding); } } else { // RoundingBehavior::Ceiling // TODO return 0; } } } } /// Insert 'text' at grapheme position 'pos'. pub fn insert_text(&mut self, f: &T, text: &str, pos: usize) { // Byte indices let mut b1: usize = 0; let mut b2: usize = 0; // Grapheme indices let mut g1: usize = 0; let mut g2: usize = 0; // Iterate through graphemes for grapheme in text.grapheme_indices(true) { if is_line_ending(grapheme.1) { if g1 < g2 { self.insert_text_recursive(f, &text[b1..b2], pos + g1); } g1 = g2; b2 += grapheme.1.len(); g2 += 1; self.insert_line_break_recursive(f, str_to_line_ending(grapheme.1), pos + g1); b1 = b2; g1 = g2; } else { b2 += grapheme.1.len(); g2 += 1; } } if g1 < g2 { self.insert_text_recursive(f, &text[b1..b2], pos + g1); } } /// Inserts the given text string at the given grapheme position. /// Note: this assumes the given text has no newline graphemes. pub fn insert_text_recursive(&mut self, f: &T, text: &str, pos: usize) { match self.data { // Find node for text to be inserted into BufferNodeData::Branch(ref mut left, ref mut right) => { if pos < left.grapheme_count { left.insert_text_recursive(f, text, pos); } else { right.insert_text_recursive(f, text, pos - left.grapheme_count); } }, // Insert the text BufferNodeData::Leaf(ref mut line) => { line.insert_text(text, pos); }, } self.update_stats(f); } /// Inserts a line break at the given grapheme position pub fn insert_line_break_recursive(&mut self, f: &T, ending: LineEnding, pos: usize) { if ending == LineEnding::None { return; } let mut old_line = Line::new(); let mut do_split: bool; match self.data { // Find node for the line break to be inserted into BufferNodeData::Branch(ref mut left, ref mut right) => { if pos < left.grapheme_count { left.insert_line_break_recursive(f, ending, pos); } else { right.insert_line_break_recursive(f, ending, pos - left.grapheme_count); } do_split = false; }, // We need to insert the line break, so get the data we // need for that (can't do it here because of borrow checker). BufferNodeData::Leaf(ref mut line) => { mem::swap(&mut old_line, line); do_split = true; }, } if do_split { // Insert line break let new_line = old_line.split(ending, pos); let new_node_a = Box::new(BufferNode::new_from_line(f, old_line)); let new_node_b = Box::new(BufferNode::new_from_line(f, new_line)); self.data = BufferNodeData::Branch(new_node_a, new_node_b); self.update_stats(f); } else { self.update_stats(f); self.rebalance(f); } } /// Removes text between grapheme positions pos_a and pos_b. /// Returns true if a dangling left side remains from the removal. /// Returns false otherwise. pub fn remove_text_recursive(&mut self, f: &T, pos_a: usize, pos_b: usize, is_last: bool) -> bool { let mut temp_node = BufferNode::new(f); let mut total_side_removal = false; let mut dangling_line = false; let mut do_merge_fix = false; let mut merge_line_number: usize = 0; match self.data { BufferNodeData::Branch(ref mut left, ref mut right) => { // Check for complete removal of both sides, which // should never happen here if pos_a == 0 && pos_b == self.grapheme_count { panic!("remove_text_recursive(): attempting to remove entirety of self, which cannot be done from inside self."); } // Complete removal of left side else if pos_a == 0 && pos_b >= left.grapheme_count { if pos_b > left.grapheme_count { let a = 0; let b = pos_b - left.grapheme_count; right.remove_text_recursive(f, a, b, is_last); } total_side_removal = true; mem::swap(&mut temp_node, &mut (**right)); } // Complete removal of right side else if pos_a <= left.grapheme_count && pos_b == self.grapheme_count { if pos_a < left.grapheme_count { let a = pos_a; let b = left.grapheme_count; dangling_line = left.remove_text_recursive(f, a, b, false); } if is_last && !dangling_line { mem::swap(&mut temp_node, &mut (**right)); } else { if is_last { dangling_line = false; } total_side_removal = true; mem::swap(&mut temp_node, &mut (**left)); } } // Partial removal of one or both sides else { // Right side if pos_b > left.grapheme_count { let a = if pos_a > left.grapheme_count {pos_a - left.grapheme_count} else {0}; let b = pos_b - left.grapheme_count; dangling_line = right.remove_text_recursive(f, a, b, is_last) && !is_last; } // Left side if pos_a < left.grapheme_count { let a = pos_a; let b = min(pos_b, left.grapheme_count); do_merge_fix = left.remove_text_recursive(f, a, b, false); merge_line_number = left.line_count - 1; } } }, BufferNodeData::Leaf(ref mut line) => { let mut pos_b2 = pos_b; if pos_b == self.grapheme_count && line.ending != LineEnding::None { line.ending = LineEnding::None; pos_b2 -= 1; } line.remove_text(pos_a, pos_b2); dangling_line = line.ending == LineEnding::None && !is_last; }, } // Do the merge fix if necessary if do_merge_fix { self.merge_line_with_next_recursive(f, merge_line_number, None); } // If one of the sides was completely removed, replace self with the // remaining side. else if total_side_removal { mem::swap(&mut temp_node, self); } self.update_stats(f); self.rebalance(f); return dangling_line; } pub fn append_line_unchecked_recursive(&mut self, f: &T, line: Line) { let mut other_line = Line::new(); if let BufferNodeData::Branch(_, ref mut right) = self.data { right.append_line_unchecked_recursive(f, line); } else { if let BufferNodeData::Leaf(ref mut this_line) = self.data { mem::swap(this_line, &mut other_line); } let new_node_a = Box::new(BufferNode::new_from_line(f, other_line)); let new_node_b = Box::new(BufferNode::new_from_line(f, line)); self.data = BufferNodeData::Branch(new_node_a, new_node_b); } self.update_stats(f); self.rebalance(f); } /// Removes lines in line number range [line_a, line_b) pub fn remove_lines_recursive(&mut self, f: &T, line_a: usize, line_b: usize) { let mut remove_left = false; let mut remove_right = false; let mut temp_node = BufferNode::new(f); if let BufferNodeData::Branch(ref mut left, ref mut right) = self.data { // Right node completely removed if line_a <= left.line_count && line_b >= (left.line_count + right.line_count) { remove_right = true; } // Right node partially removed else if line_b > left.line_count { let a = if line_a > left.line_count {line_a - left.line_count} else {0}; let b = line_b - left.line_count; right.remove_lines_recursive(f, a, b); } // Left node completely removed if line_a == 0 && line_b >= left.line_count { remove_left = true; } // Left node partially removed else if line_a < left.line_count { let a = line_a; let b = min(left.line_count, line_b); left.remove_lines_recursive(f, a, b); } // Set up for node removal if remove_left && remove_right { panic!("remove_lines_recursive(): attempting to completely remove both left and right nodes. This should never happen!"); } else if remove_left { mem::swap(&mut temp_node, &mut (**right)); } else if remove_right { mem::swap(&mut temp_node, &mut (**left)); } } else { panic!("remove_lines_recursive(): processing a leaf node directly. This should never happen!"); } // Swap out node for non-removed node if remove_left || remove_right { mem::swap(&mut temp_node, self); } self.update_stats(f); self.rebalance(f); } pub fn merge_line_with_next_recursive(&mut self, f: &T, line_number: usize, fetched_line: Option<&Line>) { match fetched_line { None => { let line: Option = self.pull_out_line_recursive(f, line_number + 1); if let Some(ref l) = line { self.merge_line_with_next_recursive(f, line_number, Some(l)); } }, Some(line) => { match self.data { BufferNodeData::Branch(ref mut left, ref mut right) => { if line_number < left.line_count { left.merge_line_with_next_recursive(f, line_number, Some(line)); } else { right.merge_line_with_next_recursive(f, line_number - left.line_count, Some(line)); } }, BufferNodeData::Leaf(ref mut line2) => { line2.append_text(line.as_str()); line2.ending = line.ending; } } } } self.update_stats(f); self.rebalance(f); } /// Removes a single line out of the text and returns it. pub fn pull_out_line_recursive(&mut self, f: &T, line_number: usize) -> Option { let mut pulled_line = Line::new(); let mut temp_node = BufferNode::new(f); let mut side_removal = false; match self.data { BufferNodeData::Branch(ref mut left, ref mut right) => { if line_number < left.line_count { if let BufferNodeData::Leaf(ref mut line) = left.data { mem::swap(&mut pulled_line, line); mem::swap(&mut temp_node, &mut (**right)); side_removal = true; } else { pulled_line = left.pull_out_line_recursive(f, line_number).unwrap(); } } else if line_number < self.line_count { if let BufferNodeData::Leaf(ref mut line) = right.data { mem::swap(&mut pulled_line, line); mem::swap(&mut temp_node, &mut (**left)); side_removal = true; } else { pulled_line = right.pull_out_line_recursive(f, line_number - left.line_count).unwrap(); } } else { return None; } }, BufferNodeData::Leaf(_) => { panic!("pull_out_line_recursive(): inside leaf node. This should never happen!"); }, } if side_removal { mem::swap(&mut temp_node, self); } self.update_stats(f); self.rebalance(f); return Some(pulled_line); } /// Ensures that the last line in the node tree has no /// ending line break. pub fn set_last_line_ending_recursive(&mut self, f: &T) { match self.data { BufferNodeData::Branch(_, ref mut right) => { right.set_last_line_ending_recursive(f); }, BufferNodeData::Leaf(ref mut line) => { line.ending = LineEnding::None; }, } self.update_stats(f); } /// Creates an iterator at the first grapheme pub fn grapheme_iter<'a>(&'a self) -> BufferNodeGraphemeIter<'a> { let mut node_stack: Vec<&'a BufferNode> = Vec::new(); let mut cur_node = self; loop { match cur_node.data { BufferNodeData::Leaf(_) => { break; }, BufferNodeData::Branch(ref left, ref right) => { node_stack.push(&(**right)); cur_node = &(**left); } } } BufferNodeGraphemeIter { node_stack: node_stack, cur_line: match cur_node.data { BufferNodeData::Leaf(ref line) => line.grapheme_iter(), _ => panic!("This should never happen.") } } } /// Creates an iterator at the given grapheme index pub fn grapheme_iter_at_index<'a>(&'a self, index: usize) -> BufferNodeGraphemeIter<'a> { let mut node_stack: Vec<&'a BufferNode> = Vec::new(); let mut cur_node = self; let mut grapheme_i = index; loop { match cur_node.data { BufferNodeData::Leaf(_) => { break; }, BufferNodeData::Branch(ref left, ref right) => { if grapheme_i < left.grapheme_count { node_stack.push(&(**right)); cur_node = &(**left); } else { cur_node = &(**right); grapheme_i -= left.grapheme_count; } } } } BufferNodeGraphemeIter { node_stack: node_stack, cur_line: match cur_node.data { BufferNodeData::Leaf(ref line) => line.grapheme_iter_at_index(grapheme_i), _ => panic!("This should never happen.") } } } /// Creates a line iterator starting at the first line pub fn line_iter<'a>(&'a self) -> BufferNodeLineIter<'a> { let mut node_stack: Vec<&'a BufferNode> = Vec::new(); let mut cur_node = self; loop { match cur_node.data { BufferNodeData::Leaf(_) => { break; }, BufferNodeData::Branch(ref left, ref right) => { node_stack.push(&(**right)); cur_node = &(**left); } } } node_stack.push(cur_node); BufferNodeLineIter { node_stack: node_stack, } } /// Creates a line iterator starting at the given line index pub fn line_iter_at_index<'a>(&'a self, index: usize) -> BufferNodeLineIter<'a> { let mut node_stack: Vec<&'a BufferNode> = Vec::new(); let mut cur_node = self; let mut line_i = index; loop { match cur_node.data { BufferNodeData::Leaf(_) => { break; }, BufferNodeData::Branch(ref left, ref right) => { if line_i < left.line_count { node_stack.push(&(**right)); cur_node = &(**left); } else { line_i -= left.line_count; cur_node = &(**right); } } } } node_stack.push(cur_node); BufferNodeLineIter { node_stack: node_stack, } } } //============================================================= // Node iterators //============================================================= /// An iterator over a text buffer's graphemes pub struct BufferNodeGraphemeIter<'a> { node_stack: Vec<&'a BufferNode>, cur_line: LineGraphemeIter<'a>, } impl<'a> BufferNodeGraphemeIter<'a> { // Puts the iterator on the next line. // Returns true if there was a next line, // false if there wasn't. pub fn next_line(&mut self) -> bool { loop { if let Option::Some(node) = self.node_stack.pop() { match node.data { BufferNodeData::Leaf(ref line) => { self.cur_line = line.grapheme_iter(); return true; }, BufferNodeData::Branch(ref left, ref right) => { self.node_stack.push(&(**right)); self.node_stack.push(&(**left)); continue; } } } else { return false; } } } // Skips the iterator n graphemes ahead. // If it runs out of graphemes before reaching the desired skip count, // returns false. Otherwise returns true. pub fn skip_graphemes(&mut self, n: usize) -> bool { // TODO: more efficient implementation for _ in range(0, n) { if let Option::None = self.next() { return false; } } return true; } } impl<'a> Iterator for BufferNodeGraphemeIter<'a> { type Item = &'a str; fn next(&mut self) -> Option<&'a str> { loop { if let Option::Some(g) = self.cur_line.next() { return Option::Some(g); } if self.next_line() { continue; } else { return Option::None; } } } } /// An iterator over a text buffer's lines pub struct BufferNodeLineIter<'a> { node_stack: Vec<&'a BufferNode>, } impl<'a> Iterator for BufferNodeLineIter<'a> { type Item = &'a Line; fn next(&mut self) -> Option<&'a Line> { loop { if let Option::Some(node) = self.node_stack.pop() { match node.data { BufferNodeData::Leaf(ref line) => { return Some(line); }, BufferNodeData::Branch(ref left, ref right) => { self.node_stack.push(&(**right)); self.node_stack.push(&(**left)); continue; } } } else { return None; } } } } //==================================================================== // TESTS //==================================================================== #[cfg(test)] mod tests { use super::BufferNode; use super::super::line::LineEnding; use super::super::line_formatter::TestLineFormatter; #[test] fn merge_line_with_next_recursive_1() { let f = TestLineFormatter::new(); let mut node = BufferNode::new(&f); node.insert_text(&f, "Hi\n there!", 0); assert!(node.grapheme_count == 10); assert!(node.line_count == 2); node.merge_line_with_next_recursive(&f, 0, None); let mut iter = node.grapheme_iter(); assert!(node.grapheme_count == 9); assert!(node.line_count == 1); assert!(Some("H") == iter.next()); assert!(Some("i") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("!") == iter.next()); assert!(None == iter.next()); } #[test] fn merge_line_with_next_recursive_2() { let f = TestLineFormatter::new(); let mut node = BufferNode::new(&f); node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0); assert!(node.grapheme_count == 33); assert!(node.line_count == 5); node.merge_line_with_next_recursive(&f, 2, None); let mut iter = node.grapheme_iter(); assert!(node.grapheme_count == 32); assert!(node.line_count == 4); assert!(Some("H") == iter.next()); assert!(Some("i") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("f") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("w") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("d") == iter.next()); assert!(Some("!") == iter.next()); assert!(None == iter.next()); } #[test] fn merge_line_with_next_recursive_3() { let f = TestLineFormatter::new(); let mut node = BufferNode::new(&f); node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0); assert!(node.grapheme_count == 33); assert!(node.line_count == 5); node.merge_line_with_next_recursive(&f, 0, None); let mut iter = node.grapheme_iter(); assert!(node.grapheme_count == 32); assert!(node.line_count == 4); assert!(Some("H") == iter.next()); assert!(Some("i") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("f") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("w") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("d") == iter.next()); assert!(Some("!") == iter.next()); assert!(None == iter.next()); } #[test] fn pull_out_line_recursive_1() { let f = TestLineFormatter::new(); let mut node = BufferNode::new(&f); node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0); assert!(node.grapheme_count == 33); assert!(node.line_count == 5); let line = node.pull_out_line_recursive(&f, 0).unwrap(); assert!(line.as_str() == "Hi"); assert!(line.ending == LineEnding::LF); let mut iter = node.grapheme_iter(); assert!(node.grapheme_count == 30); assert!(node.line_count == 4); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("f") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("w") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("d") == iter.next()); assert!(Some("!") == iter.next()); assert!(None == iter.next()); } #[test] fn pull_out_line_recursive_2() { let f = TestLineFormatter::new(); let mut node = BufferNode::new(&f); node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0); assert!(node.grapheme_count == 33); assert!(node.line_count == 5); let line = node.pull_out_line_recursive(&f, 2).unwrap(); assert!(line.as_str() == " people "); assert!(line.ending == LineEnding::LF); let mut iter = node.grapheme_iter(); assert!(node.grapheme_count == 24); assert!(node.line_count == 4); assert!(Some("H") == iter.next()); assert!(Some("i") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("f") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("w") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("d") == iter.next()); assert!(Some("!") == iter.next()); assert!(None == iter.next()); } #[test] fn pull_out_line_recursive_3() { let f = TestLineFormatter::new(); let mut node = BufferNode::new(&f); node.insert_text(&f, "Hi\n there\n people \nof the\n world!", 0); assert!(node.grapheme_count == 33); assert!(node.line_count == 5); let line = node.pull_out_line_recursive(&f, 4).unwrap(); assert!(line.as_str() == " world!"); assert!(line.ending == LineEnding::None); let mut iter = node.grapheme_iter(); assert!(node.grapheme_count == 26); assert!(node.line_count == 4); assert!(Some("H") == iter.next()); assert!(Some("i") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("r") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("p") == iter.next()); assert!(Some("l") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("\n") == iter.next()); assert!(Some("o") == iter.next()); assert!(Some("f") == iter.next()); assert!(Some(" ") == iter.next()); assert!(Some("t") == iter.next()); assert!(Some("h") == iter.next()); assert!(Some("e") == iter.next()); assert!(Some("\n") == iter.next()); assert!(None == iter.next()); } }