diff --git a/src/html.rs b/src/html.rs index 6c521720..abe29be1 100644 --- a/src/html.rs +++ b/src/html.rs @@ -725,31 +725,43 @@ impl<'o, 'c: 'o> HtmlFormatter<'o, 'c> { } } NodeValue::Text(ref literal) => { - // No sourcepos. + // Nowhere to put sourcepos. if entering { self.escape(literal.as_bytes())?; } } NodeValue::LineBreak => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b"
\n")?; + self.output.write_all(b"\n")?; } } NodeValue::SoftBreak => { - // No sourcepos. + // Unreliable sourcepos. if entering { if self.options.render.hardbreaks { - self.output.write_all(b"
\n")?; + self.output.write_all(b"\n")?; } else { self.output.write_all(b"\n")?; } } } NodeValue::Code(NodeCode { ref literal, .. }) => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; self.escape(literal.as_bytes())?; self.output.write_all(b"")?; } @@ -771,47 +783,67 @@ impl<'o, 'c: 'o> HtmlFormatter<'o, 'c> { } } NodeValue::Strong => { - // No sourcepos. + // Unreliable sourcepos. let parent_node = node.parent(); if !self.options.render.gfm_quirks || (parent_node.is_none() || !matches!(parent_node.unwrap().data.borrow().value, NodeValue::Strong)) { if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; } else { self.output.write_all(b"")?; } } } NodeValue::Emph => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; } else { self.output.write_all(b"")?; } } NodeValue::Strikethrough => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; } else { self.output.write_all(b"")?; } } NodeValue::Superscript => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; } else { self.output.write_all(b"")?; } } NodeValue::Link(ref nl) => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b" HtmlFormatter<'o, 'c> { } } NodeValue::Image(ref nl) => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b" HtmlFormatter<'o, 'c> { } #[cfg(feature = "shortcodes")] NodeValue::ShortCode(ref nsc) => { + // Nowhere to put sourcepos. if entering { self.output.write_all(nsc.emoji.as_bytes())?; } @@ -941,14 +978,17 @@ impl<'o, 'c: 'o> HtmlFormatter<'o, 'c> { } } NodeValue::FootnoteDefinition(ref nfd) => { - // No sourcepos. if entering { if self.footnote_ix == 0 { + self.output.write_all(b"\n
    \n")?; + .write_all(b" class=\"footnotes\" data-footnotes>\n
      \n")?; } self.footnote_ix += 1; - self.output.write_all(b"
    1. ")?; } else { @@ -959,14 +999,19 @@ impl<'o, 'c: 'o> HtmlFormatter<'o, 'c> { } } NodeValue::FootnoteReference(ref nfr) => { - // No sourcepos. + // Unreliable sourcepos. if entering { let mut ref_id = format!("fnref-{}", nfr.name); if nfr.ref_num > 1 { ref_id = format!("{}-{}", ref_id, nfr.ref_num); } + + self.output.write_all(b" HtmlFormatter<'o, 'c> { } } NodeValue::Escaped => { - // No sourcepos. + // Unreliable sourcepos. if self.options.render.escaped_char_spans { if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; } else { self.output.write_all(b"")?; } @@ -1024,9 +1073,13 @@ impl<'o, 'c: 'o> HtmlFormatter<'o, 'c> { } } NodeValue::WikiLink(ref nl) => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b" HtmlFormatter<'o, 'c> { } } NodeValue::Underline => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; } else { self.output.write_all(b"")?; } } NodeValue::SpoileredText => { - // No sourcepos. + // Unreliable sourcepos. if entering { - self.output.write_all(b"")?; + self.output.write_all(b"")?; } else { self.output.write_all(b"")?; } } NodeValue::EscapedTag(ref net) => { - // No sourcepos. + // Nowhere to put sourcepos. self.output.write_all(net.as_bytes())?; } } @@ -1114,7 +1175,8 @@ impl<'o, 'c: 'o> HtmlFormatter<'o, 'c> { tag_attributes.push((String::from("data-math-style"), String::from(style_attr))); - if self.options.render.sourcepos { + // Unreliable sourcepos. + if self.options.render.experimental_inline_sourcepos && self.options.render.sourcepos { let ast = node.data.borrow(); tag_attributes.push(("data-sourcepos".to_string(), ast.sourcepos.to_string())); } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index b6987a97..fed397bc 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -761,19 +761,35 @@ pub struct RenderOptions { /// extensions. The description lists extension still has issues; see /// . /// - /// Sourcepos information is **not** reliable for inlines. See - /// for a discussion. + /// Sourcepos information is **not** reliable for inlines, and is not + /// included in HTML without also setting [`experimental_inline_sourcepos`]. + /// See for a discussion. /// /// ```rust /// # use comrak::{markdown_to_commonmark_xml, Options}; /// let mut options = Options::default(); /// options.render.sourcepos = true; - /// let input = "Hello *world*!"; + /// let input = "## Hello world!"; /// let xml = markdown_to_commonmark_xml(input, &options); - /// assert!(xml.contains("")); + /// assert!(xml.contains("")); /// ``` pub sourcepos: bool, + /// Include inline sourcepos in HTML output, which is known to have issues. + /// See for a discussion. + /// ```rust + /// # use comrak::{markdown_to_html, Options}; + /// let mut options = Options::default(); + /// options.render.sourcepos = true; + /// let input = "Hello *world*!"; + /// assert_eq!(markdown_to_html(input, &options), + /// "

      Hello world!

      \n"); + /// options.render.experimental_inline_sourcepos = true; + /// assert_eq!(markdown_to_html(input, &options), + /// "

      Hello world!

      \n"); + /// ``` + pub experimental_inline_sourcepos: bool, + /// Wrap escaped characters in a `` to allow any /// post-processing to recognize them. ///