aboutsummaryrefslogtreecommitdiffstats
path: root/src/construct/partial_title.rs
diff options
context:
space:
mode:
authorLibravatar Titus Wormer <tituswormer@gmail.com>2022-06-20 11:58:48 +0200
committerLibravatar Titus Wormer <tituswormer@gmail.com>2022-06-20 11:58:48 +0200
commit912f91b2b35be6b0d05dd768d67599d76151bc5c (patch)
treef19ad643607610cdedd8934e8ade0afbaf9384ea /src/construct/partial_title.rs
parent24fec22e912c1aa2569e95683ca95edf1aafce8b (diff)
downloadmarkdown-rs-912f91b2b35be6b0d05dd768d67599d76151bc5c.tar.gz
markdown-rs-912f91b2b35be6b0d05dd768d67599d76151bc5c.tar.bz2
markdown-rs-912f91b2b35be6b0d05dd768d67599d76151bc5c.zip
Add docs to destination, label, title
Diffstat (limited to '')
-rw-r--r--src/construct/partial_title.rs127
1 files changed, 98 insertions, 29 deletions
diff --git a/src/construct/partial_title.rs b/src/construct/partial_title.rs
index 4c7b527..a626c50 100644
--- a/src/construct/partial_title.rs
+++ b/src/construct/partial_title.rs
@@ -1,32 +1,70 @@
+//! Title occurs in [definition][] and label end.
+//!
+//! They’re formed with the following BNF:
+//!
+//! ```bnf
+//! ; Restriction: no blank lines.
+//! ; Restriction: markers must match (in case of `(` with `)`).
+//! title ::= marker [ *( code - '\\' | '\\' [ marker ] ) ] marker
+//! marker ::= '"' | '\'' | '('
+//! ```
+//!
+//! Titles can be double quoted (`"a"`), single quoted (`'a'`), or
+//! parenthesized (`(a)`).
+//!
+//! Titles can contain line endings and whitespace, but they are not allowed to
+//! contain blank lines.
+//! They are allowed to be blank themselves.
+//!
+//! The title is interpreted as the [string][] content type.
+//! That means that character escapes and character reference are allowed.
+//!
+//! ## References
+//!
+//! * [`micromark-factory-title/index.js` in `micromark`](https://github.com/micromark/micromark/blob/main/packages/micromark-factory-title/dev/index.js)
+//!
+//! [definition]: crate::construct::definition
+//! [string]: crate::content::string
+//!
+//! <!-- To do: link label end. -->
+
// To do: pass token types in.
use crate::construct::partial_whitespace::start as whitespace;
use crate::tokenizer::{Code, State, StateFnResult, TokenType, Tokenizer};
-/// Type of quote, if we’re in an attribure, in complete (condition 7).
+/// Type of title.
#[derive(Debug, Clone, PartialEq)]
-enum TitleKind {
- /// In a parenthesised (`(` and `)`) title.
+enum Kind {
+ /// In a parenthesized (`(` and `)`) title.
Paren,
/// In a double quoted (`"`) title.
Double,
- /// In a single quoted (`"`) title.
+ /// In a single quoted (`'`) title.
Single,
}
-fn kind_to_marker(kind: &TitleKind) -> char {
+/// Display a marker.
+fn kind_to_marker(kind: &Kind) -> char {
match kind {
- TitleKind::Double => '"',
- TitleKind::Single => '\'',
- TitleKind::Paren => ')',
+ Kind::Double => '"',
+ Kind::Single => '\'',
+ Kind::Paren => ')',
}
}
+/// Before a title.
+///
+/// ```markdown
+/// |"a"
+/// |'a'
+/// |(a)
+/// ```
pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult {
let kind = match code {
- Code::Char('"') => Some(TitleKind::Double),
- Code::Char('\'') => Some(TitleKind::Single),
- Code::Char('(') => Some(TitleKind::Paren),
+ Code::Char('"') => Some(Kind::Double),
+ Code::Char('\'') => Some(Kind::Single),
+ Code::Char('(') => Some(Kind::Paren),
_ => None,
};
@@ -35,14 +73,22 @@ pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult {
tokenizer.enter(TokenType::DefinitionTitleMarker);
tokenizer.consume(code);
tokenizer.exit(TokenType::DefinitionTitleMarker);
- (State::Fn(Box::new(|t, c| at_first_break(t, c, kind))), None)
+ (State::Fn(Box::new(|t, c| begin(t, c, kind))), None)
} else {
(State::Nok, None)
}
}
-/// To do.
-fn at_first_break(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnResult {
+/// After the opening marker.
+///
+/// This is also used when at the closing marker.
+///
+/// ```markdown
+/// "|a"
+/// '|a'
+/// (|a)
+/// ```
+fn begin(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult {
match code {
Code::Char(char) if char == kind_to_marker(&kind) => {
tokenizer.enter(TokenType::DefinitionTitleMarker);
@@ -58,12 +104,19 @@ fn at_first_break(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> Sta
}
}
-/// To do.
-fn at_break(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnResult {
+/// At something, before something else.
+///
+/// ```markdown
+/// "|a"
+/// 'a|'
+/// (a|
+/// b)
+/// ```
+fn at_break(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult {
match code {
Code::Char(char) if char == kind_to_marker(&kind) => {
tokenizer.exit(TokenType::DefinitionTitleString);
- at_first_break(tokenizer, code, kind)
+ begin(tokenizer, code, kind)
}
Code::None => (State::Nok, None),
Code::CarriageReturnLineFeed | Code::Char('\r' | '\n') => {
@@ -71,7 +124,7 @@ fn at_break(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnRe
tokenizer.consume(code);
tokenizer.exit(TokenType::LineEnding);
(
- State::Fn(Box::new(|t, c| at_break_line_start(t, c, kind))),
+ State::Fn(Box::new(|t, c| line_start(t, c, kind))),
None,
)
}
@@ -83,14 +136,26 @@ fn at_break(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnRe
}
}
-fn at_break_line_start(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnResult {
+/// After a line ending.
+///
+/// ```markdown
+/// "a
+/// |b"
+/// ```
+fn line_start(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult {
tokenizer.attempt(
|t, c| whitespace(t, c, TokenType::Whitespace),
- |_ok| Box::new(|t, c| at_break_line_begin(t, c, kind)),
+ |_ok| Box::new(|t, c| line_begin(t, c, kind)),
)(tokenizer, code)
}
-fn at_break_line_begin(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnResult {
+/// After a line ending, after optional whitespace.
+///
+/// ```markdown
+/// "a
+/// |b"
+/// ```
+fn line_begin(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult {
match code {
// Blank line not allowed.
Code::CarriageReturnLineFeed | Code::Char('\r' | '\n') => (State::Nok, None),
@@ -98,8 +163,12 @@ fn at_break_line_begin(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -
}
}
-/// To do.
-fn title(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnResult {
+/// In title text.
+///
+/// ```markdown
+/// "a|b"
+/// ```
+fn title(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult {
match code {
Code::Char(char) if char == kind_to_marker(&kind) => {
tokenizer.exit(TokenType::ChunkString);
@@ -120,17 +189,17 @@ fn title(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnResul
}
}
-/// To do.
-fn escape(tokenizer: &mut Tokenizer, code: Code, kind: TitleKind) -> StateFnResult {
+/// After `\`, in title text.
+///
+/// ```markdown
+/// "a\|"b"
+/// ```
+fn escape(tokenizer: &mut Tokenizer, code: Code, kind: Kind) -> StateFnResult {
match code {
Code::Char(char) if char == kind_to_marker(&kind) => {
tokenizer.consume(code);
(State::Fn(Box::new(move |t, c| title(t, c, kind))), None)
}
- Code::Char('\\') => {
- tokenizer.consume(code);
- (State::Fn(Box::new(move |t, c| title(t, c, kind))), None)
- }
_ => title(tokenizer, code, kind),
}
}