mirror of
https://github.com/lexmount/moli.git
synced 2026-10-05 16:00:54 +00:00
Preserve preformatted boundaries and empty code separation
This commit is contained in:
@@ -384,10 +384,10 @@ impl<'a, D: Dom + ?Sized> Machine<'a, D> {
|
||||
NodeKind::Text(text) => self.raw.push_str(text),
|
||||
// Inline code normalizes line endings to spaces. Keep explicit
|
||||
// breaks without converting descendant formatting into Markdown.
|
||||
NodeKind::Element("br") if inline => self.raw.push('\n'),
|
||||
NodeKind::Element("br") => self.raw.push('\n'),
|
||||
NodeKind::Document | NodeKind::Element(_) if depth + 1 < self.options.max_depth => {
|
||||
if !inline
|
||||
&& matches!(self.dom.node_kind(node), NodeKind::Element(tag) if is_block(tag))
|
||||
&& matches!(self.dom.node_kind(node), NodeKind::Element(tag) if is_structural_block(tag))
|
||||
{
|
||||
if !self.raw.is_empty() && !self.raw.ends_with('\n') {
|
||||
self.raw.push('\n');
|
||||
@@ -449,17 +449,20 @@ fn class_language(class: Option<&str>) -> Option<&str> {
|
||||
}
|
||||
|
||||
fn is_block(tag: &str) -> bool {
|
||||
is_structural_block(tag)
|
||||
|| matches!(
|
||||
tag,
|
||||
"audio" | "canvas" | "frameset" | "isindex" | "noframes" | "output"
|
||||
)
|
||||
}
|
||||
|
||||
fn is_structural_block(tag: &str) -> bool {
|
||||
matches!(
|
||||
tag,
|
||||
"address"
|
||||
| "audio"
|
||||
| "canvas"
|
||||
| "frameset"
|
||||
| "isindex"
|
||||
| "noframes"
|
||||
| "output"
|
||||
| "article"
|
||||
| "aside"
|
||||
| "blockquote"
|
||||
| "body"
|
||||
| "caption"
|
||||
| "center"
|
||||
@@ -475,14 +478,23 @@ fn is_block(tag: &str) -> bool {
|
||||
| "figure"
|
||||
| "footer"
|
||||
| "form"
|
||||
| "h1"
|
||||
| "h2"
|
||||
| "h3"
|
||||
| "h4"
|
||||
| "h5"
|
||||
| "h6"
|
||||
| "header"
|
||||
| "hgroup"
|
||||
| "html"
|
||||
| "legend"
|
||||
| "li"
|
||||
| "main"
|
||||
| "menu"
|
||||
| "nav"
|
||||
| "ol"
|
||||
| "p"
|
||||
| "pre"
|
||||
| "section"
|
||||
| "summary"
|
||||
| "table"
|
||||
@@ -492,5 +504,6 @@ fn is_block(tag: &str) -> bool {
|
||||
| "th"
|
||||
| "thead"
|
||||
| "tr"
|
||||
| "ul"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -171,6 +171,11 @@ impl<'a> Writer<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn code_with_edges(&mut self, text: &str, preformatted: bool) {
|
||||
// An empty element has no visible edge. Keep the pending code until
|
||||
// the next visible text or element decides whether it needs a gap.
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
// Each call represents a separate HTML code element. Keep adjacent
|
||||
// elements distinct even when the source has no whitespace between them.
|
||||
if self.code.is_some() {
|
||||
|
||||
@@ -106,6 +106,32 @@ fn pre_keeps_raw_text_and_line_endings() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preformatted_examples_keep_inline_values_and_separate_display_lines() {
|
||||
for (source, expected) in [
|
||||
(
|
||||
"<pre>const answer = <output>42</output>;</pre>",
|
||||
"const answer = 42;",
|
||||
),
|
||||
(
|
||||
"<pre><h3>TypeScript</h3><code>function identity() {}</code></pre>",
|
||||
"TypeScript\nfunction identity() {}",
|
||||
),
|
||||
(
|
||||
"<pre><ol><li>first()</li><li>second()</li></ol></pre>",
|
||||
"first()\nsecond()",
|
||||
),
|
||||
("<pre>first<br>second</pre>", "first\nsecond"),
|
||||
] {
|
||||
let result = markdown(source);
|
||||
assert_eq!(
|
||||
rendered_html(&result),
|
||||
format!("<pre><code>{expected}\n</code></pre>\n"),
|
||||
"{source}: {result}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_emphasis_closes_with_markdown_before_a_word() {
|
||||
for (html, expected, expected_html) in [
|
||||
|
||||
@@ -158,6 +158,21 @@ fn adjacent_code_elements_keep_distinct_values() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_code_between_values_does_not_join_or_invent_code_text() {
|
||||
for empty in ["<code></code>", "<code><!-- source note --></code>"] {
|
||||
let source = format!("<code>name</code>{empty}<code>string</code>");
|
||||
for preformatted in [false, true] {
|
||||
let result = markdown(&source, preformatted);
|
||||
assert_eq!(
|
||||
rendered_html(&result),
|
||||
"<p><code>name</code> <code>string</code></p>\n",
|
||||
"{source}, preformatted={preformatted}: {result}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preformatted_block_children_keep_text_boundaries() {
|
||||
let html = "<pre><div>ts</div><div><code>function identity() {}</code></div></pre>";
|
||||
|
||||
Reference in New Issue
Block a user