Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/cm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ impl<'a, 'o, 'c> CommonMarkFormatter<'a, 'o, 'c> {
NodeValue::Emph => self.format_emph(node)?,
NodeValue::TaskItem(symbol) => self.format_task_item(symbol, node, entering)?,
NodeValue::Strikethrough => self.format_strikethrough()?,
NodeValue::Highlight => self.format_highlight()?,
NodeValue::Superscript => self.format_superscript()?,
NodeValue::Link(ref nl) => return self.format_link(node, nl, entering),
NodeValue::Image(ref nl) => self.format_image(nl, allow_wrap, entering)?,
Expand Down Expand Up @@ -783,6 +784,11 @@ impl<'a, 'o, 'c> CommonMarkFormatter<'a, 'o, 'c> {
Ok(())
}

fn format_highlight(&mut self) -> fmt::Result {
write!(self, "==")?;
Ok(())
}

fn format_superscript(&mut self) -> fmt::Result {
write!(self, "^")?;
Ok(())
Expand Down
17 changes: 17 additions & 0 deletions src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ pub fn format_node_default<'a, T>(
render_footnote_reference(context, node, entering, nfr)
}
NodeValue::Strikethrough => render_strikethrough(context, node, entering),
NodeValue::Highlight => render_highlight(context, node, entering),
NodeValue::Table(_) => render_table(context, node, entering),
NodeValue::TableCell => render_table_cell(context, node, entering),
NodeValue::TableRow(thead) => render_table_row(context, node, entering, thead),
Expand Down Expand Up @@ -1034,6 +1035,22 @@ fn render_strikethrough<'a, T>(
Ok(ChildRendering::HTML)
}

fn render_highlight<'a, T>(
context: &mut Context<T>,
node: Node<'a>,
entering: bool,
) -> Result<ChildRendering, fmt::Error> {
if entering {
context.write_str("<mark")?;
render_sourcepos(context, node)?;
context.write_str(">")?;
} else {
context.write_str("</mark>")?;
}

Ok(ChildRendering::HTML)
}

fn render_table<'a, T>(
context: &mut Context<T>,
node: Node<'a>,
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ enum Extension {
Alerts,
CjkFriendlyEmphasis,
Subtext,
Highlight,
}

