diff --git a/src/html.rs b/src/html.rs
index a82b329..a484b34 100644
--- a/src/html.rs
+++ b/src/html.rs
@@ -402,6 +402,7 @@ impl<'s, I: Iterator- >, W: std::fmt::Write> Writer<'s, I, W> {
number, number, number
)?;
}
+ Atom::Symbol(sym) => write!(self.out, ":{}:", sym)?,
Atom::LeftSingleQuote => self.out.write_str("‘")?,
Atom::RightSingleQuote => self.out.write_str("’")?,
Atom::LeftDoubleQuote => self.out.write_str("“")?,
diff --git a/src/inline.rs b/src/inline.rs
index 1a52bfb..93a624a 100644
--- a/src/inline.rs
+++ b/src/inline.rs
@@ -11,6 +11,7 @@ use Container::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Atom {
FootnoteReference,
+ Symbol,
Softbreak,
Hardbreak,
Escape,
@@ -115,6 +116,7 @@ impl + Clone> Parser {
self.parse_verbatim(&first)
.or_else(|| self.parse_attributes(&first))
.or_else(|| self.parse_autolink(&first))
+ .or_else(|| self.parse_symbol(&first))
.or_else(|| self.parse_footnote_reference(&first))
.or_else(|| self.parse_container(&first))
.or_else(|| self.parse_atom(&first))
@@ -351,6 +353,37 @@ impl + Clone> Parser {
}
}
+ fn parse_symbol(&mut self, first: &lex::Token) -> Option {
+ 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 {
if first.kind == lex::Kind::Open(Delimiter::Bracket)
&& matches!(
diff --git a/src/lex.rs b/src/lex.rs
index ebb70db..25f11e1 100644
--- a/src/lex.rs
+++ b/src/lex.rs
@@ -49,6 +49,7 @@ pub enum Symbol {
Quote2,
Tilde,
Underscore,
+ Colon,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -232,6 +233,7 @@ impl + Clone> Lexer {
}
'<' => Sym(Lt),
'|' => Sym(Pipe),
+ ':' => Sym(Colon),
'`' => self.eat_seq(Backtick),
'$' => self.eat_seq(Dollar),
diff --git a/src/lib.rs b/src/lib.rs
index 8553d4b..3d759f7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -236,6 +236,8 @@ pub enum OrderedListStyle {
pub enum Atom<'s> {
/// A footnote reference.
FootnoteReference(&'s str, usize),
+ /// A symbol, by default rendered literally but may be treated specially.
+ Symbol(CowStr<'s>),
/// Left single quotation mark.
LeftSingleQuote,
/// Right double quotation mark.
@@ -654,6 +656,7 @@ impl<'s> Parser<'s> {
number,
)
}
+ inline::Atom::Symbol => Atom::Symbol(self.inlines.src(inline.span)),
inline::Atom::Quote { ty, left } => match (ty, left) {
(inline::QuoteType::Single, true) => Atom::LeftSingleQuote,
(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]
fn link_inline() {
test_parse!(