Skip to content

Commit 22065eb

Browse files
committed
Give a warning for unclosed HTML tags
This changes the internal error message to a warning to let the user know that the HTML tags are unbalanced. In the future this will be a denyable lint. This is a very primitive approach of just ignoring the end tag. Ideally it should recover using the standard HTML parsing algorithm, since there is a chance that there will be a cascade of errors under certain unbalanced situations.
1 parent 5905bf1 commit 22065eb

File tree

2 files changed

+18
-21
lines changed

2 files changed

+18
-21
lines changed

crates/mdbook-html/src/html/tree.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use pulldown_cmark::{Alignment, CodeBlockKind, CowStr, Event, LinkType, Tag, Tag
1919
use std::borrow::Cow;
2020
use std::collections::{HashMap, HashSet};
2121
use std::ops::Deref;
22-
use tracing::{error, trace, warn};
22+
use tracing::{trace, warn};
2323

2424
/// Helper to create a [`QualName`].
2525
macro_rules! attr_qual_name {
@@ -664,9 +664,18 @@ where
664664
*is_raw = false;
665665
if self.is_html_tag_matching(&tag.name) {
666666
self.pop();
667+
} else {
668+
// The proper thing to do here is to recover. However, the HTML
669+
// parsing algorithm for that is quite complex. See
670+
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
671+
// and the adoption agency algorithm.
672+
warn!(
673+
"unexpected HTML end tag `</{}>` found in `{}`\n\
674+
Check that the HTML tags are properly balanced.",
675+
tag.name,
676+
self.options.path.display()
677+
);
667678
}
668-
// else the stack is corrupt. I'm not really sure
669-
// what to do here...
670679
}
671680

672681
/// This is used to verify HTML parsing keeps the stack of tags in sync.
@@ -675,16 +684,10 @@ where
675684
if let Node::Element(el) = current
676685
&& el.name() == name
677686
{
678-
return true;
687+
true
688+
} else {
689+
false
679690
}
680-
error!(
681-
"internal error: HTML tag stack out of sync.\n
682-
path: `{}`\n\
683-
current={current:?}\n\
684-
pop name: {name}",
685-
self.options.path.display()
686-
);
687-
false
688691
}
689692

690693
/// Eats all pulldown-cmark events until the next `End` matching the

tests/testsuite/rendering.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -274,18 +274,12 @@ fn unbalanced_html_tags() {
274274
cmd.expect_stderr(str![[r#"
275275
INFO Book building has started
276276
INFO Running the html backend
277-
ERROR internal error: HTML tag stack out of sync.
278-
279-
path: `chapter_1.md`
280-
current=Element(Element { name: QualName { prefix: None, ns: Atom('http://www.w3.org/1999/xhtml' type=static), local: Atom('span' type=inline) }, attrs: {}, self_closing: false, was_raw: true })
281-
pop name: div
277+
WARN unexpected HTML end tag `</div>` found in `chapter_1.md`
278+
Check that the HTML tags are properly balanced.
282279
WARN unclosed HTML tag `<div>` found in `chapter_1.md`
283280
INFO HTML book written to `[ROOT]/book`
284281
285282
"#]]);
286283
})
287-
.check_main_file(
288-
"book/chapter_1.html",
289-
str!["<div>x<span>foo</span></div>"],
290-
);
284+
.check_main_file("book/chapter_1.html", str!["<div>x<span>foo</span></div>"]);
291285
}

0 commit comments

Comments
 (0)