argv-todo 0.1.0

A Vim-style terminal todo manager with nested tasks, priorities, search, and local SQLite storage
use std::ops::Range;

#[derive(Debug, PartialEq)]
pub enum TokenKind {
    Char,
    Word,
    Whitespace,
    EndOfLine,
    Symbol(SymbolKind),
}

#[derive(Debug, PartialEq)]
pub enum Side {
    Open,
    Close,
}

#[derive(Debug, PartialEq)]
pub enum SymbolKind {
    Paren(Side),
    Brace(Side),
    Square(Side),
    DoubleQuote(Side),
    SingleQuote(Side),
    Punctuation,
}

impl TokenKind {
    pub fn expected_close(&self) -> Option<TokenKind> {
        match self {
            TokenKind::Symbol(SymbolKind::Paren(Side::Open)) => {
                Some(TokenKind::Symbol(SymbolKind::Paren(Side::Close)))
            }

            TokenKind::Symbol(SymbolKind::Brace(Side::Open)) => {
                Some(TokenKind::Symbol(SymbolKind::Brace(Side::Close)))
            }

            TokenKind::Symbol(SymbolKind::Square(Side::Open)) => {
                Some(TokenKind::Symbol(SymbolKind::Square(Side::Close)))
            }

            TokenKind::Symbol(SymbolKind::DoubleQuote(Side::Open)) => {
                Some(TokenKind::Symbol(SymbolKind::DoubleQuote(Side::Close)))
            }

            TokenKind::Symbol(SymbolKind::SingleQuote(Side::Open)) => {
                Some(TokenKind::Symbol(SymbolKind::SingleQuote(Side::Close)))
            }

            _ => None,
        }
    }

    pub fn matches_close(&self, expected: &TokenKind) -> bool {
        self == expected
    }
}

#[derive(Debug)]
pub struct Token {
    pub kind: TokenKind,
    pub range: Range<u16>,
    pub children: Vec<Token>,
    pub close: Option<Box<Token>>,
}

impl Token {
    pub fn new(kind: TokenKind, range: Range<u16>) -> Self {
        Self {
            kind,
            range,
            children: vec![],
            close: None,
        }
    }
}