Implement verse token, scaffold quote token
This commit is contained in:
parent
3ea6c53920
commit
aa41e33ced
9 changed files with 325 additions and 45 deletions
|
|
@ -1,6 +1,6 @@
|
|||
use crate::syntax::content::parser::{
|
||||
State, Token,
|
||||
token::{Header, Paragraph, PreFormat},
|
||||
token::{Header, Paragraph, PreFormat, Quote, Verse},
|
||||
};
|
||||
|
||||
pub mod block;
|
||||
|
|
@ -20,6 +20,8 @@ pub enum Block {
|
|||
Header(u8), // level
|
||||
List,
|
||||
PreFormat,
|
||||
Quote,
|
||||
Verse,
|
||||
None,
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +48,12 @@ pub fn close(state: &State, tokens: &mut Vec<Token>) {
|
|||
Block::Header(level) => {
|
||||
tokens.push(Token::Header(Header::from_u8(level, false, None)));
|
||||
},
|
||||
Block::Quote => {
|
||||
tokens.push(Token::Quote(Quote::new(false)));
|
||||
},
|
||||
Block::Verse => {
|
||||
tokens.push(Token::Verse(Verse::new(false)));
|
||||
},
|
||||
Block::None => (),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
use std::{iter::Peekable, slice::Iter};
|
||||
|
||||
use crate::{
|
||||
graph::Graph,
|
||||
prelude::*,
|
||||
syntax::content::{
|
||||
Parseable as _,
|
||||
parser::{
|
||||
Block, Token, Lexeme, State,
|
||||
token::{Header, List, Literal, Paragraph, PreFormat},
|
||||
Block, Lexeme, State, Token,
|
||||
token::{
|
||||
Header, List, LineBreak, Literal, Paragraph, PreFormat, Quote,
|
||||
Verse,
|
||||
},
|
||||
},
|
||||
},
|
||||
graph::Graph,
|
||||
};
|
||||
|
||||
pub fn parse(
|
||||
|
|
@ -44,6 +47,18 @@ pub fn parse(
|
|||
return super::list::parse(
|
||||
lexeme, state, tokens, iterator, graph,
|
||||
);
|
||||
} else if Quote::probe(lexeme) {
|
||||
log!(VERBOSE, "Block Context: None -> Quote on {lexeme}");
|
||||
state.context.block = Block::Quote;
|
||||
tokens.push(Token::Quote(Quote::new(true)));
|
||||
return true;
|
||||
} else if Verse::probe(lexeme) {
|
||||
log!(VERBOSE, "Block Context: None -> Verse on {lexeme}");
|
||||
state.context.block = Block::Verse;
|
||||
tokens.push(Token::Verse(Verse::new(true)));
|
||||
iterator.next();
|
||||
iterator.next();
|
||||
return true;
|
||||
} else if Paragraph::probe(lexeme) {
|
||||
log!(VERBOSE, "Block Context: None -> Paragraph on {lexeme}");
|
||||
state.context.block = Block::Paragraph;
|
||||
|
|
@ -77,6 +92,30 @@ pub fn parse(
|
|||
Block::List => {
|
||||
return super::list::parse(lexeme, state, tokens, iterator, graph);
|
||||
},
|
||||
Block::Quote => {
|
||||
if lexeme.match_char_sequence('\n', '>') {
|
||||
tokens.push(Token::LineBreak(LineBreak::default()));
|
||||
iterator.next();
|
||||
return true;
|
||||
} else if Quote::probe_end(lexeme) {
|
||||
tokens.push(Token::Quote(Quote::new(false)));
|
||||
log!(VERBOSE, "Block Context: Quote -> None on {lexeme}");
|
||||
state.context.block = Block::None;
|
||||
}
|
||||
},
|
||||
Block::Verse => {
|
||||
if Verse::probe_end(lexeme) {
|
||||
tokens.push(Token::Verse(Verse::new(false)));
|
||||
log!(VERBOSE, "Block Context: Verse -> None on {lexeme}");
|
||||
state.context.block = Block::None;
|
||||
iterator.next();
|
||||
iterator.next();
|
||||
return true;
|
||||
} else if lexeme.match_char('\n') {
|
||||
tokens.push(Token::LineBreak(LineBreak::default()));
|
||||
return true;
|
||||
}
|
||||
},
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,10 +77,7 @@ pub fn parse(
|
|||
item_candidate.text.push_str(&lexeme.text());
|
||||
}
|
||||
},
|
||||
Block::None
|
||||
| Block::Paragraph
|
||||
| Block::Header(_)
|
||||
| Block::PreFormat => {
|
||||
_ => {
|
||||
panic!("List context parser called to handle non-list context")
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::syntax::content::Parseable as _;
|
||||
use crate::syntax::content::{Parseable as _};
|
||||
|
||||
pub mod anchor;
|
||||
pub mod bold;
|
||||
|
|
@ -12,14 +12,16 @@ pub mod literal;
|
|||
pub mod oblique;
|
||||
pub mod paragraph;
|
||||
pub mod preformat;
|
||||
pub mod quote;
|
||||
pub mod strike;
|
||||
pub mod underline;
|
||||
pub mod verse;
|
||||
|
||||
pub use {
|
||||
anchor::Anchor, bold::Bold, checkbox::CheckBox, code::Code, header::Header,
|
||||
item::Item, linebreak::LineBreak, list::List, literal::Literal,
|
||||
oblique::Oblique, paragraph::Paragraph, preformat::PreFormat,
|
||||
strike::Strike, underline::Underline,
|
||||
strike::Strike, underline::Underline, quote::Quote, verse::Verse,
|
||||
};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
|
|
@ -37,7 +39,9 @@ pub enum Token {
|
|||
Oblique(Oblique),
|
||||
Paragraph(Paragraph),
|
||||
PreFormat(PreFormat),
|
||||
Quote(Quote),
|
||||
Underline(Underline),
|
||||
Verse(Verse),
|
||||
}
|
||||
|
||||
impl Token {
|
||||
|
|
@ -56,7 +60,9 @@ impl Token {
|
|||
Token::Oblique(d) => d.render(),
|
||||
Token::Paragraph(d) => d.render(),
|
||||
Token::PreFormat(d) => d.render(),
|
||||
Token::Quote(d) => d.render(),
|
||||
Token::Underline(d) => d.render(),
|
||||
Token::Verse(d) => d.render(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +81,9 @@ impl Token {
|
|||
Token::Oblique(d) => d.flatten(),
|
||||
Token::Paragraph(d) => d.flatten(),
|
||||
Token::PreFormat(d) => d.flatten(),
|
||||
Token::Quote(d) => d.flatten(),
|
||||
Token::Underline(d) => d.flatten(),
|
||||
Token::Verse(d) => d.flatten(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +104,9 @@ impl std::fmt::Display for Token {
|
|||
Token::Oblique(d) => format!("{d}"),
|
||||
Token::Paragraph(d) => format!("{d}"),
|
||||
Token::PreFormat(d) => format!("{d}"),
|
||||
Token::Quote(d) => format!("{d}"),
|
||||
Token::Underline(d) => format!("{d}"),
|
||||
Token::Verse(d) => format!("{d}"),
|
||||
};
|
||||
|
||||
write!(f, "Tk:{data}")
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pub struct LineBreak {}
|
|||
|
||||
impl Parseable for LineBreak {
|
||||
fn probe(lexeme: &Lexeme) -> bool {
|
||||
lexeme.text() == "\n" && !lexeme.last()
|
||||
lexeme.match_char('<') && lexeme.match_next_char('\n')
|
||||
}
|
||||
|
||||
fn lex(_lexeme: &Lexeme) -> LineBreak {
|
||||
|
|
@ -15,7 +15,7 @@ impl Parseable for LineBreak {
|
|||
}
|
||||
|
||||
fn render(&self) -> String {
|
||||
"\n".to_owned()
|
||||
String::from("<br>")
|
||||
}
|
||||
|
||||
fn flatten(&self) -> String {
|
||||
|
|
|
|||
58
src/syntax/content/parser/token/quote.rs
Normal file
58
src/syntax/content/parser/token/quote.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use crate::syntax::content::{Parseable, parser::Lexeme};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Quote {
|
||||
open: Option<bool>,
|
||||
}
|
||||
|
||||
impl Quote {
|
||||
pub fn new(open: bool) -> Quote {
|
||||
Quote { open: Some(open) }
|
||||
}
|
||||
|
||||
pub fn probe_end(lexeme: &Lexeme) -> bool {
|
||||
lexeme.match_char_sequence('\n', '\n')
|
||||
}
|
||||
}
|
||||
|
||||
impl Parseable for Quote {
|
||||
fn probe(lexeme: &Lexeme) -> bool {
|
||||
lexeme.match_char('>') && lexeme.match_next_char(' ')
|
||||
}
|
||||
|
||||
fn lex(_lexeme: &Lexeme) -> Quote {
|
||||
Quote { open: None }
|
||||
}
|
||||
|
||||
fn render(&self) -> String {
|
||||
if let Some(open) = self.open {
|
||||
if open {
|
||||
"<blockquote>".to_owned()
|
||||
} else {
|
||||
"</blockquote>".to_owned()
|
||||
}
|
||||
} else {
|
||||
panic!("Attempt to render a quote tag while open state is unknown")
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten(&self) -> String {
|
||||
String::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Quote {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let display_open_state = match self.open {
|
||||
Some(open_state) => {
|
||||
if open_state {
|
||||
"open"
|
||||
} else {
|
||||
"closed"
|
||||
}
|
||||
},
|
||||
None => "unknown",
|
||||
};
|
||||
write!(f, "Quote [{display_open_state}]")
|
||||
}
|
||||
}
|
||||
72
src/syntax/content/parser/token/verse.rs
Normal file
72
src/syntax/content/parser/token/verse.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use crate::syntax::content::{Parseable, parser::Lexeme};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Verse {
|
||||
open: Option<bool>,
|
||||
citation: Option<String>,
|
||||
}
|
||||
|
||||
impl Verse {
|
||||
pub fn new(open: bool) -> Verse {
|
||||
Verse {
|
||||
open: Some(open),
|
||||
citation: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn probe_end(lexeme: &Lexeme) -> bool {
|
||||
lexeme.match_char_triple('\n', '&', '\n')
|
||||
}
|
||||
}
|
||||
|
||||
impl Parseable for Verse {
|
||||
fn probe(lexeme: &Lexeme) -> bool {
|
||||
lexeme.match_char_triple('\n', '&', '\n')
|
||||
}
|
||||
|
||||
fn lex(_lexeme: &Lexeme) -> Verse {
|
||||
Verse {
|
||||
open: None,
|
||||
citation: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self) -> String {
|
||||
if let Some(open) = self.open {
|
||||
if open {
|
||||
concat!("\n", r#"<p class="verse">"#).to_string()
|
||||
} else {
|
||||
"\n</p>\n".to_owned()
|
||||
}
|
||||
} else {
|
||||
panic!("Attempt to render a verse tag while open state is unknown")
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten(&self) -> String {
|
||||
String::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Verse {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let display_open_state = match self.open {
|
||||
Some(open_state) => {
|
||||
if open_state {
|
||||
"open"
|
||||
} else {
|
||||
"closed"
|
||||
}
|
||||
},
|
||||
None => "unknown",
|
||||
};
|
||||
|
||||
let citation = if self.citation.is_some() {
|
||||
" cited"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
write!(f, "Verse [{display_open_state}{citation}]")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue