From b837d488a5892c6c29a245856c2e777d34b7b6ca Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Fri, 9 Jan 2015 22:02:32 -0800 Subject: [PATCH] Basic undo functionality. --- src/buffer/line.rs | 681 +++++++++--------- src/buffer/mod.rs | 1681 +++++++++++++++++++++++--------------------- src/editor.rs | 11 + src/term_ui.rs | 5 + 4 files changed, 1252 insertions(+), 1126 deletions(-) diff --git a/src/buffer/line.rs b/src/buffer/line.rs index a86ee4d..476056e 100644 --- a/src/buffer/line.rs +++ b/src/buffer/line.rs @@ -5,8 +5,6 @@ use std::mem; use std::str::Graphemes; use string_utils::{grapheme_count, grapheme_pos_to_byte_pos, is_line_ending}; -const TAB_WIDTH: usize = 4; - /// Returns the visual width of a grapheme given a starting /// position on a line. @@ -690,348 +688,355 @@ impl<'a> Iterator for LineGraphemeVisIter<'a> { // Line tests //========================================================================= -#[test] -fn new_text_line() { - let tl = Line::new(); - - assert!(tl.text.len() == 0); - assert!(tl.ending == LineEnding::None); -} - -#[test] -fn new_text_line_from_str() { - let tl = Line::new_from_str("Hello!"); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::None); -} - -#[test] -fn new_text_line_from_empty_str() { - let tl = Line::new_from_str(""); - - assert!(tl.text.len() == 0); - assert!(tl.ending == LineEnding::None); -} - -#[test] -fn new_text_line_from_str_with_lf() { - let tl = Line::new_from_str("Hello!\n"); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::LF); -} - -#[test] -fn new_text_line_from_str_with_crlf() { - let tl = Line::new_from_str("Hello!\r\n"); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::CRLF); -} - -#[test] -fn new_text_line_from_str_with_crlf_and_too_long() { - let tl = Line::new_from_str("Hello!\r\nLa la la la"); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::CRLF); -} - -#[test] -fn new_text_line_from_string_unchecked() { - let s = String::from_str("Hello!"); - - let tl = Line::new_from_string_unchecked(s); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::None); -} - -#[test] -fn new_text_line_from_string_unchecked_with_lf() { - let s = String::from_str("Hello!\u{000A}"); - - let tl = Line::new_from_string_unchecked(s); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::LF); -} - -#[test] -fn new_text_line_from_string_unchecked_with_crlf() { - let s = String::from_str("Hello!\u{000D}\u{000A}"); - - let tl = Line::new_from_string_unchecked(s); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::CRLF); -} - -#[test] -fn new_text_line_from_string_unchecked_with_ls() { - let s = String::from_str("Hello!\u{2028}"); - - let tl = Line::new_from_string_unchecked(s); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::LS); -} - -#[test] -fn text_line_insert_text() { - let mut tl = Line::new_from_str("Hello!\r\n"); - - tl.insert_text(" world", 5); - - assert!(tl.text.len() == 12); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == (' ' as u8)); - assert!(tl.text[6] == ('w' as u8)); - assert!(tl.text[7] == ('o' as u8)); - assert!(tl.text[8] == ('r' as u8)); - assert!(tl.text[9] == ('l' as u8)); - assert!(tl.text[10] == ('d' as u8)); - assert!(tl.text[11] == ('!' as u8)); - assert!(tl.ending == LineEnding::CRLF); -} - -#[test] -fn text_line_append_text() { - let mut tl = Line::new_from_str("Hello\r\n"); - - tl.append_text(" world!"); - - assert!(tl.text.len() == 12); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == (' ' as u8)); - assert!(tl.text[6] == ('w' as u8)); - assert!(tl.text[7] == ('o' as u8)); - assert!(tl.text[8] == ('r' as u8)); - assert!(tl.text[9] == ('l' as u8)); - assert!(tl.text[10] == ('d' as u8)); - assert!(tl.text[11] == ('!' as u8)); - assert!(tl.ending == LineEnding::CRLF); -} - -#[test] -fn text_line_remove_text() { - let mut tl = Line::new_from_str("Hello world!\r\n"); - - tl.remove_text(5, 11); - - assert!(tl.text.len() == 6); - assert!(tl.text[0] == ('H' as u8)); - assert!(tl.text[1] == ('e' as u8)); - assert!(tl.text[2] == ('l' as u8)); - assert!(tl.text[3] == ('l' as u8)); - assert!(tl.text[4] == ('o' as u8)); - assert!(tl.text[5] == ('!' as u8)); - assert!(tl.ending == LineEnding::CRLF); -} - -#[test] -fn text_line_split() { - let mut tl1 = Line::new_from_str("Hello world!\r\n"); - - let tl2 = tl1.split(LineEnding::LF, 5); - - assert!(tl1.text.len() == 5); - assert!(tl1.text[0] == ('H' as u8)); - assert!(tl1.text[1] == ('e' as u8)); - assert!(tl1.text[2] == ('l' as u8)); - assert!(tl1.text[3] == ('l' as u8)); - assert!(tl1.text[4] == ('o' as u8)); - assert!(tl1.ending == LineEnding::LF); - - assert!(tl2.text.len() == 7); - assert!(tl2.text[0] == (' ' as u8)); - assert!(tl2.text[1] == ('w' as u8)); - assert!(tl2.text[2] == ('o' as u8)); - assert!(tl2.text[3] == ('r' as u8)); - assert!(tl2.text[4] == ('l' as u8)); - assert!(tl2.text[5] == ('d' as u8)); - assert!(tl2.text[6] == ('!' as u8)); - assert!(tl2.ending == LineEnding::CRLF); -} - -#[test] -fn text_line_split_beginning() { - let mut tl1 = Line::new_from_str("Hello!\r\n"); - - let tl2 = tl1.split(LineEnding::LF, 0); - - assert!(tl1.text.len() == 0); - assert!(tl1.ending == LineEnding::LF); - - assert!(tl2.text.len() == 6); - assert!(tl2.text[0] == ('H' as u8)); - assert!(tl2.text[1] == ('e' as u8)); - assert!(tl2.text[2] == ('l' as u8)); - assert!(tl2.text[3] == ('l' as u8)); - assert!(tl2.text[4] == ('o' as u8)); - assert!(tl2.text[5] == ('!' as u8)); - assert!(tl2.ending == LineEnding::CRLF); -} - -#[test] -fn grapheme_index_to_closest_vis_pos_1() { - let tl = Line::new_from_str("Hello!"); - - assert!(tl.grapheme_index_to_closest_vis_pos(0) == 0); -} - -#[test] -fn grapheme_index_to_closest_vis_pos_2() { - let tl = Line::new_from_str("\tHello!"); - - assert!(tl.grapheme_index_to_closest_vis_pos(1) == TAB_WIDTH); -} - -#[test] -fn vis_pos_to_closest_grapheme_index_1() { - let tl = Line::new_from_str("Hello!"); - - assert!(tl.vis_pos_to_closest_grapheme_index(0) == 0); -} - -#[test] -fn vis_pos_to_closest_grapheme_index_2() { - let tl = Line::new_from_str("\tHello!"); - - assert!(tl.vis_pos_to_closest_grapheme_index(TAB_WIDTH) == 1); -} +mod tests { + use super::{Line, LineEnding, LineGraphemeIter, LineGraphemeVisIter}; + const TAB_WIDTH: usize = 4; -//========================================================================= -// LineGraphemeIter tests -//========================================================================= - -#[test] -fn text_line_grapheme_iter() { - let tl = Line::new_from_str("Hello!"); - let mut iter = tl.grapheme_iter(); + #[test] + fn new_text_line() { + let tl = Line::new(); + + assert!(tl.text.len() == 0); + assert!(tl.ending == LineEnding::None); + } - assert!(iter.next() == Some("H")); - assert!(iter.next() == Some("e")); - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("o")); - assert!(iter.next() == Some("!")); - assert!(iter.next() == None); -} - -#[test] -fn text_line_grapheme_iter_with_lf() { - let tl = Line::new_from_str("Hello!\n"); - let mut iter = tl.grapheme_iter(); + #[test] + fn new_text_line_from_str() { + let tl = Line::new_from_str("Hello!"); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::None); + } - assert!(iter.next() == Some("H")); - assert!(iter.next() == Some("e")); - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("o")); - assert!(iter.next() == Some("!")); - assert!(iter.next() == Some("\n")); - assert!(iter.next() == None); -} - -#[test] -fn text_line_grapheme_iter_with_crlf() { - let tl = Line::new_from_str("Hello!\r\n"); - let mut iter = tl.grapheme_iter(); + #[test] + fn new_text_line_from_empty_str() { + let tl = Line::new_from_str(""); + + assert!(tl.text.len() == 0); + assert!(tl.ending == LineEnding::None); + } - assert!(iter.next() == Some("H")); - assert!(iter.next() == Some("e")); - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("o")); - assert!(iter.next() == Some("!")); - assert!(iter.next() == Some("\r\n")); - assert!(iter.next() == None); -} - -#[test] -fn text_line_grapheme_iter_at_index() { - let tl = Line::new_from_str("Hello!"); - let mut iter = tl.grapheme_iter_at_index(2); + #[test] + fn new_text_line_from_str_with_lf() { + let tl = Line::new_from_str("Hello!\n"); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::LF); + } - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("l")); - assert!(iter.next() == Some("o")); - assert!(iter.next() == Some("!")); - assert!(iter.next() == None); -} - -#[test] -fn text_line_grapheme_iter_at_index_past_end() { - let tl = Line::new_from_str("Hello!"); - let mut iter = tl.grapheme_iter_at_index(10); + #[test] + fn new_text_line_from_str_with_crlf() { + let tl = Line::new_from_str("Hello!\r\n"); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::CRLF); + } - assert!(iter.next() == None); -} - -#[test] -fn text_line_grapheme_iter_at_index_at_lf() { - let tl = Line::new_from_str("Hello!\n"); - let mut iter = tl.grapheme_iter_at_index(6); + #[test] + fn new_text_line_from_str_with_crlf_and_too_long() { + let tl = Line::new_from_str("Hello!\r\nLa la la la"); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::CRLF); + } + + #[test] + fn new_text_line_from_string_unchecked() { + let s = String::from_str("Hello!"); + + let tl = Line::new_from_string_unchecked(s); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::None); + } + + #[test] + fn new_text_line_from_string_unchecked_with_lf() { + let s = String::from_str("Hello!\u{000A}"); + + let tl = Line::new_from_string_unchecked(s); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::LF); + } + + #[test] + fn new_text_line_from_string_unchecked_with_crlf() { + let s = String::from_str("Hello!\u{000D}\u{000A}"); + + let tl = Line::new_from_string_unchecked(s); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::CRLF); + } + + #[test] + fn new_text_line_from_string_unchecked_with_ls() { + let s = String::from_str("Hello!\u{2028}"); + + let tl = Line::new_from_string_unchecked(s); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::LS); + } + + #[test] + fn text_line_insert_text() { + let mut tl = Line::new_from_str("Hello!\r\n"); + + tl.insert_text(" world", 5); + + assert!(tl.text.len() == 12); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == (' ' as u8)); + assert!(tl.text[6] == ('w' as u8)); + assert!(tl.text[7] == ('o' as u8)); + assert!(tl.text[8] == ('r' as u8)); + assert!(tl.text[9] == ('l' as u8)); + assert!(tl.text[10] == ('d' as u8)); + assert!(tl.text[11] == ('!' as u8)); + assert!(tl.ending == LineEnding::CRLF); + } + + #[test] + fn text_line_append_text() { + let mut tl = Line::new_from_str("Hello\r\n"); + + tl.append_text(" world!"); + + assert!(tl.text.len() == 12); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == (' ' as u8)); + assert!(tl.text[6] == ('w' as u8)); + assert!(tl.text[7] == ('o' as u8)); + assert!(tl.text[8] == ('r' as u8)); + assert!(tl.text[9] == ('l' as u8)); + assert!(tl.text[10] == ('d' as u8)); + assert!(tl.text[11] == ('!' as u8)); + assert!(tl.ending == LineEnding::CRLF); + } + + #[test] + fn text_line_remove_text() { + let mut tl = Line::new_from_str("Hello world!\r\n"); + + tl.remove_text(5, 11); + + assert!(tl.text.len() == 6); + assert!(tl.text[0] == ('H' as u8)); + assert!(tl.text[1] == ('e' as u8)); + assert!(tl.text[2] == ('l' as u8)); + assert!(tl.text[3] == ('l' as u8)); + assert!(tl.text[4] == ('o' as u8)); + assert!(tl.text[5] == ('!' as u8)); + assert!(tl.ending == LineEnding::CRLF); + } + + #[test] + fn text_line_split() { + let mut tl1 = Line::new_from_str("Hello world!\r\n"); + + let tl2 = tl1.split(LineEnding::LF, 5); + + assert!(tl1.text.len() == 5); + assert!(tl1.text[0] == ('H' as u8)); + assert!(tl1.text[1] == ('e' as u8)); + assert!(tl1.text[2] == ('l' as u8)); + assert!(tl1.text[3] == ('l' as u8)); + assert!(tl1.text[4] == ('o' as u8)); + assert!(tl1.ending == LineEnding::LF); + + assert!(tl2.text.len() == 7); + assert!(tl2.text[0] == (' ' as u8)); + assert!(tl2.text[1] == ('w' as u8)); + assert!(tl2.text[2] == ('o' as u8)); + assert!(tl2.text[3] == ('r' as u8)); + assert!(tl2.text[4] == ('l' as u8)); + assert!(tl2.text[5] == ('d' as u8)); + assert!(tl2.text[6] == ('!' as u8)); + assert!(tl2.ending == LineEnding::CRLF); + } + + #[test] + fn text_line_split_beginning() { + let mut tl1 = Line::new_from_str("Hello!\r\n"); + + let tl2 = tl1.split(LineEnding::LF, 0); + + assert!(tl1.text.len() == 0); + assert!(tl1.ending == LineEnding::LF); + + assert!(tl2.text.len() == 6); + assert!(tl2.text[0] == ('H' as u8)); + assert!(tl2.text[1] == ('e' as u8)); + assert!(tl2.text[2] == ('l' as u8)); + assert!(tl2.text[3] == ('l' as u8)); + assert!(tl2.text[4] == ('o' as u8)); + assert!(tl2.text[5] == ('!' as u8)); + assert!(tl2.ending == LineEnding::CRLF); + } + + #[test] + fn grapheme_index_to_closest_vis_pos_1() { + let tl = Line::new_from_str("Hello!"); + + assert!(tl.grapheme_index_to_closest_vis_pos(0, TAB_WIDTH) == 0); + } + + #[test] + fn grapheme_index_to_closest_vis_pos_2() { + let tl = Line::new_from_str("\tHello!"); + + assert!(tl.grapheme_index_to_closest_vis_pos(1, TAB_WIDTH) == TAB_WIDTH); + } + + #[test] + fn vis_pos_to_closest_grapheme_index_1() { + let tl = Line::new_from_str("Hello!"); + + assert!(tl.vis_pos_to_closest_grapheme_index(0, TAB_WIDTH) == 0); + } + + #[test] + fn vis_pos_to_closest_grapheme_index_2() { + let tl = Line::new_from_str("\tHello!"); + + assert!(tl.vis_pos_to_closest_grapheme_index(TAB_WIDTH, TAB_WIDTH) == 1); + } + + + //========================================================================= + // LineGraphemeIter tests + //========================================================================= + + #[test] + fn text_line_grapheme_iter() { + let tl = Line::new_from_str("Hello!"); + let mut iter = tl.grapheme_iter(); + + assert!(iter.next() == Some("H")); + assert!(iter.next() == Some("e")); + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("o")); + assert!(iter.next() == Some("!")); + assert!(iter.next() == None); + } + + #[test] + fn text_line_grapheme_iter_with_lf() { + let tl = Line::new_from_str("Hello!\n"); + let mut iter = tl.grapheme_iter(); + + assert!(iter.next() == Some("H")); + assert!(iter.next() == Some("e")); + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("o")); + assert!(iter.next() == Some("!")); + assert!(iter.next() == Some("\n")); + assert!(iter.next() == None); + } + + #[test] + fn text_line_grapheme_iter_with_crlf() { + let tl = Line::new_from_str("Hello!\r\n"); + let mut iter = tl.grapheme_iter(); + + assert!(iter.next() == Some("H")); + assert!(iter.next() == Some("e")); + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("o")); + assert!(iter.next() == Some("!")); + assert!(iter.next() == Some("\r\n")); + assert!(iter.next() == None); + } + + #[test] + fn text_line_grapheme_iter_at_index() { + let tl = Line::new_from_str("Hello!"); + let mut iter = tl.grapheme_iter_at_index(2); + + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("l")); + assert!(iter.next() == Some("o")); + assert!(iter.next() == Some("!")); + assert!(iter.next() == None); + } + + #[test] + fn text_line_grapheme_iter_at_index_past_end() { + let tl = Line::new_from_str("Hello!"); + let mut iter = tl.grapheme_iter_at_index(10); + + assert!(iter.next() == None); + } + + #[test] + fn text_line_grapheme_iter_at_index_at_lf() { + let tl = Line::new_from_str("Hello!\n"); + let mut iter = tl.grapheme_iter_at_index(6); + + assert!(iter.next() == Some("\n")); + assert!(iter.next() == None); + } - assert!(iter.next() == Some("\n")); - assert!(iter.next() == None); } \ No newline at end of file diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 301108b..7062796 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -4,7 +4,7 @@ use std::mem; use self::node::{BufferNode, BufferNodeGraphemeIter, BufferNodeLineIter}; use self::line::{Line, LineEnding}; -use string_utils::{is_line_ending}; +use string_utils::{is_line_ending, grapheme_count}; pub mod line; mod node; @@ -18,6 +18,7 @@ mod node; pub struct Buffer { text: BufferNode, pub line_ending_type: LineEnding, + undo_stack: Vec, } @@ -26,6 +27,7 @@ impl Buffer { Buffer { text: BufferNode::new(), line_ending_type: LineEnding::LF, + undo_stack: Vec::new(), } } @@ -138,12 +140,27 @@ impl Buffer { /// Insert 'text' at grapheme position 'pos'. pub fn insert_text(&mut self, text: &str, pos: usize) { + self._insert_text(text, pos); + + self.undo_stack.push(Operation::InsertText(String::from_str(text), pos)); + } + + fn _insert_text(&mut self, text: &str, pos: usize) { self.text.insert_text(text, pos); } /// Remove the text between grapheme positions 'pos_a' and 'pos_b'. pub fn remove_text(&mut self, pos_a: usize, pos_b: usize) { + let removed_text = self.string_from_range(pos_a, pos_b); + + self._remove_text(pos_a, pos_b); + + // Push operation to the undo stack + self.undo_stack.push(Operation::RemoveText(removed_text, pos_a)); + } + + fn _remove_text(&mut self, pos_a: usize, pos_b: usize) { // Nothing to do if pos_a == pos_b { return; @@ -169,7 +186,59 @@ impl Buffer { self.text.set_last_line_ending_recursive(); } } - + + + /// Undoes operations that were pushed to the undo stack, and returns a + /// cursor position that the cursor should jump to, if any. + pub fn undo(&mut self) -> Option { + if let Some(op) = self.undo_stack.pop() { + match op { + Operation::InsertText(ref s, p) => { + let size = grapheme_count(s.as_slice()); + self._remove_text(p, p+size); + return Some(p); + }, + + Operation::RemoveText(ref s, p) => { + let size = grapheme_count(s.as_slice()); + self._insert_text(s.as_slice(), p); + return Some(p+size); + }, + } + } + + return None; + } + + + /// Creates a String from the buffer text in grapheme range [pos_a, posb). + fn string_from_range(&self, pos_a: usize, pos_b: usize) -> String { + // Bounds checks + if pos_b < pos_a { + panic!("Buffer::string_from_range(): pos_a must be less than or equal to pos_b."); + } + else if pos_b > self.len() { + panic!("Buffer::string_from_range(): specified range is past end of buffer text."); + } + + let mut s = String::with_capacity(pos_b - pos_a); + + let mut iter = self.grapheme_iter_at_index(pos_a); + let mut i = 0; + let i_end = pos_b - pos_a; + + for g in iter { + if i == i_end { + break; + } + + s.push_str(g); + + i += 1; + } + + return s; + } /// Creates an iterator at the first character pub fn grapheme_iter<'a>(&'a self) -> BufferGraphemeIter<'a> { @@ -278,799 +347,835 @@ impl<'a> Iterator for BufferLineIter<'a> { +//================================================================ +// Buffer undo structures +//================================================================ + +enum Operation { + InsertText(String, usize), + RemoveText(String, usize), +} + + + //================================================================ // TESTS //================================================================ -#[test] -fn insert_text() { - let mut buf = Buffer::new(); +mod tests { + use super::{Buffer, Operation, BufferGraphemeIter, BufferLineIter}; + + #[test] + fn insert_text() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello 世界!", 0); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 9); + assert!(buf.text.line_count == 1); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("!") == iter.next()); + assert!(None == iter.next()); + } - buf.insert_text("Hello 世界!", 0); - let mut iter = buf.grapheme_iter(); + #[test] + fn insert_text_with_newlines() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 11); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn insert_text_in_non_empty_buffer_1() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + buf.insert_text("Again ", 0); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 17); + assert!(buf.text.line_count == 3); + assert!(Some("A") == iter.next()); + assert!(Some("g") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn insert_text_in_non_empty_buffer_2() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + buf.insert_text(" again", 5); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 17); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("g") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("n") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn insert_text_in_non_empty_buffer_3() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + buf.insert_text("again", 6); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 16); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("g") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn insert_text_in_non_empty_buffer_4() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + buf.insert_text("again", 11); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 16); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("g") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("n") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn insert_text_in_non_empty_buffer_5() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + buf.insert_text("again", 2); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 16); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("g") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("n") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + + assert!(None == iter.next()); + } + + + #[test] + fn insert_text_in_non_empty_buffer_6() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + buf.insert_text("again", 8); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 16); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("g") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("n") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + + assert!(None == iter.next()); + } + + + #[test] + fn insert_text_in_non_empty_buffer_7() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\n 世界\r\n!", 0); + buf.insert_text("\nag\n\nain\n", 2); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 20); + assert!(buf.text.line_count == 7); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("g") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("a") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("n") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some(" ") == iter.next()); + assert!(Some("世") == iter.next()); + assert!(Some("界") == iter.next()); + assert!(Some("\r\n") == iter.next()); + assert!(Some("!") == iter.next()); + + assert!(None == iter.next()); + } + + + #[test] + fn remove_text_1() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_text(0, 3); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 26); + assert!(buf.text.line_count == 5); + 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("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("\n") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("f") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == 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 remove_text_2() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_text(0, 12); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 17); + assert!(buf.text.line_count == 4); + assert!(Some("p") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("f") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == 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 remove_text_3() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_text(5, 17); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 17); + assert!(buf.text.line_count == 4); + assert!(Some("H") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(Some("f") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == 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 remove_text_4() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_text(23, 29); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 23); + assert!(buf.text.line_count == 6); + assert!(Some("H") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("\n") == 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("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("\n") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("f") == iter.next()); + assert!(Some("\n") == 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()); + } + + + #[test] + fn remove_text_5() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_text(17, 29); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 17); + assert!(buf.text.line_count == 4); + assert!(Some("H") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("\n") == 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("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("\n") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn remove_text_6() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\nworld!", 0); + assert!(buf.len() == 12); + assert!(buf.text.line_count == 2); + + buf.remove_text(3, 12); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 3); + assert!(buf.text.line_count == 1); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn remove_text_7() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\nworld!", 0); + assert!(buf.len() == 15); + assert!(buf.text.line_count == 3); + + buf.remove_text(5, 15); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 5); + assert!(buf.text.line_count == 2); + assert!(Some("H") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn remove_text_8() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\nworld!", 0); + assert!(buf.len() == 12); + assert!(buf.text.line_count == 2); + + buf.remove_text(3, 11); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 4); + assert!(buf.text.line_count == 1); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("!") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn remove_text_9() { + let mut buf = Buffer::new(); + + buf.insert_text("Hello\nworld!", 0); + assert!(buf.len() == 12); + assert!(buf.text.line_count == 2); + + buf.remove_text(8, 12); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 8); + assert!(buf.text.line_count == 2); + assert!(Some("H") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("l") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("w") == iter.next()); + assert!(Some("o") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn remove_text_10() { + let mut buf = Buffer::new(); + + buf.insert_text("12\n34\n56\n78", 0); + assert!(buf.len() == 11); + assert!(buf.text.line_count == 4); + + buf.remove_text(4, 11); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 4); + assert!(buf.text.line_count == 2); + assert!(Some("1") == iter.next()); + assert!(Some("2") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("3") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn remove_text_11() { + let mut buf = Buffer::new(); + + buf.insert_text("1234567890", 0); + assert!(buf.len() == 10); + assert!(buf.text.line_count == 1); + + buf.remove_text(9, 10); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 9); + assert!(buf.text.line_count == 1); + assert!(Some("1") == iter.next()); + assert!(Some("2") == iter.next()); + assert!(Some("3") == iter.next()); + assert!(Some("4") == iter.next()); + assert!(Some("5") == iter.next()); + assert!(Some("6") == iter.next()); + assert!(Some("7") == iter.next()); + assert!(Some("8") == iter.next()); + assert!(Some("9") == iter.next()); + assert!(None == iter.next()); + } + + + #[test] + fn remove_lines_1() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_lines(0, 3); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 13); + assert!(buf.text.line_count == 3); + assert!(Some("o") == iter.next()); + assert!(Some("f") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == 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 remove_lines_2() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_lines(1, 4); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 13); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == 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 remove_lines_3() { + let mut buf = Buffer::new(); + + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + assert!(buf.len() == 29); + assert!(buf.text.line_count == 6); + + buf.remove_lines(3, 6); + + let mut iter = buf.grapheme_iter(); + + assert!(buf.len() == 15); + assert!(buf.text.line_count == 3); + assert!(Some("H") == iter.next()); + assert!(Some("i") == iter.next()); + assert!(Some("\n") == 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("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!(None == iter.next()); + } + + + #[test] + fn pos_2d_to_closest_1d_1() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let pos = buf.pos_2d_to_closest_1d((2, 3)); + + assert!(pos == 12); + } + + + #[test] + fn pos_2d_to_closest_1d_2() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let pos = buf.pos_2d_to_closest_1d((2, 10)); + + assert!(pos == 15); + } + + #[test] + fn pos_2d_to_closest_1d_3() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let pos = buf.pos_2d_to_closest_1d((10, 2)); + + assert!(pos == 29); + } + + + #[test] + fn pos_1d_to_closest_2d_1() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let pos = buf.pos_1d_to_closest_2d(5); + + assert!(pos == (1, 2)); + } + + + #[test] + fn pos_1d_to_closest_2d_2() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let pos = buf.pos_1d_to_closest_2d(50); + + assert!(pos == (5, 6)); + } + + + #[test] + fn string_from_range_1() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let s = buf.string_from_range(1, 12); + + assert!(s.as_slice() == "i\nthere\npeo"); + } + + + #[test] + fn string_from_range_2() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let s = buf.string_from_range(0, 29); + + assert!(s.as_slice() == "Hi\nthere\npeople\nof\nthe\nworld!"); + } + + + #[test] + fn grapheme_iter_at_index_1() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let mut iter = buf.grapheme_iter_at_index(16); + + assert!(Some("o") == iter.next()); + assert!(Some("f") == iter.next()); + assert!(Some("\n") == iter.next()); + assert!(Some("t") == iter.next()); + assert!(Some("h") == iter.next()); + assert!(Some("e") == iter.next()); + assert!(Some("\n") == 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 grapheme_iter_at_index_2() { + let mut buf = Buffer::new(); + buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); + + let mut iter = buf.grapheme_iter_at_index(29); + + assert!(None == iter.next()); + } + - assert!(buf.len() == 9); - assert!(buf.text.line_count == 1); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("!") == iter.next()); - assert!(None == iter.next()); } - -#[test] -fn insert_text_with_newlines() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 11); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn insert_text_in_non_empty_buffer_1() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - buf.insert_text("Again ", 0); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 17); - assert!(buf.text.line_count == 3); - assert!(Some("A") == iter.next()); - assert!(Some("g") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn insert_text_in_non_empty_buffer_2() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - buf.insert_text(" again", 5); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 17); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("g") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("n") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn insert_text_in_non_empty_buffer_3() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - buf.insert_text("again", 6); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 16); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("g") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn insert_text_in_non_empty_buffer_4() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - buf.insert_text("again", 11); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 16); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("g") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("n") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn insert_text_in_non_empty_buffer_5() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - buf.insert_text("again", 2); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 16); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("g") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("n") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - - assert!(None == iter.next()); -} - - -#[test] -fn insert_text_in_non_empty_buffer_6() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - buf.insert_text("again", 8); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 16); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("g") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("n") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - - assert!(None == iter.next()); -} - - -#[test] -fn insert_text_in_non_empty_buffer_7() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\n 世界\r\n!", 0); - buf.insert_text("\nag\n\nain\n", 2); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 20); - assert!(buf.text.line_count == 7); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("g") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("a") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("n") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some(" ") == iter.next()); - assert!(Some("世") == iter.next()); - assert!(Some("界") == iter.next()); - assert!(Some("\r\n") == iter.next()); - assert!(Some("!") == iter.next()); - - assert!(None == iter.next()); -} - - -#[test] -fn remove_text_1() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_text(0, 3); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 26); - assert!(buf.text.line_count == 5); - 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("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("\n") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("f") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == 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 remove_text_2() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_text(0, 12); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 17); - assert!(buf.text.line_count == 4); - assert!(Some("p") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("f") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == 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 remove_text_3() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_text(5, 17); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 17); - assert!(buf.text.line_count == 4); - assert!(Some("H") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(Some("f") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == 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 remove_text_4() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_text(23, 29); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 23); - assert!(buf.text.line_count == 6); - assert!(Some("H") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("\n") == 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("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("\n") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("f") == iter.next()); - assert!(Some("\n") == 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()); -} - - -#[test] -fn remove_text_5() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_text(17, 29); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 17); - assert!(buf.text.line_count == 4); - assert!(Some("H") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("\n") == 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("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("\n") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn remove_text_6() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\nworld!", 0); - assert!(buf.len() == 12); - assert!(buf.text.line_count == 2); - - buf.remove_text(3, 12); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 3); - assert!(buf.text.line_count == 1); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn remove_text_7() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\nworld!", 0); - assert!(buf.len() == 15); - assert!(buf.text.line_count == 3); - - buf.remove_text(5, 15); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 5); - assert!(buf.text.line_count == 2); - assert!(Some("H") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn remove_text_8() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\nworld!", 0); - assert!(buf.len() == 12); - assert!(buf.text.line_count == 2); - - buf.remove_text(3, 11); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 4); - assert!(buf.text.line_count == 1); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("!") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn remove_text_9() { - let mut buf = Buffer::new(); - - buf.insert_text("Hello\nworld!", 0); - assert!(buf.len() == 12); - assert!(buf.text.line_count == 2); - - buf.remove_text(8, 12); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 8); - assert!(buf.text.line_count == 2); - assert!(Some("H") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("l") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("w") == iter.next()); - assert!(Some("o") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn remove_text_10() { - let mut buf = Buffer::new(); - - buf.insert_text("12\n34\n56\n78", 0); - assert!(buf.len() == 11); - assert!(buf.text.line_count == 4); - - buf.remove_text(4, 11); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 4); - assert!(buf.text.line_count == 2); - assert!(Some("1") == iter.next()); - assert!(Some("2") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("3") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn remove_text_11() { - let mut buf = Buffer::new(); - - buf.insert_text("1234567890", 0); - assert!(buf.len() == 10); - assert!(buf.text.line_count == 1); - - buf.remove_text(9, 10); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 9); - assert!(buf.text.line_count == 1); - assert!(Some("1") == iter.next()); - assert!(Some("2") == iter.next()); - assert!(Some("3") == iter.next()); - assert!(Some("4") == iter.next()); - assert!(Some("5") == iter.next()); - assert!(Some("6") == iter.next()); - assert!(Some("7") == iter.next()); - assert!(Some("8") == iter.next()); - assert!(Some("9") == iter.next()); - assert!(None == iter.next()); -} - - -#[test] -fn remove_lines_1() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_lines(0, 3); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 13); - assert!(buf.text.line_count == 3); - assert!(Some("o") == iter.next()); - assert!(Some("f") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == 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 remove_lines_2() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_lines(1, 4); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 13); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == 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 remove_lines_3() { - let mut buf = Buffer::new(); - - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - assert!(buf.len() == 29); - assert!(buf.text.line_count == 6); - - buf.remove_lines(3, 6); - - let mut iter = buf.grapheme_iter(); - - assert!(buf.len() == 15); - assert!(buf.text.line_count == 3); - assert!(Some("H") == iter.next()); - assert!(Some("i") == iter.next()); - assert!(Some("\n") == 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("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!(None == iter.next()); -} - - -#[test] -fn pos_2d_to_closest_1d_1() { - let mut buf = Buffer::new(); - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - - let pos = buf.pos_2d_to_closest_1d((2, 3)); - - assert!(pos == 12); -} - - -#[test] -fn pos_2d_to_closest_1d_2() { - let mut buf = Buffer::new(); - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - - let pos = buf.pos_2d_to_closest_1d((2, 10)); - - assert!(pos == 15); -} - -#[test] -fn pos_2d_to_closest_1d_3() { - let mut buf = Buffer::new(); - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - - let pos = buf.pos_2d_to_closest_1d((10, 2)); - - assert!(pos == 29); -} - - -#[test] -fn pos_1d_to_closest_2d_1() { - let mut buf = Buffer::new(); - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - - let pos = buf.pos_1d_to_closest_2d(5); - - assert!(pos == (1, 2)); -} - - -#[test] -fn pos_1d_to_closest_2d_2() { - let mut buf = Buffer::new(); - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - - let pos = buf.pos_1d_to_closest_2d(50); - - assert!(pos == (5, 6)); -} - - -#[test] -fn grapheme_iter_at_index_1() { - let mut buf = Buffer::new(); - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - - let mut iter = buf.grapheme_iter_at_index(16); - - assert!(Some("o") == iter.next()); - assert!(Some("f") == iter.next()); - assert!(Some("\n") == iter.next()); - assert!(Some("t") == iter.next()); - assert!(Some("h") == iter.next()); - assert!(Some("e") == iter.next()); - assert!(Some("\n") == 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 grapheme_iter_at_index_2() { - let mut buf = Buffer::new(); - buf.insert_text("Hi\nthere\npeople\nof\nthe\nworld!", 0); - - let mut iter = buf.grapheme_iter_at_index(29); - - assert!(None == iter.next()); -} - - - - diff --git a/src/editor.rs b/src/editor.rs index 0549719..99e1378 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -189,6 +189,17 @@ impl Editor { } + pub fn undo(&mut self) { + if let Some(pos) = self.buffer.undo() { + self.cursor.range.0 = pos; + self.cursor.range.1 = pos; + self.cursor.update_vis_start(&(self.buffer), self.tab_width); + + self.move_view_to_cursor(); + } + } + + /// Moves the editor's view the minimum amount to show the cursor pub fn move_view_to_cursor(&mut self) { let (v, h) = self.buffer.pos_1d_to_closest_vis_2d(self.cursor.range.0, self.tab_width); diff --git a/src/term_ui.rs b/src/term_ui.rs index 7b29015..44648e6 100644 --- a/src/term_ui.rs +++ b/src/term_ui.rs @@ -25,6 +25,7 @@ const K_CTRL_L: u16 = 12; const K_CTRL_O: u16 = 15; const K_CTRL_Q: u16 = 17; const K_CTRL_S: u16 = 19; +const K_CTRL_Z: u16 = 26; pub struct TermUI { @@ -98,6 +99,10 @@ impl TermUI { self.editor.save_if_dirty(); }, + K_CTRL_Z => { + self.editor.undo(); + }, + K_CTRL_L => { self.go_to_line_ui_loop(); },