diff --git a/src/configuration.rs b/src/configuration.rs
index 4f0281f..341cb57 100644
--- a/src/configuration.rs
+++ b/src/configuration.rs
@@ -115,6 +115,13 @@ pub struct Constructs {
/// ^^^
/// ````
pub frontmatter: bool,
+ /// wikilink syntax.
+ ///
+ /// ```markdown
+ /// > | [[a]]
+ /// ^^^^^
+ /// ```
+ pub wikilink: bool,
/// GFM: autolink literal.
///
/// ```markdown
@@ -379,6 +386,7 @@ impl Default for Constructs {
mdx_jsx_flow: false,
mdx_jsx_text: false,
thematic_break: true,
+ wikilink: false,
}
}
}
@@ -1456,7 +1464,7 @@ mod tests {
assert_eq!(
format!("{:?}", ParseOptions::default()),
- "ParseOptions { constructs: Constructs { attention: true, autolink: true, block_quote: true, character_escape: true, character_reference: true, code_indented: true, code_fenced: true, code_text: true, definition: true, frontmatter: false, gfm_autolink_literal: false, gfm_footnote_definition: false, gfm_label_start_footnote: false, gfm_strikethrough: false, gfm_table: false, gfm_task_list_item: false, hard_break_escape: true, hard_break_trailing: true, heading_atx: true, heading_setext: true, html_flow: true, html_text: true, label_start_image: true, label_start_link: true, label_end: true, list_item: true, math_flow: false, math_text: false, mdx_esm: false, mdx_expression_flow: false, mdx_expression_text: false, mdx_jsx_flow: false, mdx_jsx_text: false, thematic_break: true }, gfm_strikethrough_single_tilde: true, math_text_single_dollar: true, mdx_expression_parse: None, mdx_esm_parse: None }",
+ "ParseOptions { constructs: Constructs { attention: true, autolink: true, block_quote: true, character_escape: true, character_reference: true, code_indented: true, code_fenced: true, code_text: true, definition: true, frontmatter: false, wikilink: false, gfm_autolink_literal: false, gfm_footnote_definition: false, gfm_label_start_footnote: false, gfm_strikethrough: false, gfm_table: false, gfm_task_list_item: false, hard_break_escape: true, hard_break_trailing: true, heading_atx: true, heading_setext: true, html_flow: true, html_text: true, label_start_image: true, label_start_link: true, label_end: true, list_item: true, math_flow: false, math_text: false, mdx_esm: false, mdx_expression_flow: false, mdx_expression_text: false, mdx_jsx_flow: false, mdx_jsx_text: false, thematic_break: true }, gfm_strikethrough_single_tilde: true, math_text_single_dollar: true, mdx_expression_parse: None, mdx_esm_parse: None }",
"should support `Debug` trait"
);
assert_eq!(
@@ -1469,7 +1477,7 @@ mod tests {
})),
..Default::default()
}),
- "ParseOptions { constructs: Constructs { attention: true, autolink: true, block_quote: true, character_escape: true, character_reference: true, code_indented: true, code_fenced: true, code_text: true, definition: true, frontmatter: false, gfm_autolink_literal: false, gfm_footnote_definition: false, gfm_label_start_footnote: false, gfm_strikethrough: false, gfm_table: false, gfm_task_list_item: false, hard_break_escape: true, hard_break_trailing: true, heading_atx: true, heading_setext: true, html_flow: true, html_text: true, label_start_image: true, label_start_link: true, label_end: true, list_item: true, math_flow: false, math_text: false, mdx_esm: false, mdx_expression_flow: false, mdx_expression_text: false, mdx_jsx_flow: false, mdx_jsx_text: false, thematic_break: true }, gfm_strikethrough_single_tilde: true, math_text_single_dollar: true, mdx_expression_parse: Some(\"[Function]\"), mdx_esm_parse: Some(\"[Function]\") }",
+ "ParseOptions { constructs: Constructs { attention: true, autolink: true, block_quote: true, character_escape: true, character_reference: true, code_indented: true, code_fenced: true, code_text: true, definition: true, frontmatter: false, wikilink: false, gfm_autolink_literal: false, gfm_footnote_definition: false, gfm_label_start_footnote: false, gfm_strikethrough: false, gfm_table: false, gfm_task_list_item: false, hard_break_escape: true, hard_break_trailing: true, heading_atx: true, heading_setext: true, html_flow: true, html_text: true, label_start_image: true, label_start_link: true, label_end: true, list_item: true, math_flow: false, math_text: false, mdx_esm: false, mdx_expression_flow: false, mdx_expression_text: false, mdx_jsx_flow: false, mdx_jsx_text: false, thematic_break: true }, gfm_strikethrough_single_tilde: true, math_text_single_dollar: true, mdx_expression_parse: Some(\"[Function]\"), mdx_esm_parse: Some(\"[Function]\") }",
"should support `Debug` trait on mdx functions"
);
}
diff --git a/src/construct/mod.rs b/src/construct/mod.rs
index 6098313..8f030b0 100644
--- a/src/construct/mod.rs
+++ b/src/construct/mod.rs
@@ -196,3 +196,5 @@ pub mod raw_text;
pub mod string;
pub mod text;
pub mod thematic_break;
+pub mod wikilink;
+pub mod wikilink_label;
diff --git a/src/construct/text.rs b/src/construct/text.rs
index a461d02..82037b3 100644
--- a/src/construct/text.rs
+++ b/src/construct/text.rs
@@ -138,7 +138,7 @@ pub fn before(tokenizer: &mut Tokenizer) -> State {
Some(b'[') => {
tokenizer.attempt(
State::Next(StateName::TextBefore),
- State::Next(StateName::TextBeforeLabelStartLink),
+ State::Next(StateName::TextBeforeWikilinkStart),
);
State::Retry(StateName::GfmLabelStartFootnoteStart)
}
@@ -215,8 +215,25 @@ pub fn before_hard_break_escape(tokenizer: &mut Tokenizer) -> State {
State::Retry(StateName::HardBreakEscapeStart)
}
+/// Before wikilink start.
+///
+/// At `[`, which wasn’t a GFM label start (footnote).
+///
+/// ```markdown
+/// > | [[a]]
+/// ^
+/// ```
+pub fn before_label_wikilink_start(tokenizer: &mut Tokenizer) -> State {
+ tokenizer.attempt(
+ State::Next(StateName::TextBefore),
+ State::Next(StateName::TextBeforeData),
+ );
+ State::Retry(StateName::WikilinkStart)
+}
+
/// Before label start (link).
///
+///
/// At `[`, which wasn’t a GFM label start (footnote).
///
/// ```markdown
diff --git a/src/construct/wikilink.rs b/src/construct/wikilink.rs
new file mode 100644
index 0000000..929ccd7
--- /dev/null
+++ b/src/construct/wikilink.rs
@@ -0,0 +1,88 @@
+//! wikilink occurs in the [[text]][] content type.
+//!
+//! ## Grammar
+//!
+//! ```bnf
+//! wikilink ::= '[[' label opt_alias opt_heading opt_block ']]'
+//!
+//! opt_alias ::= '|' label | ''
+//! opt_heading ::= '#' label | ''
+//! opt_block ::= '^' label | ''
+//!
+//! ; See the `label` constructs for the BNF of
+//! ; those parts.
+//! ```
+//!
+
+use crate::event::Name;
+use crate::state::Name as MoveName;
+use crate::state::State;
+use crate::tokenizer::{Label, LabelKind, LabelStart, Tokenizer};
+
+/// Start of label (link) start.
+///
+/// ```markdown
+/// > | a [b] c
+/// ^
+/// ```
+pub fn start(tokenizer: &mut Tokenizer) -> State {
+ let start_conditions =
+ tokenizer.parse_state.options.constructs.wikilink && tokenizer.current == Some(b'[');
+
+ if start_conditions && tokenizer.tokenize_state.size == 0 {
+ tokenizer.tokenize_state.size += 1;
+ tokenizer.attempt(State::Next(MoveName::WikilinkStart), State::Nok);
+ tokenizer.consume();
+ return State::Ok;
+ } else if start_conditions && tokenizer.tokenize_state.size == 1 {
+ tokenizer.tokenize_state.size = 0;
+ let start = tokenizer.events.len();
+
+ tokenizer.enter(Name::WikilinkStart);
+ // // tokenizer.enter(Name::LabelMarker);
+ tokenizer.consume();
+ // // tokenizer.exit(Name::LabelMarker);
+ tokenizer.exit(Name::WikilinkStart);
+
+ tokenizer.tokenize_state.wikilink_starts.push(LabelStart {
+ kind: LabelKind::Link,
+ start: (start, tokenizer.events.len()),
+ inactive: false,
+ });
+ State::Next(MoveName::WikilinkLabelStart)
+ } else {
+ tokenizer.tokenize_state.size = 0;
+ State::Nok
+ }
+}
+
+pub fn end(tokenizer: &mut Tokenizer) -> State {
+ if Some(b']') == tokenizer.current
+ && Some(b']') == tokenizer.previous
+ && tokenizer.parse_state.options.constructs.wikilink
+ && !tokenizer.tokenize_state.wikilink_starts.is_empty()
+ {
+ let wikilink_start = tokenizer.tokenize_state.wikilink_starts.last().unwrap();
+ tokenizer.tokenize_state.end = tokenizer.events.len();
+
+ // If the corresponding label (link) start is marked as inactive,
+ // it means we’d be wrapping a link, like this:
+ //
+ // ```markdown
+ // > | a [b [c](d) e](f) g.
+ // ^
+ // ```
+ //
+ // We can’t have that, so it’s just balanced brackets.
+ if wikilink_start.inactive {
+ return State::Retry(MoveName::WikilinkEndNok);
+ }
+
+ tokenizer.enter(Name::WikilinkEnd);
+ tokenizer.consume();
+ tokenizer.exit(Name::WikilinkEnd);
+ return State::Ok;
+ }
+
+ State::Nok
+}
diff --git a/src/construct/wikilink_label.rs b/src/construct/wikilink_label.rs
new file mode 100644
index 0000000..f46510a
--- /dev/null
+++ b/src/construct/wikilink_label.rs
@@ -0,0 +1,152 @@
+use crate::construct::partial_space_or_tab_eol::{space_or_tab_eol_with_options, Options};
+use crate::event::{Content, Link, Name};
+use crate::state::{Name as StateName, State};
+use crate::subtokenize::link;
+use crate::tokenizer::Tokenizer;
+use crate::util::constant::LINK_REFERENCE_SIZE_MAX;
+
+/// Start of label.
+///
+/// ```markdown
+/// > | [a]
+/// ^
+/// ```
+pub fn start(tokenizer: &mut Tokenizer) -> State {
+ State::Retry(StateName::WikilinkLabelAtBreak)
+}
+
+/// In label, at something, before something else.
+///
+/// ```markdown
+/// > | [a]
+/// ^
+/// ```
+pub fn at_break(tokenizer: &mut Tokenizer) -> State {
+ if tokenizer.tokenize_state.size > LINK_REFERENCE_SIZE_MAX || matches!(tokenizer.current, None)
+ {
+ State::Retry(StateName::WikilinkLabelNok)
+ } else {
+ match tokenizer.current {
+ Some(b'\n') => {
+ tokenizer.attempt(
+ State::Next(StateName::WikilinkLabelEolAfter),
+ State::Next(StateName::WikilinkLabelNok),
+ );
+ State::Retry(space_or_tab_eol_with_options(
+ tokenizer,
+ Options {
+ content: Some(Content::String),
+ connect: tokenizer.tokenize_state.connect,
+ },
+ ))
+ }
+
+ Some(b']') if tokenizer.tokenize_state.size_b == 1 => {
+ tokenizer.tokenize_state.size_b = 0;
+ State::Retry(StateName::WikilinkEnd)
+ }
+ _ => {
+ tokenizer.enter_link(
+ Name::Data,
+ Link {
+ previous: None,
+ next: None,
+ content: Content::String,
+ },
+ );
+
+ if tokenizer.tokenize_state.connect {
+ let index = tokenizer.events.len() - 1;
+ link(&mut tokenizer.events, index);
+ } else {
+ tokenizer.tokenize_state.connect = true;
+ }
+
+ State::Retry(StateName::WikilinkLabelInside)
+ }
+ }
+ }
+}
+
+/// In label, after whitespace.
+///
+/// ```markdown
+/// | [a␊
+/// > | b]
+/// ^
+/// ```
+pub fn eol_after(tokenizer: &mut Tokenizer) -> State {
+ tokenizer.tokenize_state.connect = true;
+ State::Retry(StateName::WikilinkLabelAtBreak)
+}
+
+/// In label, on something disallowed.
+///
+/// ```markdown
+/// > | []
+/// ^
+/// ```
+pub fn nok(tokenizer: &mut Tokenizer) -> State {
+ tokenizer.tokenize_state.connect = false;
+ tokenizer.tokenize_state.seen = false;
+ tokenizer.tokenize_state.size = 0;
+ State::Nok
+}
+
+/// In label, in text.
+///
+/// ```markdown
+/// > | [a]
+/// ^
+/// ```
+pub fn inside(tokenizer: &mut Tokenizer) -> State {
+ match tokenizer.current {
+ None | Some(b'\n') => {
+ tokenizer.exit(Name::Data);
+ State::Retry(StateName::WikilinkLabelAtBreak)
+ }
+ Some(b']') => {
+ tokenizer.exit(Name::Data);
+ tokenizer.consume();
+ tokenizer.tokenize_state.size += 1;
+ tokenizer.tokenize_state.size_b = 1;
+ tokenizer.tokenize_state.seen = false; // ??
+
+ State::Next(StateName::WikilinkLabelAtBreak)
+ }
+ Some(byte) => {
+ if tokenizer.tokenize_state.size > LINK_REFERENCE_SIZE_MAX {
+ tokenizer.exit(Name::Data);
+ State::Retry(StateName::WikilinkLabelAtBreak)
+ } else {
+ tokenizer.consume();
+ tokenizer.tokenize_state.size += 1;
+ if !tokenizer.tokenize_state.seen && !matches!(byte, b'\t' | b' ') {
+ tokenizer.tokenize_state.seen = true;
+ }
+ State::Next(if matches!(byte, b'\\') {
+ StateName::WikilinkLabelEscape
+ } else {
+ StateName::WikilinkLabelInside
+ })
+ }
+ }
+ }
+}
+
+/// After `\`, at a special character.
+///
+/// ```markdown
+/// > | [a\*a]
+/// ^
+/// ```
+pub fn escape(tokenizer: &mut Tokenizer) -> State {
+ match tokenizer.current {
+ Some(b'[' | b'\\' | b']') => {
+ tokenizer.consume();
+ tokenizer.tokenize_state.size += 1;
+ State::Next(StateName::WikilinkLabelInside)
+ }
+ _ => State::Retry(StateName::WikilinkLabelInside),
+ }
+}
diff --git a/src/event.rs b/src/event.rs
index 87254f7..3b310f4 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -1907,6 +1907,9 @@ pub enum Name {
/// ^^^^^^^
/// ```
Image,
+ WikilinkText,
+ WikilinkStart,
+ WikilinkEnd,
/// Label.
///
/// ## Info
@@ -3427,6 +3430,9 @@ pub const VOID_EVENTS: [Name; 76] = [
Name::HeadingSetextUnderlineSequence,
Name::HtmlFlowData,
Name::HtmlTextData,
+ // Name::WikilinkStart,
+ // Name::WikilinkStart,
+ // Name::WikilinkEnd,
Name::LabelImageMarker,
Name::LabelMarker,
Name::LineEnding,
diff --git a/src/state.rs b/src/state.rs
index 5e765c7..ef5cb8d 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -153,6 +153,21 @@ pub enum Name {
FrontmatterCloseSequence,
FrontmatterCloseAfter,
+ WikilinkStart,
+ WikilinkAlias,
+ WikilinkHeading,
+ WikilinkBlock,
+ WikilinkEnd,
+ WikilinkEndOk,
+ WikilinkEndNok,
+
+ WikilinkLabelStart,
+ WikilinkLabelAtBreak,
+ WikilinkLabelEolAfter,
+ WikilinkLabelEscape,
+ WikilinkLabelInside,
+ WikilinkLabelNok,
+
GfmAutolinkLiteralProtocolStart,
GfmAutolinkLiteralProtocolAfter,
GfmAutolinkLiteralProtocolPrefixInside,
@@ -451,6 +466,7 @@ pub enum Name {
TextBeforeHtml,
TextBeforeMdxJsx,
TextBeforeHardBreakEscape,
+ TextBeforeWikilinkStart,
TextBeforeLabelStartLink,
TextBeforeData,
@@ -474,7 +490,6 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
let func = match name {
Name::AttentionStart => construct::attention::start,
Name::AttentionInside => construct::attention::inside,
-
Name::AutolinkStart => construct::autolink::start,
Name::AutolinkOpen => construct::autolink::open,
Name::AutolinkSchemeOrEmailAtext => construct::autolink::scheme_or_email_atext,
@@ -484,26 +499,20 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::AutolinkEmailAtext => construct::autolink::email_atext,
Name::AutolinkEmailValue => construct::autolink::email_value,
Name::AutolinkEmailLabel => construct::autolink::email_label,
-
Name::BlankLineStart => construct::blank_line::start,
Name::BlankLineAfter => construct::blank_line::after,
-
Name::BlockQuoteStart => construct::block_quote::start,
Name::BlockQuoteContStart => construct::block_quote::cont_start,
Name::BlockQuoteContBefore => construct::block_quote::cont_before,
Name::BlockQuoteContAfter => construct::block_quote::cont_after,
-
Name::BomStart => construct::partial_bom::start,
Name::BomInside => construct::partial_bom::inside,
-
Name::CharacterEscapeStart => construct::character_escape::start,
Name::CharacterEscapeInside => construct::character_escape::inside,
-
Name::CharacterReferenceStart => construct::character_reference::start,
Name::CharacterReferenceOpen => construct::character_reference::open,
Name::CharacterReferenceNumeric => construct::character_reference::numeric,
Name::CharacterReferenceValue => construct::character_reference::value,
-
Name::CodeIndentedStart => construct::code_indented::start,
Name::CodeIndentedAtBreak => construct::code_indented::at_break,
Name::CodeIndentedAfter => construct::code_indented::after,
@@ -511,16 +520,13 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::CodeIndentedInside => construct::code_indented::inside,
Name::CodeIndentedFurtherBegin => construct::code_indented::further_begin,
Name::CodeIndentedFurtherAfter => construct::code_indented::further_after,
-
Name::ContentChunkStart => construct::content::chunk_start,
Name::ContentChunkInside => construct::content::chunk_inside,
Name::ContentDefinitionBefore => construct::content::definition_before,
Name::ContentDefinitionAfter => construct::content::definition_after,
-
Name::DataStart => construct::partial_data::start,
Name::DataInside => construct::partial_data::inside,
Name::DataAtBreak => construct::partial_data::at_break,
-
Name::DefinitionStart => construct::definition::start,
Name::DefinitionBefore => construct::definition::before,
Name::DefinitionLabelAfter => construct::definition::label_after,
@@ -537,14 +543,12 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::DefinitionTitleAfterOptionalWhitespace => {
construct::definition::title_after_optional_whitespace
}
-
Name::DestinationStart => construct::partial_destination::start,
Name::DestinationEnclosedBefore => construct::partial_destination::enclosed_before,
Name::DestinationEnclosed => construct::partial_destination::enclosed,
Name::DestinationEnclosedEscape => construct::partial_destination::enclosed_escape,
Name::DestinationRaw => construct::partial_destination::raw,
Name::DestinationRawEscape => construct::partial_destination::raw_escape,
-
Name::DocumentStart => construct::document::start,
Name::DocumentBeforeFrontmatter => construct::document::before_frontmatter,
Name::DocumentContainerExistingBefore => construct::document::container_existing_before,
@@ -563,7 +567,6 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::DocumentContainersAfter => construct::document::containers_after,
Name::DocumentFlowEnd => construct::document::flow_end,
Name::DocumentFlowInside => construct::document::flow_inside,
-
Name::FlowStart => construct::flow::start,
Name::FlowBeforeGfmTable => construct::flow::before_gfm_table,
Name::FlowBeforeCodeIndented => construct::flow::before_code_indented,
@@ -578,7 +581,6 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::FlowBlankLineBefore => construct::flow::blank_line_before,
Name::FlowBlankLineAfter => construct::flow::blank_line_after,
Name::FlowBeforeContent => construct::flow::before_content,
-
Name::FrontmatterStart => construct::frontmatter::start,
Name::FrontmatterOpenSequence => construct::frontmatter::open_sequence,
Name::FrontmatterOpenAfter => construct::frontmatter::open_after,
@@ -589,7 +591,8 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::FrontmatterCloseStart => construct::frontmatter::close_start,
Name::FrontmatterCloseSequence => construct::frontmatter::close_sequence,
Name::FrontmatterCloseAfter => construct::frontmatter::close_after,
-
+ Name::WikilinkStart => construct::wikilink::start,
+ Name::WikilinkEnd => construct::wikilink::end,
Name::GfmAutolinkLiteralProtocolStart => construct::gfm_autolink_literal::protocol_start,
Name::GfmAutolinkLiteralProtocolAfter => construct::gfm_autolink_literal::protocol_after,
Name::GfmAutolinkLiteralProtocolPrefixInside => {
@@ -624,7 +627,6 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::GfmAutolinkLiteralTrailBracketAfter => {
construct::gfm_autolink_literal::trail_bracket_after
}
-
Name::GfmFootnoteDefinitionStart => construct::gfm_footnote_definition::start,
Name::GfmFootnoteDefinitionLabelBefore => construct::gfm_footnote_definition::label_before,
Name::GfmFootnoteDefinitionLabelAtMarker => {
@@ -639,10 +641,8 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::GfmFootnoteDefinitionContStart => construct::gfm_footnote_definition::cont_start,
Name::GfmFootnoteDefinitionContBlank => construct::gfm_footnote_definition::cont_blank,
Name::GfmFootnoteDefinitionContFilled => construct::gfm_footnote_definition::cont_filled,
-
Name::GfmLabelStartFootnoteStart => construct::gfm_label_start_footnote::start,
Name::GfmLabelStartFootnoteOpen => construct::gfm_label_start_footnote::open,
-
Name::GfmTableStart => construct::gfm_table::start,
Name::GfmTableHeadRowBefore => construct::gfm_table::head_row_before,
Name::GfmTableHeadRowStart => construct::gfm_table::head_row_start,
@@ -666,7 +666,6 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::GfmTableBodyRowBreak => construct::gfm_table::body_row_break,
Name::GfmTableBodyRowData => construct::gfm_table::body_row_data,
Name::GfmTableBodyRowEscape => construct::gfm_table::body_row_escape,
-
Name::GfmTaskListItemCheckStart => construct::gfm_task_list_item_check::start,
Name::GfmTaskListItemCheckInside => construct::gfm_task_list_item_check::inside,
Name::GfmTaskListItemCheckClose => construct::gfm_task_list_item_check::close,
@@ -674,22 +673,18 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::GfmTaskListItemCheckAfterSpaceOrTab => {
construct::gfm_task_list_item_check::after_space_or_tab
}
-
Name::HardBreakEscapeStart => construct::hard_break_escape::start,
Name::HardBreakEscapeAfter => construct::hard_break_escape::after,
-
Name::HeadingAtxStart => construct::heading_atx::start,
Name::HeadingAtxBefore => construct::heading_atx::before,
Name::HeadingAtxSequenceOpen => construct::heading_atx::sequence_open,
Name::HeadingAtxAtBreak => construct::heading_atx::at_break,
Name::HeadingAtxSequenceFurther => construct::heading_atx::sequence_further,
Name::HeadingAtxData => construct::heading_atx::data,
-
Name::HeadingSetextStart => construct::heading_setext::start,
Name::HeadingSetextBefore => construct::heading_setext::before,
Name::HeadingSetextInside => construct::heading_setext::inside,
Name::HeadingSetextAfter => construct::heading_setext::after,
-
Name::HtmlFlowStart => construct::html_flow::start,
Name::HtmlFlowBefore => construct::html_flow::before,
Name::HtmlFlowOpen => construct::html_flow::open,
@@ -737,7 +732,6 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::HtmlFlowContinuationClose => construct::html_flow::continuation_close,
Name::HtmlFlowContinuationCdataInside => construct::html_flow::continuation_cdata_inside,
Name::HtmlFlowContinuationStartNonLazy => construct::html_flow::continuation_start_non_lazy,
-
Name::HtmlTextStart => construct::html_text::start,
Name::HtmlTextOpen => construct::html_text::open,
Name::HtmlTextDeclarationOpen => construct::html_text::declaration_open,
@@ -777,14 +771,12 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::HtmlTextLineEndingBefore => construct::html_text::line_ending_before,
Name::HtmlTextLineEndingAfter => construct::html_text::line_ending_after,
Name::HtmlTextLineEndingAfterPrefix => construct::html_text::line_ending_after_prefix,
-
Name::LabelStart => construct::partial_label::start,
Name::LabelAtBreak => construct::partial_label::at_break,
Name::LabelEolAfter => construct::partial_label::eol_after,
Name::LabelEscape => construct::partial_label::escape,
Name::LabelInside => construct::partial_label::inside,
Name::LabelNok => construct::partial_label::nok,
-
Name::LabelEndStart => construct::label_end::start,
Name::LabelEndAfter => construct::label_end::after,
Name::LabelEndResourceStart => construct::label_end::resource_start,
@@ -805,12 +797,10 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::LabelEndReferenceNotFull => construct::label_end::reference_not_full,
Name::LabelEndReferenceCollapsed => construct::label_end::reference_collapsed,
Name::LabelEndReferenceCollapsedOpen => construct::label_end::reference_collapsed_open,
-
Name::LabelStartImageStart => construct::label_start_image::start,
Name::LabelStartImageOpen => construct::label_start_image::open,
Name::LabelStartImageAfter => construct::label_start_image::after,
Name::LabelStartLinkStart => construct::label_start_link::start,
-
Name::ListItemStart => construct::list_item::start,
Name::ListItemBefore => construct::list_item::before,
Name::ListItemBeforeOrdered => construct::list_item::before_ordered,
@@ -826,7 +816,6 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::ListItemContStart => construct::list_item::cont_start,
Name::ListItemContBlank => construct::list_item::cont_blank,
Name::ListItemContFilled => construct::list_item::cont_filled,
-
Name::MdxEsmStart => construct::mdx_esm::start,
Name::MdxEsmWord => construct::mdx_esm::word,
Name::MdxEsmInside => construct::mdx_esm::inside,
@@ -834,31 +823,25 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::MdxEsmBlankLineBefore => construct::mdx_esm::blank_line_before,
Name::MdxEsmContinuationStart => construct::mdx_esm::continuation_start,
Name::MdxEsmAtEnd => construct::mdx_esm::at_end,
-
Name::MdxExpressionStart => construct::partial_mdx_expression::start,
Name::MdxExpressionPrefix => construct::partial_mdx_expression::prefix,
Name::MdxExpressionBefore => construct::partial_mdx_expression::before,
Name::MdxExpressionInside => construct::partial_mdx_expression::inside,
Name::MdxExpressionEolAfter => construct::partial_mdx_expression::eol_after,
-
Name::MdxExpressionFlowStart => construct::mdx_expression_flow::start,
Name::MdxExpressionFlowBefore => construct::mdx_expression_flow::before,
Name::MdxExpressionFlowAfter => construct::mdx_expression_flow::after,
Name::MdxExpressionFlowEnd => construct::mdx_expression_flow::end,
-
Name::MdxExpressionTextStart => construct::mdx_expression_text::start,
Name::MdxExpressionTextAfter => construct::mdx_expression_text::after,
-
Name::MdxJsxFlowStart => construct::mdx_jsx_flow::start,
Name::MdxJsxFlowBefore => construct::mdx_jsx_flow::before,
Name::MdxJsxFlowAfter => construct::mdx_jsx_flow::after,
Name::MdxJsxFlowEnd => construct::mdx_jsx_flow::end,
Name::MdxJsxFlowNok => construct::mdx_jsx_flow::nok,
-
Name::MdxJsxTextStart => construct::mdx_jsx_text::start,
Name::MdxJsxTextAfter => construct::mdx_jsx_text::after,
Name::MdxJsxTextNok => construct::mdx_jsx_text::nok,
-
Name::MdxJsxStart => construct::partial_mdx_jsx::start,
Name::MdxJsxStartAfter => construct::partial_mdx_jsx::start_after,
Name::MdxJsxNameBefore => construct::partial_mdx_jsx::name_before,
@@ -899,14 +882,11 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::MdxJsxEsWhitespaceStart => construct::partial_mdx_jsx::es_whitespace_start,
Name::MdxJsxEsWhitespaceInside => construct::partial_mdx_jsx::es_whitespace_inside,
Name::MdxJsxEsWhitespaceEolAfter => construct::partial_mdx_jsx::es_whitespace_eol_after,
-
Name::NonLazyContinuationStart => construct::partial_non_lazy_continuation::start,
Name::NonLazyContinuationAfter => construct::partial_non_lazy_continuation::after,
-
Name::ParagraphStart => construct::paragraph::start,
Name::ParagraphLineStart => construct::paragraph::line_start,
Name::ParagraphInside => construct::paragraph::inside,
-
Name::RawFlowStart => construct::raw_flow::start,
Name::RawFlowBeforeSequenceOpen => construct::raw_flow::before_sequence_open,
Name::RawFlowSequenceOpen => construct::raw_flow::sequence_open,
@@ -924,40 +904,34 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::RawFlowBeforeContentChunk => construct::raw_flow::before_content_chunk,
Name::RawFlowContentChunk => construct::raw_flow::content_chunk,
Name::RawFlowAfter => construct::raw_flow::after,
-
Name::RawTextStart => construct::raw_text::start,
Name::RawTextSequenceOpen => construct::raw_text::sequence_open,
Name::RawTextBetween => construct::raw_text::between,
Name::RawTextData => construct::raw_text::data,
Name::RawTextSequenceClose => construct::raw_text::sequence_close,
-
Name::SpaceOrTabStart => construct::partial_space_or_tab::start,
Name::SpaceOrTabInside => construct::partial_space_or_tab::inside,
Name::SpaceOrTabAfter => construct::partial_space_or_tab::after,
-
Name::SpaceOrTabEolStart => construct::partial_space_or_tab_eol::start,
Name::SpaceOrTabEolAfterFirst => construct::partial_space_or_tab_eol::after_first,
Name::SpaceOrTabEolAfterEol => construct::partial_space_or_tab_eol::after_eol,
Name::SpaceOrTabEolAtEol => construct::partial_space_or_tab_eol::at_eol,
Name::SpaceOrTabEolAfterMore => construct::partial_space_or_tab_eol::after_more,
-
Name::StringStart => construct::string::start,
Name::StringBefore => construct::string::before,
Name::StringBeforeData => construct::string::before_data,
-
Name::TextStart => construct::text::start,
Name::TextBefore => construct::text::before,
Name::TextBeforeHtml => construct::text::before_html,
Name::TextBeforeMdxJsx => construct::text::before_mdx_jsx,
Name::TextBeforeHardBreakEscape => construct::text::before_hard_break_escape,
+ Name::TextBeforeWikilinkStart => construct::text::before_label_wikilink_start,
Name::TextBeforeLabelStartLink => construct::text::before_label_start_link,
Name::TextBeforeData => construct::text::before_data,
-
Name::ThematicBreakStart => construct::thematic_break::start,
Name::ThematicBreakBefore => construct::thematic_break::before,
Name::ThematicBreakSequence => construct::thematic_break::sequence,
Name::ThematicBreakAtBreak => construct::thematic_break::at_break,
-
Name::TitleStart => construct::partial_title::start,
Name::TitleBegin => construct::partial_title::begin,
Name::TitleAfterEol => construct::partial_title::after_eol,
@@ -965,6 +939,17 @@ pub fn call(tokenizer: &mut Tokenizer, name: Name) -> State {
Name::TitleEscape => construct::partial_title::escape,
Name::TitleInside => construct::partial_title::inside,
Name::TitleNok => construct::partial_title::nok,
+ Name::WikilinkAlias => todo!(),
+ Name::WikilinkHeading => todo!(),
+ Name::WikilinkBlock => todo!(),
+ Name::WikilinkEndOk => todo!(),
+ Name::WikilinkEndNok => todo!(),
+ Name::WikilinkLabelStart => construct::wikilink_label::start,
+ Name::WikilinkLabelAtBreak => construct::wikilink_label::at_break,
+ Name::WikilinkLabelEolAfter => construct::wikilink_label::eol_after,
+ Name::WikilinkLabelEscape => construct::wikilink_label::escape,
+ Name::WikilinkLabelInside => construct::wikilink_label::inside,
+ Name::WikilinkLabelNok => construct::wikilink_label::nok,
};
func(tokenizer)
diff --git a/src/to_html.rs b/src/to_html.rs
index b50ec91..b563c71 100644
--- a/src/to_html.rs
+++ b/src/to_html.rs
@@ -350,6 +350,7 @@ fn enter(context: &mut CompileContext) {
Name::HtmlText => on_enter_html_text(context),
Name::Image => on_enter_image(context),
Name::Link => on_enter_link(context),
+ Name::WikilinkStart => on_enter_wikilink(context),
Name::ListItemMarker => on_enter_list_item_marker(context),
Name::ListOrdered | Name::ListUnordered => on_enter_list(context),
Name::Paragraph => on_enter_paragraph(context),
@@ -425,6 +426,7 @@ fn exit(context: &mut CompileContext) {
Name::HtmlFlow | Name::HtmlText => on_exit_html(context),
Name::HtmlFlowData | Name::HtmlTextData => on_exit_html_data(context),
Name::Image | Name::Link => on_exit_media(context),
+ Name::WikilinkEnd => on_exit_wikilink(context),
Name::Label => on_exit_label(context),
Name::LabelText => on_exit_label_text(context),
Name::LineEnding => on_exit_line_ending(context),
@@ -648,6 +650,19 @@ fn on_enter_link(context: &mut CompileContext) {
});
}
+/// Handle [`Enter`][Kind::Enter]:[`Link`][Name::WikilinkStart].
+fn on_enter_wikilink(context: &mut CompileContext) {
+ if !context.image_alt_inside {
+ context.push("");
+ }
+}
+
+fn on_exit_wikilink(context: &mut CompileContext) {
+ if !context.image_alt_inside {
+ context.push("");
+ }
+}
+
/// Handle [`Enter`][Kind::Enter]:{[`ListOrdered`][Name::ListOrdered],[`ListUnordered`][Name::ListUnordered]}.
fn on_enter_list(context: &mut CompileContext) {
let loose = list_loose(context.events, context.index, true);
diff --git a/src/tokenizer.rs b/src/tokenizer.rs
index b30098c..584cc76 100644
--- a/src/tokenizer.rs
+++ b/src/tokenizer.rs
@@ -213,6 +213,9 @@ pub struct TokenizeState<'a> {
pub space_or_tab_size: usize,
pub space_or_tab_token: Name,
+ pub wikilinks: Vec