Implement checkbox

This commit is contained in:
Juno Takano 2026-01-07 10:56:38 -03:00
commit dfdc631600
5 changed files with 75 additions and 5 deletions

View file

@ -52,7 +52,7 @@
- [x] Inline code
- [x] Lists
- [ ] Nested lists
- [ ] Checkboxes
- [x] Checkboxes
- [ ] Move this roadmap to en
- [ ] Full-text search
- [ ] Begin centralizing state

View file

@ -9,8 +9,7 @@ use crate::{
lexeme::Lexeme,
state::State,
token::{
Token, header::Header, preformat::PreFormat,
paragraph::Paragraph, literal::Literal, list::List, item::Item,
Token, checkbox::CheckBox, header::Header, item::Item, list::List, literal::Literal, paragraph::Paragraph, preformat::PreFormat
},
},
},
@ -98,7 +97,13 @@ pub fn parse(
}
},
Block::Item(ordered) => {
if Item::probe_end(lexeme) {
if CheckBox::probe(lexeme) {
log!("Probed CheckBox: {lexeme}");
tokens.push(Token::CheckBox(CheckBox::lex(lexeme)));
iterator.next();
iterator.next();
return true
} else if Item::probe_end(lexeme) {
tokens.push(Token::Item(Item::new(false)));
log!("Block Context: Item -> List on {lexeme}");
state.context.block = Block::List(ordered);

View file

@ -17,7 +17,7 @@ pub mod delimiter {
Delimiters {
atomic: vec!['`', '|', '\\'],
double: vec!['_', '~'],
flanking: vec!['_', '*', '~', '(', ')', '\'', '"'],
flanking: vec!['_', '*', '~', '(', ')', '[', ']', '\'', '"'],
punctuation: vec![',', '.', ';', ':', '?', '!'],
whitespace: vec!['\n', ' '],
}

View file

@ -2,6 +2,7 @@ use crate::syntax::content::Parseable as _;
pub mod anchor;
pub mod bold;
pub mod checkbox;
pub mod code;
pub mod header;
pub mod item;
@ -19,6 +20,7 @@ pub mod underline;
pub enum Token {
Anchor(anchor::Anchor),
Bold(bold::Bold),
CheckBox(checkbox::CheckBox),
Code(code::Code),
Strike(strike::Strike),
Header(header::Header),
@ -38,6 +40,7 @@ impl Token {
match *self {
Token::Anchor(ref d) => d.render(),
Token::Bold(ref d) => d.render(),
Token::CheckBox(ref d) => d.render(),
Token::Code(ref d) => d.render(),
Token::Strike(ref d) => d.render(),
Token::Header(ref d) => d.render(),
@ -59,6 +62,7 @@ impl std::fmt::Display for Token {
let data = match *self {
Token::Anchor(ref d) => format!("{d}"),
Token::Bold(ref d) => format!("{d}"),
Token::CheckBox(ref d) => format!("{d}"),
Token::Code(ref d) => format!("{d}"),
Token::Strike(ref d) => format!("{d}"),
Token::Header(ref d) => format!("{d}"),

View file

@ -0,0 +1,61 @@
use crate::{
syntax::content::{Parseable, Lexeme},
};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct CheckBox {
checked: bool,
}
impl CheckBox {
pub fn new(checked: bool) -> CheckBox {
CheckBox { checked }
}
}
impl Parseable for CheckBox {
fn probe(lexeme: &Lexeme) -> bool {
lexeme.match_triple_as_char(('[', ' ', ']'))
|| lexeme.match_triple_as_char(('[', 'x', ']'))
}
fn lex(lexeme: &Lexeme) -> CheckBox {
use crate::prelude::*;
log!("Lexing: {lexeme}");
if lexeme.match_next_as_char('x') {
CheckBox::new(true)
} else {
CheckBox::new(false)
}
}
fn render(&self) -> String {
let toggle = if self.checked {
" checked "
} else {
""
};
format!(r#"<input type="checkbox"{toggle}/>"#)
}
}
impl std::fmt::Display for CheckBox {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let display_state = if self.checked { "checked" } else { "empty" };
write!(f, "CheckBox [{display_state}]")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render() {
let code_open = CheckBox::new(true);
assert_eq!(code_open.render(), r#"<input type="checkbox" checked />"#);
let code_closed = CheckBox::new(false);
assert_eq!(code_closed.render(), r#"<input type="checkbox"/>"#);
}
}