Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Options:
Multiple extensions can be delimited with ",", e.g. --extension strikethrough,table

[possible values: strikethrough, tagfilter, table, autolink, tasklist, superscript,
footnotes, description-lists]
footnotes, description-lists, subscript, highlight]

-t, --to <FORMAT>
Specify output format
Expand Down Expand Up @@ -222,6 +222,8 @@ Comrak additionally supports its own extensions, which are yet to be specced out
- Description lists
- Front matter
- Shortcodes
- Subscript
- Highlight

By default none are enabled; they are individually enabled with each parse by setting the appropriate values in the
[`ComrakOptions` struct](https://docs.rs/comrak/newest/comrak/struct.ComrakOptions.html).
Expand Down
12 changes: 11 additions & 1 deletion src/cm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> {
NodeValue::FootnoteReference(ref r) => {
self.format_footnote_reference(r.as_bytes(), entering)
}
NodeValue::Subscript => self.format_subscript(),
NodeValue::Highlight => self.format_highlight(),
};
true
}
Expand Down Expand Up @@ -631,13 +633,21 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> {
}

fn format_strikethrough(&mut self) {
write!(self, "~").unwrap();
write!(self, "~~").unwrap();
}

fn format_superscript(&mut self) {
write!(self, "^").unwrap();
}

fn format_subscript(&mut self) {
write!(self, "~").unwrap();
}

fn format_highlight(&mut self) {
write!(self, "==").unwrap();
}

fn format_link(&mut self, node: &'a AstNode<'a>, nl: &NodeLink, entering: bool) -> bool {
if is_autolink(node, nl) {
if entering {
Expand Down
18 changes: 18 additions & 0 deletions src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,24 @@ impl<'o> HtmlFormatter<'o> {
self.output.write_all(b"</li>\n")?;
}
}
NodeValue::Subscript => {
if entering {
self.output.write_all(b"<sub")?;
self.render_sourcepos(node)?;
self.output.write_all(b">")?;
} else {
self.output.write_all(b"</sub>")?;
}
}
NodeValue::Highlight => {
if entering {
self.output.write_all(b"<mark")?;
self.render_sourcepos(node)?;
self.output.write_all(b">")?;
} else {
self.output.write_all(b"</mark>")?;
}
}
}
Ok(false)
}
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ enum Extension {
Superscript,
Footnotes,
DescriptionLists,
Subscript,
Highlight
}

