#![allow(dead_code)]
use logos::Logos;
#[derive(Logos, Debug, Clone, PartialEq)]
pub enum Token {
#[regex(r"#{1,6}[ \t]+", |lex| lex.slice().trim_end().len())]
HeadingPrefix(usize),
#[regex(r"(\*[ \t]*){3,}|(-[ \t]*){3,}|(_[ \t]*){3,}")]
ThematicBreak,
#[token(">")]
BlockQuotePrefix,
#[regex(r"[-*+][ \t]+")]
UnorderedListMarker,
#[regex(r"[0-9]+\.[ \t]+", |lex| {
let s = lex.slice();
s[..s.len()-2].parse::<u32>().ok()
})]
OrderedListMarker(Option<u32>),
#[regex(r"```[^\n]*|~~~[^\n]*")]
FencedCodeDelimiter,
#[token("*")]
Asterisk,
#[token("_")]
Underscore,
#[token("**")]
DoubleAsterisk,
#[token("__")]
DoubleUnderscore,
#[token("~~")]
Strikethrough,
#[token("`")]
Backtick,
#[token("``")]
DoubleBacktick,
#[token("[")]
LeftBracket,
#[token("](")]
LinkMiddle,
#[token("]")]
RightBracket,
#[token("(")]
LeftParen,
#[token(")")]
RightParen,
#[token("![")]
ImageStart,
#[token("\n")]
Newline,
#[regex(r" \n|\\n")]
HardBreak,
#[regex(r"\\[\\`*_\{\}\[\]()#+\-.!~]")]
Escape,
#[regex(r"<[^>]+>")]
HtmlTag,
#[regex(r"<[a-zA-Z][a-zA-Z0-9+.-]*:[^\s>]+>")]
Autolink,
#[token("|")]
Pipe,
#[regex(r"[ \t]+")]
Whitespace,
#[regex(r"[^\n\[\]()!*_`~\\#>|\- \t]+")]
Text,
}
#[derive(Debug, Clone, Default)]
pub struct LexerState {
pub line: u32,
pub column: u32,
pub at_line_start: bool,
pub indent: u32,
}
impl LexerState {
#[must_use]
pub fn new() -> Self {
Self { line: 1, column: 1, at_line_start: true, indent: 0 }
}
pub fn advance(&mut self, text: &str) {
for ch in text.chars() {
if ch == '\n' {
self.line += 1;
self.column = 1;
self.at_line_start = true;
self.indent = 0;
} else {
if self.at_line_start {
if ch == ' ' {
self.indent += 1;
} else if ch == '\t' {
self.indent += 4;
} else {
self.at_line_start = false;
}
}
self.column += 1;
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_heading_prefix() {
let mut lexer = Token::lexer("# ");
assert_eq!(lexer.next(), Some(Ok(Token::HeadingPrefix(1))));
}
#[test]
fn test_thematic_break() {
let mut lexer = Token::lexer("---");
assert_eq!(lexer.next(), Some(Ok(Token::ThematicBreak)));
}
#[test]
fn test_ordered_list() {
let mut lexer = Token::lexer("1. ");
assert_eq!(lexer.next(), Some(Ok(Token::OrderedListMarker(Some(1)))));
}
}