diff options
author | Titus Wormer <tituswormer@gmail.com> | 2022-07-07 17:21:38 +0200 |
---|---|---|
committer | Titus Wormer <tituswormer@gmail.com> | 2022-07-07 17:36:35 +0200 |
commit | 4806864e5377a5fef937b3fa02542e620c547969 (patch) | |
tree | c91ae2bbd1dc2037f425efd24d62d05e706e3e60 /src/construct | |
parent | c2b4402223e53498078fc33dd55aabc0a48cdb56 (diff) | |
download | markdown-rs-4806864e5377a5fef937b3fa02542e620c547969.tar.gz markdown-rs-4806864e5377a5fef937b3fa02542e620c547969.tar.bz2 markdown-rs-4806864e5377a5fef937b3fa02542e620c547969.zip |
Add basic support for block quotes
Diffstat (limited to 'src/construct')
-rw-r--r-- | src/construct/block_quote.rs | 58 | ||||
-rw-r--r-- | src/construct/heading_setext.rs | 27 | ||||
-rw-r--r-- | src/construct/mod.rs | 1 | ||||
-rw-r--r-- | src/construct/paragraph.rs | 28 |
4 files changed, 101 insertions, 13 deletions
diff --git a/src/construct/block_quote.rs b/src/construct/block_quote.rs new file mode 100644 index 0000000..cd5b872 --- /dev/null +++ b/src/construct/block_quote.rs @@ -0,0 +1,58 @@ +//! To do. + +use crate::constant::TAB_SIZE; +use crate::construct::partial_space_or_tab::space_or_tab_min_max; +use crate::tokenizer::{Code, State, StateFnResult, TokenType, Tokenizer}; + +pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { + // To do: allow arbitrary when code (indented) is turned off. + tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before)(tokenizer, code) +} + +fn before(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { + match code { + Code::Char('>') => { + tokenizer.enter(TokenType::BlockQuote); + cont_before(tokenizer, code) + } + _ => cont_before(tokenizer, code), + } +} + +pub fn cont(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { + // To do: allow arbitrary when code (indented) is turned off. + tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), cont_before)(tokenizer, code) +} + +fn cont_before(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { + match code { + Code::Char('>') => { + tokenizer.enter(TokenType::BlockQuotePrefix); + tokenizer.enter(TokenType::BlockQuoteMarker); + tokenizer.consume(code); + tokenizer.exit(TokenType::BlockQuoteMarker); + (State::Fn(Box::new(cont_after)), None) + } + _ => (State::Nok, None), + } +} + +fn cont_after(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { + match code { + Code::VirtualSpace | Code::Char('\t' | ' ') => { + tokenizer.enter(TokenType::BlockQuotePrefixWhitespace); + tokenizer.consume(code); + tokenizer.exit(TokenType::BlockQuotePrefixWhitespace); + tokenizer.exit(TokenType::BlockQuotePrefix); + (State::Ok, None) + } + _ => { + tokenizer.exit(TokenType::BlockQuotePrefix); + (State::Ok, Some(vec![code])) + } + } +} + +pub fn end() -> Vec<TokenType> { + vec![TokenType::BlockQuote] +} diff --git a/src/construct/heading_setext.rs b/src/construct/heading_setext.rs index 211434f..440baa8 100644 --- a/src/construct/heading_setext.rs +++ b/src/construct/heading_setext.rs @@ -60,7 +60,7 @@ use crate::constant::TAB_SIZE; use crate::construct::partial_space_or_tab::{space_or_tab, space_or_tab_min_max}; use crate::tokenizer::{Code, Event, EventType, State, StateFnResult, TokenType, Tokenizer}; -use crate::util::edit_map::EditMap; +use crate::util::{edit_map::EditMap, skip::opt_back as skip_opt_back}; /// Kind of underline. #[derive(Debug, Clone, PartialEq)] @@ -116,11 +116,26 @@ impl Kind { /// ``` pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { let index = tokenizer.events.len(); - let paragraph_before = index > 3 - && tokenizer.events[index - 1].token_type == TokenType::LineEnding - && tokenizer.events[index - 3].token_type == TokenType::Paragraph; - - if paragraph_before { + let previous = if index > 1 { + skip_opt_back( + &tokenizer.events, + index - 1, + &[TokenType::SpaceOrTab, TokenType::BlockQuotePrefix], + ) + } else { + 0 + }; + let previous = skip_opt_back(&tokenizer.events, previous, &[TokenType::LineEnding]); + let paragraph_before = + previous > 1 && tokenizer.events[previous].token_type == TokenType::Paragraph; + + println!( + "setext-start: {:?} {:?} {:?}", + tokenizer.interrupt, tokenizer.lazy, paragraph_before + ); + + // Require a paragraph before and do not allow on a lazy line. + if paragraph_before && !tokenizer.lazy { // To do: allow arbitrary when code (indented) is turned off. tokenizer.go(space_or_tab_min_max(0, TAB_SIZE - 1), before)(tokenizer, code) } else { diff --git a/src/construct/mod.rs b/src/construct/mod.rs index 66b2a3c..936ecf6 100644 --- a/src/construct/mod.rs +++ b/src/construct/mod.rs @@ -64,6 +64,7 @@ pub mod attention; pub mod autolink; pub mod blank_line; +pub mod block_quote; pub mod character_escape; pub mod character_reference; pub mod code_fenced; diff --git a/src/construct/paragraph.rs b/src/construct/paragraph.rs index 4f5e662..ace174f 100644 --- a/src/construct/paragraph.rs +++ b/src/construct/paragraph.rs @@ -35,7 +35,7 @@ use crate::tokenizer::{ Code, ContentType, Event, EventType, State, StateFnResult, TokenType, Tokenizer, }; -use crate::util::edit_map::EditMap; +use crate::util::{edit_map::EditMap, skip::opt as skip_opt}; /// Before a paragraph. /// @@ -90,19 +90,27 @@ pub fn resolve(tokenizer: &mut Tokenizer) -> Vec<Event> { if event.event_type == EventType::Enter && event.token_type == TokenType::Paragraph { // Exit:Paragraph let mut exit_index = index + 3; + let mut enter_next_index = + skip_opt(&tokenizer.events, exit_index + 1, &[TokenType::LineEnding]); // Enter:Paragraph - let mut enter_next_index = exit_index + 3; + enter_next_index = skip_opt( + &tokenizer.events, + enter_next_index, + &[TokenType::SpaceOrTab, TokenType::BlockQuotePrefix], + ); // Find future `Paragraphs`. - // There will be `LineEnding` between. - while enter_next_index < len + while enter_next_index < tokenizer.events.len() && tokenizer.events[enter_next_index].token_type == TokenType::Paragraph { // Remove Exit:Paragraph, Enter:LineEnding, Exit:LineEnding, Enter:Paragraph. - edit_map.add(exit_index, 4, vec![]); + edit_map.add(exit_index, 3, vec![]); + + // Remove Enter:Paragraph. + edit_map.add(enter_next_index, 1, vec![]); // Add Exit:LineEnding position info to Exit:Data. - let line_ending_exit = &tokenizer.events[enter_next_index - 1]; + let line_ending_exit = &tokenizer.events[exit_index + 2]; let line_ending_point = line_ending_exit.point.clone(); let line_ending_index = line_ending_exit.index; let data_exit = &mut tokenizer.events[exit_index - 1]; @@ -117,7 +125,13 @@ pub fn resolve(tokenizer: &mut Tokenizer) -> Vec<Event> { // Potential next start. exit_index = enter_next_index + 3; - enter_next_index = exit_index + 3; + enter_next_index = + skip_opt(&tokenizer.events, exit_index + 1, &[TokenType::LineEnding]); + enter_next_index = skip_opt( + &tokenizer.events, + enter_next_index, + &[TokenType::SpaceOrTab, TokenType::BlockQuotePrefix], + ); } // Move to `Exit:Paragraph`. |