inline: parse multi-line link tags/urls
reimplement after broken by "take str per line instead of full inline iter" commit this also resolves #22
This commit is contained in:
parent
98f3fe5c7c
commit
a846477cea
3 changed files with 149 additions and 83 deletions
190
src/inline.rs
190
src/inline.rs
|
@ -1,5 +1,6 @@
|
||||||
use crate::attr;
|
use crate::attr;
|
||||||
use crate::lex;
|
use crate::lex;
|
||||||
|
use crate::CowStr;
|
||||||
use crate::Span;
|
use crate::Span;
|
||||||
|
|
||||||
use lex::Delimiter;
|
use lex::Delimiter;
|
||||||
|
@ -23,8 +24,8 @@ pub enum Atom {
|
||||||
Quote { ty: QuoteType, left: bool },
|
Quote { ty: QuoteType, left: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Container {
|
pub enum Container<'s> {
|
||||||
Span,
|
Span,
|
||||||
Subscript,
|
Subscript,
|
||||||
Superscript,
|
Superscript,
|
||||||
|
@ -38,14 +39,10 @@ pub enum Container {
|
||||||
RawFormat,
|
RawFormat,
|
||||||
InlineMath,
|
InlineMath,
|
||||||
DisplayMath,
|
DisplayMath,
|
||||||
/// Span is the reference link tag.
|
ReferenceLink(CowStr<'s>),
|
||||||
ReferenceLink,
|
ReferenceImage(CowStr<'s>),
|
||||||
/// Span is the reference link tag.
|
InlineLink(CowStr<'s>),
|
||||||
ReferenceImage,
|
InlineImage(CowStr<'s>),
|
||||||
/// Span is the URL.
|
|
||||||
InlineLink,
|
|
||||||
/// Span is the URL.
|
|
||||||
InlineImage,
|
|
||||||
/// Open delimiter span is URL, closing is '>'.
|
/// Open delimiter span is URL, closing is '>'.
|
||||||
Autolink,
|
Autolink,
|
||||||
}
|
}
|
||||||
|
@ -57,9 +54,9 @@ pub enum QuoteType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum EventKind {
|
pub enum EventKind<'s> {
|
||||||
Enter(Container),
|
Enter(Container<'s>),
|
||||||
Exit(Container),
|
Exit(Container<'s>),
|
||||||
Atom(Atom),
|
Atom(Atom),
|
||||||
Str,
|
Str,
|
||||||
Attributes { container: bool },
|
Attributes { container: bool },
|
||||||
|
@ -67,8 +64,8 @@ pub enum EventKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Event {
|
pub struct Event<'s> {
|
||||||
pub kind: EventKind,
|
pub kind: EventKind<'s>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +76,8 @@ struct Input<'s> {
|
||||||
lexer: lex::Lexer<'s>,
|
lexer: lex::Lexer<'s>,
|
||||||
/// The block is complete, the final line has been provided.
|
/// The block is complete, the final line has been provided.
|
||||||
complete: bool,
|
complete: bool,
|
||||||
|
/// Span of current line.
|
||||||
|
span_line: Span,
|
||||||
/// Span of current event.
|
/// Span of current event.
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
@ -89,6 +88,7 @@ impl<'s> Input<'s> {
|
||||||
src,
|
src,
|
||||||
lexer: lex::Lexer::new(""),
|
lexer: lex::Lexer::new(""),
|
||||||
complete: false,
|
complete: false,
|
||||||
|
span_line: Span::new(0, 0),
|
||||||
span: Span::empty_at(0),
|
span: Span::empty_at(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,7 @@ impl<'s> Input<'s> {
|
||||||
debug_assert!(!self.complete);
|
debug_assert!(!self.complete);
|
||||||
self.lexer = lex::Lexer::new(line.of(self.src));
|
self.lexer = lex::Lexer::new(line.of(self.src));
|
||||||
self.complete = last;
|
self.complete = last;
|
||||||
|
self.span_line = line;
|
||||||
self.span = line.empty_before();
|
self.span = line.empty_before();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +193,7 @@ pub struct Parser<'s> {
|
||||||
openers: Vec<(Opener, usize)>,
|
openers: Vec<(Opener, usize)>,
|
||||||
/// Buffer queue for next events. Events are buffered until no modifications due to future
|
/// Buffer queue for next events. Events are buffered until no modifications due to future
|
||||||
/// characters are needed.
|
/// characters are needed.
|
||||||
events: std::collections::VecDeque<Event>,
|
events: std::collections::VecDeque<Event<'s>>,
|
||||||
/// State if inside a verbatim container.
|
/// State if inside a verbatim container.
|
||||||
verbatim: Option<VerbatimState>,
|
verbatim: Option<VerbatimState>,
|
||||||
}
|
}
|
||||||
|
@ -219,12 +220,12 @@ impl<'s> Parser<'s> {
|
||||||
debug_assert!(self.verbatim.is_none());
|
debug_assert!(self.verbatim.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_sp(&mut self, kind: EventKind, span: Span) -> Option<()> {
|
fn push_sp(&mut self, kind: EventKind<'s>, span: Span) -> Option<()> {
|
||||||
self.events.push_back(Event { kind, span });
|
self.events.push_back(Event { kind, span });
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, kind: EventKind) -> Option<()> {
|
fn push(&mut self, kind: EventKind<'s>) -> Option<()> {
|
||||||
self.push_sp(kind, self.input.span)
|
self.push_sp(kind, self.input.span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,12 +275,12 @@ impl<'s> Parser<'s> {
|
||||||
}
|
}
|
||||||
self.input.span = span_attr;
|
self.input.span = span_attr;
|
||||||
};
|
};
|
||||||
let ty_opener = if let EventKind::Enter(ty) = self.events[event_opener].kind {
|
let ty_opener = if let EventKind::Enter(ty) = &self.events[event_opener].kind {
|
||||||
debug_assert!(matches!(
|
debug_assert!(matches!(
|
||||||
ty,
|
ty,
|
||||||
Verbatim | RawFormat | InlineMath | DisplayMath
|
Verbatim | RawFormat | InlineMath | DisplayMath
|
||||||
));
|
));
|
||||||
ty
|
ty.clone()
|
||||||
} else {
|
} else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
@ -504,7 +505,7 @@ impl<'s> Parser<'s> {
|
||||||
self.openers.drain(o..);
|
self.openers.drain(o..);
|
||||||
let mut closed = match DelimEventKind::from(opener) {
|
let mut closed = match DelimEventKind::from(opener) {
|
||||||
DelimEventKind::Container(cont) => {
|
DelimEventKind::Container(cont) => {
|
||||||
self.events[e_opener].kind = EventKind::Enter(cont);
|
self.events[e_opener].kind = EventKind::Enter(cont.clone());
|
||||||
self.push(EventKind::Exit(cont))
|
self.push(EventKind::Exit(cont))
|
||||||
}
|
}
|
||||||
DelimEventKind::Quote(ty) => {
|
DelimEventKind::Quote(ty) => {
|
||||||
|
@ -536,26 +537,79 @@ impl<'s> Parser<'s> {
|
||||||
image,
|
image,
|
||||||
} => {
|
} => {
|
||||||
let span_spec = self.events[e_opener].span.between(self.input.span);
|
let span_spec = self.events[e_opener].span.between(self.input.span);
|
||||||
let span_spec = if !inline && span_spec.is_empty() {
|
let multiline =
|
||||||
self.events[event_span]
|
self.events[e_opener].span.start() < self.input.span_line.start();
|
||||||
|
|
||||||
|
let spec: CowStr = if span_spec.is_empty() && !inline {
|
||||||
|
let span_spec = self.events[event_span]
|
||||||
.span
|
.span
|
||||||
.between(self.events[e_opener - 1].span)
|
.between(self.events[e_opener - 1].span);
|
||||||
|
let events_text = self
|
||||||
|
.events
|
||||||
|
.iter()
|
||||||
|
.skip(event_span + 1)
|
||||||
|
.take(e_opener - event_span - 2);
|
||||||
|
|
||||||
|
if multiline
|
||||||
|
|| events_text.clone().any(|ev| {
|
||||||
|
!matches!(ev.kind, EventKind::Str | EventKind::Atom(..))
|
||||||
|
})
|
||||||
|
{
|
||||||
|
events_text
|
||||||
|
.filter(|ev| {
|
||||||
|
matches!(ev.kind, EventKind::Str | EventKind::Atom(..))
|
||||||
|
})
|
||||||
|
.map(|ev| ev.span.of(self.input.src))
|
||||||
|
.collect::<String>()
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
span_spec.of(self.input.src).into()
|
||||||
|
}
|
||||||
|
} else if multiline {
|
||||||
|
let mut spec = String::new();
|
||||||
|
let mut first_part = true;
|
||||||
|
let mut span = self.events[e_opener].span.empty_after();
|
||||||
|
|
||||||
|
let mut append = |span: Span| {
|
||||||
|
span.of(self.input.src).split('\n').for_each(|s| {
|
||||||
|
if !s.is_empty() {
|
||||||
|
if !inline && !first_part {
|
||||||
|
spec.push(' ');
|
||||||
|
}
|
||||||
|
spec.push_str(s);
|
||||||
|
first_part = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
for ev in self.events.iter().skip(e_opener + 1) {
|
||||||
|
if span.end() == ev.span.start() {
|
||||||
|
span = Span::new(span.start(), ev.span.end());
|
||||||
|
} else {
|
||||||
|
append(span);
|
||||||
|
span = ev.span;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
append(span);
|
||||||
|
|
||||||
|
spec.into()
|
||||||
} else {
|
} else {
|
||||||
span_spec
|
span_spec.of(self.input.src).into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let container = match (image, inline) {
|
let container = match (image, inline) {
|
||||||
(false, false) => ReferenceLink,
|
(false, false) => ReferenceLink(spec.into()),
|
||||||
(false, true) => InlineLink,
|
(false, true) => InlineLink(spec.into()),
|
||||||
(true, false) => ReferenceImage,
|
(true, false) => ReferenceImage(spec.into()),
|
||||||
(true, true) => InlineImage,
|
(true, true) => InlineImage(spec.into()),
|
||||||
};
|
|
||||||
self.events[event_span] = Event {
|
|
||||||
kind: EventKind::Enter(container),
|
|
||||||
span: span_spec,
|
|
||||||
};
|
};
|
||||||
|
self.events[event_span].kind = EventKind::Enter(container.clone());
|
||||||
self.events[e_opener - 1] = Event {
|
self.events[e_opener - 1] = Event {
|
||||||
kind: EventKind::Exit(container),
|
kind: EventKind::Exit(container),
|
||||||
span: span_spec,
|
span: Span::new(
|
||||||
|
self.events[e_opener - 1].span.start(),
|
||||||
|
span_spec.end() + 1,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
self.events.drain(e_opener..);
|
self.events.drain(e_opener..);
|
||||||
Some(())
|
Some(())
|
||||||
|
@ -687,7 +741,7 @@ impl<'s> Parser<'s> {
|
||||||
self.push(EventKind::Atom(atom))
|
self.push(EventKind::Atom(atom))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_str_events(&mut self, span_str: Span) -> Event {
|
fn merge_str_events(&mut self, span_str: Span) -> Event<'s> {
|
||||||
let mut span = span_str;
|
let mut span = span_str;
|
||||||
let should_merge = |e: &Event, span: Span| {
|
let should_merge = |e: &Event, span: Span| {
|
||||||
matches!(e.kind, EventKind::Str | EventKind::Placeholder)
|
matches!(e.kind, EventKind::Str | EventKind::Placeholder)
|
||||||
|
@ -711,7 +765,7 @@ impl<'s> Parser<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_word_attributes(&mut self, span_str: Span) -> Event {
|
fn apply_word_attributes(&mut self, span_str: Span) -> Event<'s> {
|
||||||
if let Some(i) = span_str
|
if let Some(i) = span_str
|
||||||
.of(self.input.src)
|
.of(self.input.src)
|
||||||
.bytes()
|
.bytes()
|
||||||
|
@ -848,8 +902,8 @@ impl Opener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DelimEventKind {
|
enum DelimEventKind<'s> {
|
||||||
Container(Container),
|
Container(Container<'s>),
|
||||||
Span(SpanType),
|
Span(SpanType),
|
||||||
Quote(QuoteType),
|
Quote(QuoteType),
|
||||||
Link {
|
Link {
|
||||||
|
@ -859,7 +913,7 @@ enum DelimEventKind {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Opener> for DelimEventKind {
|
impl<'s> From<Opener> for DelimEventKind<'s> {
|
||||||
fn from(d: Opener) -> Self {
|
fn from(d: Opener) -> Self {
|
||||||
match d {
|
match d {
|
||||||
Opener::Span(ty) => Self::Span(ty),
|
Opener::Span(ty) => Self::Span(ty),
|
||||||
|
@ -886,7 +940,7 @@ impl From<Opener> for DelimEventKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'s> Iterator for Parser<'s> {
|
impl<'s> Iterator for Parser<'s> {
|
||||||
type Item = Event;
|
type Item = Event<'s>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
while self.events.is_empty()
|
while self.events.is_empty()
|
||||||
|
@ -908,12 +962,12 @@ impl<'s> Iterator for Parser<'s> {
|
||||||
|
|
||||||
// automatically close unclosed verbatim
|
// automatically close unclosed verbatim
|
||||||
if let Some(VerbatimState { event_opener, .. }) = self.verbatim.take() {
|
if let Some(VerbatimState { event_opener, .. }) = self.verbatim.take() {
|
||||||
let ty_opener = if let EventKind::Enter(ty) = self.events[event_opener].kind {
|
let ty_opener = if let EventKind::Enter(ty) = &self.events[event_opener].kind {
|
||||||
debug_assert!(matches!(
|
debug_assert!(matches!(
|
||||||
ty,
|
ty,
|
||||||
Verbatim | RawFormat | InlineMath | DisplayMath
|
Verbatim | RawFormat | InlineMath | DisplayMath
|
||||||
));
|
));
|
||||||
ty
|
ty.clone()
|
||||||
} else {
|
} else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
@ -1109,31 +1163,31 @@ mod test {
|
||||||
fn span_tag() {
|
fn span_tag() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"[text][tag]",
|
"[text][tag]",
|
||||||
(Enter(ReferenceLink), "tag"),
|
(Enter(ReferenceLink("tag".into())), "["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(ReferenceLink), "tag"),
|
(Exit(ReferenceLink("tag".into())), "][tag]"),
|
||||||
);
|
);
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"![text][tag]",
|
"![text][tag]",
|
||||||
(Enter(ReferenceImage), "tag"),
|
(Enter(ReferenceImage("tag".into())), "!["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(ReferenceImage), "tag"),
|
(Exit(ReferenceImage("tag".into())), "][tag]"),
|
||||||
);
|
);
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"before [text][tag] after",
|
"before [text][tag] after",
|
||||||
(Str, "before "),
|
(Str, "before "),
|
||||||
(Enter(ReferenceLink), "tag"),
|
(Enter(ReferenceLink("tag".into())), "["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(ReferenceLink), "tag"),
|
(Exit(ReferenceLink("tag".into())), "][tag]"),
|
||||||
(Str, " after"),
|
(Str, " after"),
|
||||||
);
|
);
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"[[inner][i]][o]",
|
"[[inner][i]][o]",
|
||||||
(Enter(ReferenceLink), "o"),
|
(Enter(ReferenceLink("o".into())), "["),
|
||||||
(Enter(ReferenceLink), "i"),
|
(Enter(ReferenceLink("i".into())), "["),
|
||||||
(Str, "inner"),
|
(Str, "inner"),
|
||||||
(Exit(ReferenceLink), "i"),
|
(Exit(ReferenceLink("i".into())), "][i]"),
|
||||||
(Exit(ReferenceLink), "o"),
|
(Exit(ReferenceLink("o".into())), "][o]"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1141,15 +1195,15 @@ mod test {
|
||||||
fn span_tag_empty() {
|
fn span_tag_empty() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"[text][]",
|
"[text][]",
|
||||||
(Enter(ReferenceLink), "text"),
|
(Enter(ReferenceLink("text".into())), "["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(ReferenceLink), "text"),
|
(Exit(ReferenceLink("text".into())), "][]"),
|
||||||
);
|
);
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"![text][]",
|
"![text][]",
|
||||||
(Enter(ReferenceImage), "text"),
|
(Enter(ReferenceImage("text".into())), "!["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(ReferenceImage), "text"),
|
(Exit(ReferenceImage("text".into())), "][]"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1158,12 +1212,12 @@ mod test {
|
||||||
// TODO strip non str from tag?
|
// TODO strip non str from tag?
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"[some _text_][]",
|
"[some _text_][]",
|
||||||
(Enter(ReferenceLink), "some _text_"),
|
(Enter(ReferenceLink("some text".into())), "["),
|
||||||
(Str, "some "),
|
(Str, "some "),
|
||||||
(Enter(Emphasis), "_"),
|
(Enter(Emphasis), "_"),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(Emphasis), "_"),
|
(Exit(Emphasis), "_"),
|
||||||
(Exit(ReferenceLink), "some _text_"),
|
(Exit(ReferenceLink("some text".into())), "][]"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1172,19 +1226,19 @@ mod test {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"before [text](url) after",
|
"before [text](url) after",
|
||||||
(Str, "before "),
|
(Str, "before "),
|
||||||
(Enter(InlineLink), "url"),
|
(Enter(InlineLink("url".into())), "["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(InlineLink), "url"),
|
(Exit(InlineLink("url".into())), "](url)"),
|
||||||
(Str, " after"),
|
(Str, " after"),
|
||||||
);
|
);
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"[outer [inner](i)](o)",
|
"[outer [inner](i)](o)",
|
||||||
(Enter(InlineLink), "o"),
|
(Enter(InlineLink("o".into())), "["),
|
||||||
(Str, "outer "),
|
(Str, "outer "),
|
||||||
(Enter(InlineLink), "i"),
|
(Enter(InlineLink("i".into())), "["),
|
||||||
(Str, "inner"),
|
(Str, "inner"),
|
||||||
(Exit(InlineLink), "i"),
|
(Exit(InlineLink("i".into())), "](i)"),
|
||||||
(Exit(InlineLink), "o"),
|
(Exit(InlineLink("o".into())), "](o)"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1203,9 +1257,9 @@ mod test {
|
||||||
fn span_url_attr_closed() {
|
fn span_url_attr_closed() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"[text]({.cls})",
|
"[text]({.cls})",
|
||||||
(Enter(InlineLink), "{.cls}"),
|
(Enter(InlineLink("{.cls}".into())), "["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(InlineLink), "{.cls}"),
|
(Exit(InlineLink("{.cls}".into())), "]({.cls})"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1214,9 +1268,9 @@ mod test {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"before [text]() after",
|
"before [text]() after",
|
||||||
(Str, "before "),
|
(Str, "before "),
|
||||||
(Enter(InlineLink), ""),
|
(Enter(InlineLink("".into())), "["),
|
||||||
(Str, "text"),
|
(Str, "text"),
|
||||||
(Exit(InlineLink), ""),
|
(Exit(InlineLink("".into())), "]()"),
|
||||||
(Str, " after"),
|
(Str, " after"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
41
src/lib.rs
41
src/lib.rs
|
@ -830,16 +830,14 @@ impl<'s> Parser<'s> {
|
||||||
inline::Container::Emphasis => Container::Emphasis,
|
inline::Container::Emphasis => Container::Emphasis,
|
||||||
inline::Container::Strong => Container::Strong,
|
inline::Container::Strong => Container::Strong,
|
||||||
inline::Container::Mark => Container::Mark,
|
inline::Container::Mark => Container::Mark,
|
||||||
inline::Container::InlineLink => Container::Link(
|
inline::Container::InlineLink(url) => {
|
||||||
inline.span.of(self.src).replace('\n', "").into(),
|
Container::Link(url, LinkType::Span(SpanLinkType::Inline))
|
||||||
LinkType::Span(SpanLinkType::Inline),
|
}
|
||||||
),
|
inline::Container::InlineImage(url) => {
|
||||||
inline::Container::InlineImage => Container::Image(
|
Container::Image(url, SpanLinkType::Inline)
|
||||||
inline.span.of(self.src).replace('\n', "").into(),
|
}
|
||||||
SpanLinkType::Inline,
|
inline::Container::ReferenceLink(ref tag)
|
||||||
),
|
| inline::Container::ReferenceImage(ref tag) => {
|
||||||
inline::Container::ReferenceLink | inline::Container::ReferenceImage => {
|
|
||||||
let tag = inline.span.of(self.src).replace('\n', " ");
|
|
||||||
let link_def = self
|
let link_def = self
|
||||||
.pre_pass
|
.pre_pass
|
||||||
.link_definitions
|
.link_definitions
|
||||||
|
@ -851,12 +849,12 @@ impl<'s> Parser<'s> {
|
||||||
(url, SpanLinkType::Reference)
|
(url, SpanLinkType::Reference)
|
||||||
} else {
|
} else {
|
||||||
self.pre_pass.heading_id_by_tag(tag.as_ref()).map_or_else(
|
self.pre_pass.heading_id_by_tag(tag.as_ref()).map_or_else(
|
||||||
|| (tag.into(), SpanLinkType::Unresolved),
|
|| (tag.clone(), SpanLinkType::Unresolved),
|
||||||
|id| (format!("#{}", id).into(), SpanLinkType::Reference),
|
|id| (format!("#{}", id).into(), SpanLinkType::Reference),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches!(c, inline::Container::ReferenceLink) {
|
if matches!(c, inline::Container::ReferenceLink(..)) {
|
||||||
Container::Link(url_or_tag, LinkType::Span(ty))
|
Container::Link(url_or_tag, LinkType::Span(ty))
|
||||||
} else {
|
} else {
|
||||||
Container::Image(url_or_tag, ty)
|
Container::Image(url_or_tag, ty)
|
||||||
|
@ -1359,7 +1357,6 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore = "broken"]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn link_inline_multi_line() {
|
fn link_inline_multi_line() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
|
@ -1378,6 +1375,23 @@ mod test {
|
||||||
End(Paragraph),
|
End(Paragraph),
|
||||||
End(Blockquote),
|
End(Blockquote),
|
||||||
);
|
);
|
||||||
|
test_parse!(
|
||||||
|
concat!(
|
||||||
|
"> [text](a\n", //
|
||||||
|
"> bc\n", //
|
||||||
|
"> def)\n", //
|
||||||
|
),
|
||||||
|
Start(Blockquote, Attributes::new()),
|
||||||
|
Start(Paragraph, Attributes::new()),
|
||||||
|
Start(
|
||||||
|
Link("abcdef".into(), LinkType::Span(SpanLinkType::Inline)),
|
||||||
|
Attributes::new()
|
||||||
|
),
|
||||||
|
Str("text".into()),
|
||||||
|
End(Link("abcdef".into(), LinkType::Span(SpanLinkType::Inline))),
|
||||||
|
End(Paragraph),
|
||||||
|
End(Blockquote),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1442,7 +1456,6 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore = "multiline links broken"]
|
|
||||||
#[test]
|
#[test]
|
||||||
fn link_reference_multiline() {
|
fn link_reference_multiline() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
|
|
|
@ -9,7 +9,6 @@ ae6fc15:bugged left/right quote
|
||||||
e1f5b5e:untrimmed whitespace before linebreak
|
e1f5b5e:untrimmed whitespace before linebreak
|
||||||
07888f3:div close within raw block
|
07888f3:div close within raw block
|
||||||
8423412:heading id conflict with existing id
|
8423412:heading id conflict with existing id
|
||||||
00a46ed:clear inline formatting from link tags
|
|
||||||
c0a3dec:escape in url
|
c0a3dec:escape in url
|
||||||
61876cf:roman alpha ambiguity
|
61876cf:roman alpha ambiguity
|
||||||
f31b357:roman alpha ambiguity
|
f31b357:roman alpha ambiguity
|
||||||
|
|
Loading…
Reference in a new issue