diff options
author | Titus Wormer <tituswormer@gmail.com> | 2022-06-21 18:06:47 +0200 |
---|---|---|
committer | Titus Wormer <tituswormer@gmail.com> | 2022-06-21 18:06:47 +0200 |
commit | d1063268e62633a334bb9464f7cba2385da5812d (patch) | |
tree | 76035cdf260046cd2afe1841c0351b311ea66d99 /src/construct/partial_title.rs | |
parent | 56ff5c73c7ec19b349e7d60d04ce1057c006d6ec (diff) | |
download | markdown-rs-d1063268e62633a334bb9464f7cba2385da5812d.tar.gz markdown-rs-d1063268e62633a334bb9464f7cba2385da5812d.tar.bz2 markdown-rs-d1063268e62633a334bb9464f7cba2385da5812d.zip |
Add support for passing token types to destination, label, title
Diffstat (limited to '')
-rw-r--r-- | src/construct/partial_title.rs | 102 |
1 files changed, 66 insertions, 36 deletions
diff --git a/src/construct/partial_title.rs b/src/construct/partial_title.rs index aa1e067..d02ce60 100644 --- a/src/construct/partial_title.rs +++ b/src/construct/partial_title.rs @@ -31,12 +31,23 @@ //! //! <!-- To do: link label end. --> -// To do: pass token types in. - use crate::construct::partial_space_or_tab::space_or_tab_opt; use crate::tokenizer::{Code, State, StateFnResult, TokenType, Tokenizer}; use crate::util::link::link; +/// Configuration. +/// +/// You must pass the token types in that are used. +#[derive(Debug)] +pub struct Options { + /// Token for the whole title. + pub title: TokenType, + /// Token for the marker. + pub marker: TokenType, + /// Token for the string inside the quotes. + pub string: TokenType, +} + /// Type of title. #[derive(Debug, PartialEq)] enum Kind { @@ -94,6 +105,17 @@ impl Kind { } } +/// State needed to parse titles. +#[derive(Debug)] +struct Info { + /// Whether we’ve seen our first `ChunkString`. + connect: bool, + /// Kind of title. + kind: Kind, + /// Configuration. + options: Options, +} + /// Before a title. /// /// ```markdown @@ -101,15 +123,19 @@ impl Kind { /// |'a' /// |(a) /// ``` -pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { +pub fn start(tokenizer: &mut Tokenizer, code: Code, options: Options) -> StateFnResult { match code { Code::Char(char) if char == '(' || char == '"' || char == '\'' => { - let kind = Kind::from_char(char); - tokenizer.enter(TokenType::DefinitionTitle); - tokenizer.enter(TokenType::DefinitionTitleMarker); + let info = Info { + connect: false, + kind: Kind::from_char(char), + options, + }; + tokenizer.enter(info.options.title.clone()); + tokenizer.enter(info.options.marker.clone()); tokenizer.consume(code); - tokenizer.exit(TokenType::DefinitionTitleMarker); - (State::Fn(Box::new(|t, c| begin(t, c, kind))), None) + tokenizer.exit(info.options.marker.clone()); + (State::Fn(Box::new(|t, c| begin(t, c, info))), None) } _ => (State::Nok, None), } @@ -124,18 +150,18 @@ pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { /// '|a' /// (|a) /// ``` -fn begin(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult { +fn begin(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { match code { - Code::Char(char) if char == kind.as_char() => { - tokenizer.enter(TokenType::DefinitionTitleMarker); + Code::Char(char) if char == info.kind.as_char() => { + tokenizer.enter(info.options.marker.clone()); tokenizer.consume(code); - tokenizer.exit(TokenType::DefinitionTitleMarker); - tokenizer.exit(TokenType::DefinitionTitle); + tokenizer.exit(info.options.marker.clone()); + tokenizer.exit(info.options.title); (State::Ok, None) } _ => { - tokenizer.enter(TokenType::DefinitionTitleString); - at_break(tokenizer, code, kind, false) + tokenizer.enter(info.options.string.clone()); + at_break(tokenizer, code, info) } } } @@ -148,20 +174,24 @@ fn begin(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult { /// (a| /// b) /// ``` -fn at_break(tokenizer: &mut Tokenizer, code: Code, kind: Kind, connect: bool) -> StateFnResult { +fn at_break(tokenizer: &mut Tokenizer, code: Code, mut info: Info) -> StateFnResult { match code { - Code::Char(char) if char == kind.as_char() => { - tokenizer.exit(TokenType::DefinitionTitleString); - begin(tokenizer, code, kind) + Code::Char(char) if char == info.kind.as_char() => { + tokenizer.exit(info.options.string.clone()); + begin(tokenizer, code, info) } Code::None => (State::Nok, None), _ => { tokenizer.enter(TokenType::ChunkString); - if connect { + + if info.connect { let index = tokenizer.events.len() - 1; link(&mut tokenizer.events, index); + } else { + info.connect = true; } - title(tokenizer, code, kind) + + title(tokenizer, code, info) } } } @@ -172,8 +202,8 @@ fn at_break(tokenizer: &mut Tokenizer, code: Code, kind: Kind, connect: bool) -> /// "a /// |b" /// ``` -fn line_start(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult { - tokenizer.go(space_or_tab_opt(), |t, c| line_begin(t, c, kind))(tokenizer, code) +fn line_start(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { + tokenizer.go(space_or_tab_opt(), |t, c| line_begin(t, c, info))(tokenizer, code) } /// After a line ending, after optional whitespace. @@ -182,11 +212,11 @@ fn line_start(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResul /// "a /// |b" /// ``` -fn line_begin(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult { +fn line_begin(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { match code { // Blank line not allowed. Code::CarriageReturnLineFeed | Code::Char('\r' | '\n') => (State::Nok, None), - _ => at_break(tokenizer, code, kind, true), + _ => at_break(tokenizer, code, info), } } @@ -195,28 +225,28 @@ fn line_begin(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResul /// ```markdown /// "a|b" /// ``` -fn title(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult { +fn title(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { match code { - Code::Char(char) if char == kind.as_char() => { + Code::Char(char) if char == info.kind.as_char() => { tokenizer.exit(TokenType::ChunkString); - at_break(tokenizer, code, kind, true) + at_break(tokenizer, code, info) } Code::None => { tokenizer.exit(TokenType::ChunkString); - at_break(tokenizer, code, kind, true) + at_break(tokenizer, code, info) } Code::CarriageReturnLineFeed | Code::Char('\r' | '\n') => { tokenizer.consume(code); tokenizer.exit(TokenType::ChunkString); - (State::Fn(Box::new(|t, c| line_start(t, c, kind))), None) + (State::Fn(Box::new(|t, c| line_start(t, c, info))), None) } Code::Char('\\') => { tokenizer.consume(code); - (State::Fn(Box::new(|t, c| escape(t, c, kind))), None) + (State::Fn(Box::new(|t, c| escape(t, c, info))), None) } _ => { tokenizer.consume(code); - (State::Fn(Box::new(|t, c| title(t, c, kind))), None) + (State::Fn(Box::new(|t, c| title(t, c, info))), None) } } } @@ -226,12 +256,12 @@ fn title(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult { /// ```markdown /// "a\|"b" /// ``` -fn escape(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult { +fn escape(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { match code { - Code::Char(char) if char == kind.as_char() => { + Code::Char(char) if char == info.kind.as_char() => { tokenizer.consume(code); - (State::Fn(Box::new(|t, c| title(t, c, kind))), None) + (State::Fn(Box::new(|t, c| title(t, c, info))), None) } - _ => title(tokenizer, code, kind), + _ => title(tokenizer, code, info), } } |