implement symbols

e.g. :some-sym:
This commit is contained in:
Noah Hellman 2023-02-04 17:10:38 +01:00
parent 61f0d6281e
commit 0420aad0a5
4 changed files with 51 additions and 0 deletions

View file

@ -402,6 +402,7 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
number, number, number number, number, number
)?; )?;
} }
Atom::Symbol(sym) => write!(self.out, ":{}:", sym)?,
Atom::LeftSingleQuote => self.out.write_str("&lsquo;")?, Atom::LeftSingleQuote => self.out.write_str("&lsquo;")?,
Atom::RightSingleQuote => self.out.write_str("&rsquo;")?, Atom::RightSingleQuote => self.out.write_str("&rsquo;")?,
Atom::LeftDoubleQuote => self.out.write_str("&ldquo;")?, Atom::LeftDoubleQuote => self.out.write_str("&ldquo;")?,

View file

@ -11,6 +11,7 @@ use Container::*;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Atom { pub enum Atom {
FootnoteReference, FootnoteReference,
Symbol,
Softbreak, Softbreak,
Hardbreak, Hardbreak,
Escape, Escape,
@ -115,6 +116,7 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
self.parse_verbatim(&first) self.parse_verbatim(&first)
.or_else(|| self.parse_attributes(&first)) .or_else(|| self.parse_attributes(&first))
.or_else(|| self.parse_autolink(&first)) .or_else(|| self.parse_autolink(&first))
.or_else(|| self.parse_symbol(&first))
.or_else(|| self.parse_footnote_reference(&first)) .or_else(|| self.parse_footnote_reference(&first))
.or_else(|| self.parse_container(&first)) .or_else(|| self.parse_container(&first))
.or_else(|| self.parse_atom(&first)) .or_else(|| self.parse_atom(&first))
@ -351,6 +353,37 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
} }
} }
fn parse_symbol(&mut self, first: &lex::Token) -> Option<Event> {
if first.kind == lex::Kind::Sym(Symbol::Colon) {
let mut ahead = self.lexer.chars();
let mut end = false;
let mut valid = true;
let len = (&mut ahead)
.take_while(|c| {
if *c == ':' {
end = true;
} else if !c.is_ascii_alphanumeric() && !matches!(c, '-' | '+' | '_') {
valid = false;
}
!end && !c.is_whitespace()
})
.map(char::len_utf8)
.sum();
(end && valid).then(|| {
self.lexer = lex::Lexer::new(ahead);
self.span = self.span.after(len);
let span = self.span;
self.span = self.span.after(1);
Event {
kind: EventKind::Atom(Symbol),
span,
}
})
} else {
None
}
}
fn parse_footnote_reference(&mut self, first: &lex::Token) -> Option<Event> { fn parse_footnote_reference(&mut self, first: &lex::Token) -> Option<Event> {
if first.kind == lex::Kind::Open(Delimiter::Bracket) if first.kind == lex::Kind::Open(Delimiter::Bracket)
&& matches!( && matches!(

View file

@ -49,6 +49,7 @@ pub enum Symbol {
Quote2, Quote2,
Tilde, Tilde,
Underscore, Underscore,
Colon,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -232,6 +233,7 @@ impl<I: Iterator<Item = char> + Clone> Lexer<I> {
} }
'<' => Sym(Lt), '<' => Sym(Lt),
'|' => Sym(Pipe), '|' => Sym(Pipe),
':' => Sym(Colon),
'`' => self.eat_seq(Backtick), '`' => self.eat_seq(Backtick),
'$' => self.eat_seq(Dollar), '$' => self.eat_seq(Dollar),

View file

@ -236,6 +236,8 @@ pub enum OrderedListStyle {
pub enum Atom<'s> { pub enum Atom<'s> {
/// A footnote reference. /// A footnote reference.
FootnoteReference(&'s str, usize), FootnoteReference(&'s str, usize),
/// A symbol, by default rendered literally but may be treated specially.
Symbol(CowStr<'s>),
/// Left single quotation mark. /// Left single quotation mark.
LeftSingleQuote, LeftSingleQuote,
/// Right double quotation mark. /// Right double quotation mark.
@ -654,6 +656,7 @@ impl<'s> Parser<'s> {
number, number,
) )
} }
inline::Atom::Symbol => Atom::Symbol(self.inlines.src(inline.span)),
inline::Atom::Quote { ty, left } => match (ty, left) { inline::Atom::Quote { ty, left } => match (ty, left) {
(inline::QuoteType::Single, true) => Atom::LeftSingleQuote, (inline::QuoteType::Single, true) => Atom::LeftSingleQuote,
(inline::QuoteType::Single, false) => Atom::RightSingleQuote, (inline::QuoteType::Single, false) => Atom::RightSingleQuote,
@ -1088,6 +1091,18 @@ mod test {
); );
} }
#[test]
fn symbol() {
test_parse!(
"abc :+1: def",
Start(Paragraph, Attributes::new()),
Str("abc ".into()),
Atom(Symbol("+1".into())),
Str(" def".into()),
End(Paragraph),
);
}
#[test] #[test]
fn link_inline() { fn link_inline() {
test_parse!( test_parse!(