GitLab

+2 −3
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#[cfg(test)]
mod test;

use tokens::{arena, TokenId, TokenType};
use tokens::{arena, TokenId};

#[derive(Debug, Default)]
pub struct Cursor {
@@ -70,8 +70,7 @@ impl Cursor {
                break;
            }

            let terminates = arena().read(grapheme_id, &|grapheme| grapheme.terminates());
            if terminates == TokenType::Line {
            if arena().read(grapheme_id, &|grapheme| grapheme.is_newline_grapheme()) {
                break;
            }

+71 −0
Original line number Diff line number Diff line
@@ -90,6 +90,77 @@ fn move_grapheme() {
    assert_eq!(cursor.grapheme_index(), 2);
}

#[test]
fn move_grapheme_with_line_ending() {
    let line_ids = parse::lines("01\n01").unwrap();
    let word_id = arena().read(line_ids[0], &|line| line.first_child().unwrap());
    let grapheme_id = arena().read(word_id, &|word| word.first_child());
    let mut cursor = Cursor::new(grapheme_id, 0, 0);

    cursor.move_grapheme(2);
    assert_eq!(cursor.line_index(), 0);
    assert_eq!(cursor.grapheme_index(), 1);

    cursor.move_grapheme(1);
    assert_eq!(cursor.line_index(), 0);
    assert_eq!(cursor.grapheme_index(), 1);

    cursor.move_grapheme(-1);
    assert_eq!(cursor.line_index(), 0);
    assert_eq!(cursor.grapheme_index(), 0);

    cursor.move_line(1);
    assert_eq!(cursor.line_index(), 1);
    assert_eq!(cursor.grapheme_index(), 0);

    cursor.move_grapheme(1);
    assert_eq!(cursor.line_index(), 1);
    assert_eq!(cursor.grapheme_index(), 1);

    cursor.move_grapheme(1);
    assert_eq!(cursor.line_index(), 1);
    assert_eq!(cursor.grapheme_index(), 1);
}

#[test]
fn move_grapheme_with_paragraph_ending() {
    let paragraph_ids = parse::paragraphs("01\r\n\r\n01").unwrap();
    let line_id = arena().read(paragraph_ids[0], &|paragraph| {
        paragraph.first_child().unwrap()
    });
    let word_id = arena().read(line_id, &|line| line.first_child().unwrap());
    let grapheme_id = arena().read(word_id, &|word| word.first_child());
    let mut cursor = Cursor::new(grapheme_id, 0, 0);

    cursor.move_grapheme(1);
    assert_eq!(cursor.line_index(), 0);
    assert_eq!(cursor.grapheme_index(), 1);

    cursor.move_grapheme(1);
    assert_eq!(cursor.line_index(), 0);
    assert_eq!(cursor.grapheme_index(), 1);

    cursor.move_grapheme(-1);
    assert_eq!(cursor.line_index(), 0);
    assert_eq!(cursor.grapheme_index(), 0);

    cursor.move_line(1);
    assert_eq!(cursor.line_index(), 1);
    assert_eq!(cursor.grapheme_index(), 0);

    cursor.move_line(1);
    assert_eq!(cursor.line_index(), 2);
    assert_eq!(cursor.grapheme_index(), 0);

    cursor.move_grapheme(1);
    assert_eq!(cursor.line_index(), 2);
    assert_eq!(cursor.grapheme_index(), 1);

    cursor.move_grapheme(1);
    assert_eq!(cursor.line_index(), 2);
    assert_eq!(cursor.grapheme_index(), 1);
}

#[test]
fn move_line() {
    let line_ids = parse::lines("0\n1\n2").unwrap();
+20 −0
Original line number Diff line number Diff line
@@ -145,6 +145,15 @@ impl Token {
        }
    }

    pub fn is_newline_grapheme(&self) -> bool {
        self.value_or(false, &|value| match value.as_ref() {
            "\n" => true,
            "\r" => true,
            "\r\n" => true,
            _ => false,
        })
    }

    pub fn iter(&self, first: Option<TokenId>, last: Option<TokenId>) -> TokenIterator {
        self.siblings(&|siblings| siblings.iter(first, last))
    }
@@ -245,6 +254,10 @@ impl Token {
        self.children_or(None, &|children| children.last())
    }

    pub fn value<'v>(&'v self) -> Option<&'v str> {
        self.value_or(None, &|value| Some(value.as_ref()))
    }

    pub fn delete(&mut self) {
        let previous_id = self.previous();
        let next_id = self.next();
@@ -384,6 +397,13 @@ impl Token {
            _ => default,
        }
    }

    fn value_or<'v, T>(&'v self, default: T, action: &Fn(&'v Value) -> T) -> T {
        match *self {
            Token::Grapheme { ref value, .. } => action(value),
            _ => default,
        }
    }
}