#[derive(Clone, Copy, Debug, ValueEnum)]
Expand Down Expand Up @@ -284,7 +285,8 @@ fn main() -> Result<(), Box<dyn Error>> {
.alerts(exts.contains(&Extension::Alerts))
.maybe_front_matter_delimiter(cli.front_matter_delimiter)
.cjk_friendly_emphasis(exts.contains(&Extension::CjkFriendlyEmphasis))
.subtext(exts.contains(&Extension::Subtext));
.subtext(exts.contains(&Extension::Subtext))
.highlight(exts.contains(&Extension::Highlight));

#[cfg(feature = "shortcodes")]
let extension = extension.shortcodes(cli.gemoji);
Expand Down
7 changes: 7 additions & 0 deletions src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ pub enum NodeValue {
/// per the GFM spec.
Strikethrough,

/// ***Inline**. [Highlight](https://www.markdownlang.com/extended/highlight.html) / mark text
Highlight,

/// **Inline**. Superscript. Enabled with `ext_superscript` option.
Superscript,

Expand Down Expand Up @@ -646,6 +649,7 @@ impl NodeValue {
NodeValue::HtmlInline(..) => "html_inline",
NodeValue::Raw(..) => "raw",
NodeValue::Strikethrough => "strikethrough",
NodeValue::Highlight => "highlight",
NodeValue::FrontMatter(_) => "frontmatter",
NodeValue::TaskItem { .. } => "taskitem",
NodeValue::Superscript => "superscript",
Expand Down Expand Up @@ -925,6 +929,7 @@ impl<'a> arena_tree::Node<'a, RefCell<Ast>> {
| NodeValue::Image(..)
| NodeValue::WikiLink(..)
| NodeValue::Strikethrough
| NodeValue::Highlight
| NodeValue::Superscript
| NodeValue::SpoileredText
| NodeValue::Underline
Expand All @@ -947,6 +952,7 @@ impl<'a> arena_tree::Node<'a, RefCell<Ast>> {
| NodeValue::Link(..)
| NodeValue::Image(..)
| NodeValue::Strikethrough
| NodeValue::Highlight
| NodeValue::HtmlInline(..)
| NodeValue::Math(..)
| NodeValue::WikiLink(..)
Expand All @@ -969,6 +975,7 @@ impl<'a> arena_tree::Node<'a, RefCell<Ast>> {
| NodeValue::Link(..)
| NodeValue::Image(..)
| NodeValue::Strikethrough
| NodeValue::Highlight
| NodeValue::HtmlInline(..)
| NodeValue::Math(..)
| NodeValue::WikiLink(..)
Expand Down
22 changes: 19 additions & 3 deletions src/parser/inlines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ impl<'a, 'r, 'o, 'd, 'c, 'p> Subject<'a, 'r, 'o, 'd, 'c, 'p> {
s.skip_char_bytes[b'~' as usize] = true;
s.emph_delim_bytes[b'~' as usize] = true;
}
if options.extension.highlight {
s.special_char_bytes[b'=' as usize] = true;
s.skip_char_bytes[b'=' as usize] = true;
s.emph_delim_bytes[b'=' as usize] = true;
}
if options.extension.superscript || options.extension.inline_footnotes {
s.special_char_bytes[b'^' as usize] = true;
}
Expand Down Expand Up @@ -198,6 +203,7 @@ impl<'a, 'r, 'o, 'd, 'c, 'p> Subject<'a, 'r, 'o, 'd, 'c, 'p> {
let new_inl: Option<Node<'a>> = match b {
b'\r' | b'\n' => Some(self.handle_newline()),
b'`' => Some(self.handle_backticks(&ast.line_offsets)),
b'=' if self.options.extension.highlight => Some(self.handle_delim(b'=')),
b'\\' => Some(self.handle_backslash()),
b'&' => Some(self.handle_entity()),
b'<' => Some(self.handle_pointy_brace(&ast.line_offsets)),
Expand Down Expand Up @@ -684,15 +690,18 @@ impl<'a, 'r, 'o, 'd, 'c, 'p> Subject<'a, 'r, 'o, 'd, 'c, 'p> {
self.scanner.pos - 1,
);

let is_valid_strikethrough_delim = if b == b'~' && self.options.extension.strikethrough {
let is_valid_double_delim_if_required = if b == b'~' && self.options.extension.strikethrough
{
numdelims <= 2
} else if b == b'=' && self.options.extension.highlight {
numdelims == 2
} else {
true
};

if (can_open || can_close)
&& (!(b == b'\'' || b == b'"') || self.options.parse.smart)
&& is_valid_strikethrough_delim
&& is_valid_double_delim_if_required
{
self.push_delimiter(b, can_open, can_close, inl);
}
Expand Down Expand Up @@ -1202,7 +1211,7 @@ impl<'a, 'r, 'o, 'd, 'c, 'p> Subject<'a, 'r, 'o, 'd, 'c, 'p> {
// This array is an important optimization that prevents searching down
// the stack for openers we've previously searched for and know don't
// exist, preventing exponential blowup on pathological cases.
let mut openers_bottom: [usize; 12] = [stack_bottom; 12];
let mut openers_bottom: [usize; 13] = [stack_bottom; 13];

// This is traversing the stack from the top to the bottom, setting `closer` to
// the delimiter directly above `stack_bottom`. In the case where we are processing
Expand Down Expand Up @@ -1233,6 +1242,7 @@ impl<'a, 'r, 'o, 'd, 'c, 'p> Subject<'a, 'r, 'o, 'd, 'c, 'p> {
b'\'' => 4,
b'_' => 5,
b'*' => 6 + (if c.can_open { 3 } else { 0 }) + (c.length % 3),
b'=' => 12,
_ => unreachable!(),
};

Expand Down Expand Up @@ -1459,6 +1469,12 @@ impl<'a, 'r, 'o, 'd, 'c, 'p> Subject<'a, 'r, 'o, 'd, 'c, 'p> {
}
} else if self.options.extension.superscript && opener_byte == b'^' {
NodeValue::Superscript
} else if opener_byte == b'=' {
if self.options.extension.highlight {
NodeValue::Highlight
} else {
NodeValue::EscapedTag("==".to_owned())
}
} else if self.options.extension.spoiler && opener_byte == b'|' {
if use_delims == 2 {
NodeValue::SpoileredText
Expand Down
17 changes: 17 additions & 0 deletions src/parser/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,23 @@ pub struct Extension<'c> {
/// ```
#[cfg_attr(feature = "bon", builder(default))]
pub subtext: bool,

/// Enables highlighting (mark) using `==`.
///
/// ```md
/// Hey, ==this is important!==
/// ```
///
/// ```rust
/// # use comrak::{markdown_to_html, Options};
/// let mut options = Options::default();
/// options.extension.highlight = true;
///
/// assert_eq!(markdown_to_html("Hey, ==this is important!==", &options),
/// "<p>Hey, <mark>this is important!</mark></p>\n");
/// ```
#[cfg_attr(feature = "bon", builder(default))]
pub highlight: bool,
}

impl<'c> Extension<'c> {
Expand Down
1 change: 1 addition & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod front_matter;
mod fuzz;
mod greentext;
mod header_ids;
mod highlight;
#[path = "tests/html.rs"]
mod html_;
mod inline_footnotes;
Expand Down
26 changes: 26 additions & 0 deletions src/tests/highlight.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use super::*;

#[test]
fn highlight() {
html_opts!(
[extension.highlight],
concat!(
"This is ==important!==.\n",
"\n",
"This is ==very important== OK?\n",
"\n",
"==It is a \n shrubbery==\n",
"\n",
"Vendo ==Opel Corsa **em bom estado**==\n",
"\n",
"Ceci n'est pas =important=\n"
),
concat!(
"<p>This is <mark>important!</mark>.</p>\n",
"<p>This is <mark>very important</mark> OK?</p>\n",
"<p><mark>It is a\nshrubbery</mark></p>\n",
"<p>Vendo <mark>Opel Corsa <strong>em bom estado</strong></mark></p>\n",
"<p>Ceci n'est pas =important=</p>\n"
),
);
}
7 changes: 7 additions & 0 deletions src/tests/sourcepos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ const STRIKETHROUGH: TestCase = (
"hello ~~world~~ between ~~wo\nrld~~ after",
);

const HIGHLIGHT: TestCase = (
&[sourcepos!((1:7-1:15)), sourcepos!((1:25-2:5))],
"hello ==world== between ==wo\nrld== after",
);

const SUPERSCRIPT: TestCase = (
&[sourcepos!((1:7-1:13)), sourcepos!((1:23-2:4))],
"hello ^world^ between ^wo\nrld^ after",
Expand Down Expand Up @@ -475,6 +480,7 @@ fn node_values() -> HashMap<NodeValueDiscriminants, TestCase> {
Emph => EMPH,
Strong => STRONG,
Strikethrough => STRIKETHROUGH,
Highlight => HIGHLIGHT,
Superscript => SUPERSCRIPT,
Subscript => SUBSCRIPT,
Link => LINK,
Expand Down Expand Up @@ -508,6 +514,7 @@ fn sourcepos() {
options.extension.table = true;
options.extension.tasklist = true;
options.extension.strikethrough = true;
options.extension.highlight = true;
options.extension.superscript = true;
options.extension.subscript = true;
options.extension.autolink = true;
Expand Down
1 change: 1 addition & 0 deletions src/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ impl<'o, 'c> XmlFormatter<'o, 'c> {
NodeValue::Strong => {}
NodeValue::Emph => {}
NodeValue::Strikethrough => {}
NodeValue::Highlight => {}
NodeValue::Superscript => {}
NodeValue::Link(ref nl) | NodeValue::Image(ref nl) => {
self.output.write_str(" destination=\"")?;
Expand Down