led/src/buffer/node.rs

1251 lines
42 KiB
Rust

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<BufferNode>, Box<BufferNode>),
}
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<T: LineFormatter>(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<T: LineFormatter>(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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&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<T: LineFormatter>(&mut self, f: &T, line_number: usize, fetched_line: Option<&Line>) {
match fetched_line {
None => {
let line: Option<Line> = 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<T: LineFormatter>(&mut self, f: &T, line_number: usize) -> Option<Line> {
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<T: LineFormatter>(&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());
}
}