diff --git a/docs/development/roadmap.md b/docs/development/roadmap.md
index 32a9c64..54362fe 100644
--- a/docs/development/roadmap.md
+++ b/docs/development/roadmap.md
@@ -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
diff --git a/src/syntax/content/parser/context/block.rs b/src/syntax/content/parser/context/block.rs
index 608b58b..11fa54f 100644
--- a/src/syntax/content/parser/context/block.rs
+++ b/src/syntax/content/parser/context/block.rs
@@ -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);
diff --git a/src/syntax/content/parser/segment.rs b/src/syntax/content/parser/segment.rs
index 26fdec1..28cfdb1 100644
--- a/src/syntax/content/parser/segment.rs
+++ b/src/syntax/content/parser/segment.rs
@@ -17,7 +17,7 @@ pub mod delimiter {
Delimiters {
atomic: vec!['`', '|', '\\'],
double: vec!['_', '~'],
- flanking: vec!['_', '*', '~', '(', ')', '\'', '"'],
+ flanking: vec!['_', '*', '~', '(', ')', '[', ']', '\'', '"'],
punctuation: vec![',', '.', ';', ':', '?', '!'],
whitespace: vec!['\n', ' '],
}
diff --git a/src/syntax/content/parser/token.rs b/src/syntax/content/parser/token.rs
index fb88989..9cead7c 100644
--- a/src/syntax/content/parser/token.rs
+++ b/src/syntax/content/parser/token.rs
@@ -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}"),
diff --git a/src/syntax/content/parser/token/checkbox.rs b/src/syntax/content/parser/token/checkbox.rs
new file mode 100644
index 0000000..ebdafcd
--- /dev/null
+++ b/src/syntax/content/parser/token/checkbox.rs
@@ -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#""#)
+ }
+}
+
+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#""#);
+
+ let code_closed = CheckBox::new(false);
+ assert_eq!(code_closed.render(), r#""#);
+ }
+}