#[derive(Clone, Copy, Debug, ValueEnum)]
Expand Down Expand Up @@ -209,6 +211,8 @@ fn main() -> Result<(), Box<dyn Error>> {
front_matter_delimiter: cli.front_matter_delimiter,
#[cfg(feature = "shortcodes")]
shortcodes: cli.gemojis,
subscript: exts.contains(&Extension::Subscript),
highlight: exts.contains(&Extension::Highlight)
},
parse: ComrakParseOptions {
smart: cli.smart,
Expand Down
10 changes: 9 additions & 1 deletion src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ pub enum NodeValue {
/// per the GFM spec.
Strikethrough,

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

/// **Inline**. A [link](https://github.github.com/gfm/#links) to some URL, with possible
Expand All @@ -151,6 +151,12 @@ pub enum NodeValue {
#[cfg(feature = "shortcodes")]
/// **Inline**. An Emoji character generated from a shortcode. Enable with feature "shortcodes".
ShortCode(NodeShortCode),

/// **Inline**. Supscript.
Subscript,

/// **Inline**. Highlight.
Highlight,
}

/// Alignment of a single table cell.
Expand Down Expand Up @@ -425,6 +431,8 @@ impl NodeValue {
NodeValue::FootnoteReference(_) => "footnote_reference",
#[cfg(feature = "shortcodes")]
NodeValue::ShortCode(_) => "shortcode",
NodeValue::Subscript => "subscript",
NodeValue::Highlight => "highlight"
}
}
}
Expand Down
41 changes: 23 additions & 18 deletions src/parser/inlines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,20 @@ impl<'a, 'r, 'o, 'd, 'i, 'c, 'subj> Subject<'a, 'r, 'o, 'd, 'i, 'c, 'subj> {
s.special_chars[b'~' as usize] = true;
s.skip_chars[b'~' as usize] = true;
}
if options.extension.subscript {
s.special_chars[b'~' as usize] = true;
}
if options.extension.superscript {
s.special_chars[b'^' as usize] = true;
}
#[cfg(feature = "shortcodes")]
if options.extension.shortcodes {
s.special_chars[b':' as usize] = true;
}
if options.extension.highlight {
s.special_chars[b'=' as usize] = true;
s.skip_chars[b'=' as usize] = true;
}
for &c in &[b'"', b'\'', b'.', b'-'] {
s.smart_chars[c as usize] = true;
}
Expand Down Expand Up @@ -210,10 +217,9 @@ impl<'a, 'r, 'o, 'd, 'i, 'c, 'subj> Subject<'a, 'r, 'o, 'd, 'i, 'c, 'subj> {
))
}
}
'~' if self.options.extension.strikethrough => Some(self.handle_delim(b'~')),
'^' if self.options.extension.superscript && !self.within_brackets => {
Some(self.handle_delim(b'^'))
}
'~' if (self.options.extension.subscript && !self.within_brackets) || self.options.extension.strikethrough => Some(self.handle_delim(b'~')),
'^' if self.options.extension.superscript && !self.within_brackets => Some(self.handle_delim(b'^')),
'=' if self.options.extension.highlight => Some(self.handle_delim(b'=')),
_ => {
let endpos = self.find_special_char();
let mut contents = self.input[self.pos..endpos].to_vec();
Expand Down Expand Up @@ -337,10 +343,11 @@ impl<'a, 'r, 'o, 'd, 'i, 'c, 'subj> Subject<'a, 'r, 'o, 'd, 'i, 'c, 'subj> {
let ix = match c.delim_char {
b'~' => 0,
b'^' => 1,
b'"' => 2,
b'\'' => 3,
b'_' => 4,
b'*' => 5 + (if c.can_open { 3 } else { 0 }) + (c.length % 3),
b'=' => 2,
b'"' => 3,
b'\'' => 4,
b'_' => 5,
b'*' => 6 + (if c.can_open { 2 } else { 0 }) + (c.length % 3),
_ => unreachable!(),
};

Expand Down Expand Up @@ -387,8 +394,9 @@ impl<'a, 'r, 'o, 'd, 'i, 'c, 'subj> Subject<'a, 'r, 'o, 'd, 'i, 'c, 'subj> {
// both get passed.
if c.delim_char == b'*'
|| c.delim_char == b'_'
|| (self.options.extension.strikethrough && c.delim_char == b'~')
|| ((self.options.extension.strikethrough || self.options.extension.subscript) && c.delim_char == b'~')
|| (self.options.extension.superscript && c.delim_char == b'^')
|| (self.options.extension.highlight && c.delim_char == b'=')
{
if opener_found {
// Finally, here's the happy case where the delimiters
Expand Down Expand Up @@ -837,13 +845,6 @@ impl<'a, 'r, 'o, 'd, 'i, 'c, 'subj> Subject<'a, 'r, 'o, 'd, 'i, 'c, 'subj> {
opener_num_chars -= use_delims;
closer_num_chars -= use_delims;

if self.options.extension.strikethrough
&& opener_char == b'~'
&& (opener_num_chars != closer_num_chars || opener_num_chars > 0)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect (though haven't checked) this will cause spec failure with this example. The spec requires three or more tildes to not generate a strikethrough; since we've already subtracted use_delims (2 for a strikethrough of length 2 or more) from opener_num_chars, if we had 3 or more, opener_num_chars > 0 would be true and so we'd return None here.

Copy link
Author

@bismitpanda bismitpanda May 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If subscript and strikethrough, both are enabled, it will be a subscript as well as a strikethrough\ like in cases of italics and bolds. Considering this, I removed the condition.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding and additional && to check if subscript is enabled. Like

if (self.options.extension.strikethrough
    && opener_char == b'~'
    && (opener_num_chars != closer_num_chars || opener_num_chars > 0))
    && !self.options.extension.subscript
{
    return None;
}

{
return None;
}

opener
.inl
.data
Expand All @@ -870,9 +871,13 @@ impl<'a, 'r, 'o, 'd, 'i, 'c, 'subj> Subject<'a, 'r, 'o, 'd, 'i, 'c, 'subj> {
}

let emph = self.make_inline(
if self.options.extension.strikethrough && opener_char == b'~' {
if self.options.extension.highlight && opener_char == b'=' && use_delims == 2 {
NodeValue::Highlight
} else if self.options.extension.strikethrough && opener_char == b'~' && use_delims == 2 {
NodeValue::Strikethrough
} else if self.options.extension.superscript && opener_char == b'^' {
} else if self.options.extension.subscript && opener_char == b'~' && use_delims == 1 {
NodeValue::Subscript
} else if self.options.extension.superscript && opener_char == b'^' && use_delims == 1 {
NodeValue::Superscript
} else if use_delims == 1 {
NodeValue::Emph
Expand Down
22 changes: 22 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,28 @@ pub struct ComrakExtensionOptions {
/// "<p>Happy Friday! 😄</p>\n");
/// ```
pub shortcodes: bool,

/// Enables the subscript Comrak extension.
///
/// ```
/// # use comrak::{markdown_to_html, ComrakOptions};
/// let mut options = ComrakOptions::default();
/// options.extension.subscript = true;
/// assert_eq!(markdown_to_html("Water is H~2~O.\n", &options),
/// "<p><p>Water is H<sup>2</sup>O.</p></p>\n");
/// ```
pub subscript: bool,

/// Enables the highlight Comrak extension.
///
/// ```
/// # use comrak::{markdown_to_html, ComrakOptions};
/// let mut options = ComrakOptions::default();
/// options.extension.highlight = true;
/// assert_eq!(markdown_to_html("This is an ==important== word.\n", &options),
/// "<p>This is an <mark>important</mark> word.</p>\n");
/// ```
pub highlight: bool,
}

#[derive(Default, Debug, Clone)]
Expand Down
2 changes: 2 additions & 0 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ mod description_lists;
mod footnotes;
mod fuzz;
mod header_ids;
mod highlight;
mod options;
mod plugins;
mod propfuzz;
mod regressions;
mod shortcodes;
mod strikethrough;
mod subscript;
mod superscript;
mod table;
mod tagfilter;
Expand Down
4 changes: 4 additions & 0 deletions src/tests/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ fn exercise_full_api() {
front_matter_delimiter: None,
#[cfg(feature = "shortcodes")]
shortcodes: true,
highlight: false,
subscript: false
},
parse: ComrakParseOptions {
smart: false,
Expand Down Expand Up @@ -210,5 +212,7 @@ fn exercise_full_api() {
nodes::NodeValue::FootnoteReference(name) => {
let _: &String = name;
}
nodes::NodeValue::Subscript => {}
nodes::NodeValue::Highlight => {}
}
}
10 changes: 10 additions & 0 deletions src/tests/highlight.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use super::*;

#[test]
fn highlight() {
html_opts!(
[extension.highlight],
concat!("This is an ==important== word.\n"),
concat!("<p>This is an <mark>important</mark> word.</p>\n"),
);
}
2 changes: 2 additions & 0 deletions src/tests/propfuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ fn propfuzz_doesnt_crash(md: String) {
front_matter_delimiter: None,
#[cfg(feature = "shortcodes")]
shortcodes: true,
highlight: true,
subscript: true
},
parse: ComrakParseOptions {
smart: true,
Expand Down
2 changes: 1 addition & 1 deletion src/tests/strikethrough.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ fn strikethrough() {
html_opts!(
[extension.strikethrough],
concat!(
"This is ~strikethrough~.\n",
"This is ~~strikethrough~~.\n",
"\n",
"As is ~~this, okay~~?\n"
),
Expand Down
10 changes: 10 additions & 0 deletions src/tests/subscript.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use super::*;

#[test]
fn subscript() {
html_opts!(
[extension.subscript],
concat!("Water is H~2~O.\n"),
concat!("<p>Water is H<sub>2</sub>O.</p>\n"),
);
}
3 changes: 3 additions & 0 deletions src/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ impl<'o> XmlFormatter<'o> {
self.escape(nsc.shortcode().as_bytes())?;
self.output.write_all(b"\"")?;
}

NodeValue::Subscript => {}
NodeValue::Highlight => {}
}

if node.first_child().is_some() {
Expand Down