fn link_children(parent_id: TokenId, children: &[TokenId]) {
+21 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ fn grapheme() {
        assert_eq!(grapheme.len(), 1);
        assert_eq!(grapheme.to_string(), " ");
        assert_eq!(grapheme.terminates(), TokenType::Grapheme);
        assert!(grapheme.is_grapheme());
        assert!(!grapheme.is_newline_grapheme());
        assert!(grapheme.previous().is_none());
        assert!(grapheme.next().is_none());
    });
@@ -36,6 +38,8 @@ fn unicode_grapheme() {
        assert_eq!(grapheme.len(), 1);
        assert_eq!(grapheme.to_string(), "💩");
        assert_eq!(grapheme.terminates(), TokenType::Grapheme);
        assert!(grapheme.is_grapheme());
        assert!(!grapheme.is_newline_grapheme());
        assert!(grapheme.previous().is_none());
        assert!(grapheme.next().is_none());
    });
@@ -56,6 +60,7 @@ fn parse_graphemes() {
        .for_each(|(index, grapheme_id)| {
            arena().read(*grapheme_id, &|grapheme| {
                assert_eq!(grapheme.to_string(), expected_graphemes[index]);
                assert!(grapheme.is_grapheme());

                if index > 0 {
                    assert!(*grapheme_id > grapheme_ids[index - 1]);
@@ -67,6 +72,12 @@ fn parse_graphemes() {
                    assert!(grapheme.next().is_some());
                    assert_eq!(grapheme.next().unwrap(), grapheme_ids[index + 1]);
                }

                if index == 3 || index == 4 || index == 5 {
                    assert!(grapheme.is_newline_grapheme());
                } else {
                    assert!(!grapheme.is_newline_grapheme());
                }
            });
        });
}
@@ -80,6 +91,8 @@ fn word() {
        assert_eq!(word.len(), 6);
        assert_eq!(word.to_string(), "wibble");
        assert_eq!(word.terminates(), TokenType::Word);
        assert!(!word.is_grapheme());
        assert!(!word.is_newline_grapheme());
        assert!(word.previous().is_none());
        assert!(word.next().is_none());
    });
@@ -103,6 +116,8 @@ fn unicode_word() {
    arena().read(word_id, &|word| {
        assert_eq!(word.len(), 3);
        assert_eq!(word.to_string(), "🐮🐼🐸");
        assert!(!word.is_grapheme());
        assert!(!word.is_newline_grapheme());
        assert!(word.previous().is_none());
        assert!(word.next().is_none());
    });
@@ -144,6 +159,8 @@ fn line() {
        assert_eq!(line.len(), 15);
        assert_eq!(line.to_string(), "foo bar baz qux");
        assert_eq!(line.terminates(), TokenType::Line);
        assert!(!line.is_grapheme());
        assert!(!line.is_newline_grapheme());
        assert!(line.previous().is_none());
        assert!(line.next().is_none());
    });
@@ -167,6 +184,8 @@ fn unicode_line() {
    arena().read(line_id, &|line| {
        assert_eq!(line.len(), 7);
        assert_eq!(line.to_string(), "🐮🐼🐸 🍺🍷🍸");
        assert!(!line.is_grapheme());
        assert!(!line.is_newline_grapheme());
        assert!(line.previous().is_none());
        assert!(line.next().is_none());
    });
@@ -206,6 +225,8 @@ fn paragraph() {
        assert_eq!(paragraph.len(), 22);
        assert_eq!(paragraph.to_string(), "foo bar\nbaz qux\r\nwibble");
        assert_eq!(paragraph.terminates(), TokenType::Paragraph);
        assert!(!paragraph.is_grapheme());
        assert!(!paragraph.is_newline_grapheme());
        assert!(paragraph.previous().is_none());
        assert!(paragraph.next().is_none());
    });
+6 −0
Original line number Diff line number Diff line
@@ -30,6 +30,12 @@ impl Value {
    }
}

impl AsRef<str> for Value {
    fn as_ref(&self) -> &str {
        &self.value
    }
}

impl Display for Value {
    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
        write!(formatter, "{}", &self.value)

Read the original on gitlab.com ↗