Skip to content

Commit c045ce4

Browse files
authored
Merge pull request #673 from kivikakk/push-vnrrkomqxwny
Add "leave_footnote_definitions" parse option; add comrak::Node and expose NodeValue::xml_node_name.
2 parents 9a25834 + 692f03a commit c045ce4

File tree

5 files changed

+118
-26
lines changed

5 files changed

+118
-26
lines changed

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
//!
2020
//! ```rust
2121
//! use comrak::{Arena, parse_document, format_html, Options};
22-
//! use comrak::nodes::{NodeValue};
22+
//! use comrak::nodes::NodeValue;
2323
//!
2424
//! # fn main() {
2525
//! let arena = Arena::new();
@@ -91,6 +91,7 @@ pub use html::format_document as format_html;
9191
pub use html::format_document_with_plugins as format_html_with_plugins;
9292
#[doc(inline)]
9393
pub use html::Anchorizer;
94+
pub use nodes::Node;
9495
pub use parser::options;
9596
pub use parser::{parse_document, Options, ResolvedReference};
9697
pub use typed_arena::Arena;

src/nodes.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -608,17 +608,10 @@ impl NodeValue {
608608
}
609609
}
610610

611-
pub(crate) fn accepts_lines(&self) -> bool {
612-
matches!(
613-
*self,
614-
NodeValue::Paragraph
615-
| NodeValue::Heading(..)
616-
| NodeValue::CodeBlock(..)
617-
| NodeValue::Subtext
618-
)
619-
}
620-
621-
pub(crate) fn xml_node_name(&self) -> &'static str {
611+
/// Returns the name this kind of node gets in an XML document. Follows
612+
/// the CommonMark DTD for nodes from the spec, otherwise we just vibe in a
613+
/// stable way.
614+
pub fn xml_node_name(&self) -> &'static str {
622615
match *self {
623616
NodeValue::Document => "document",
624617
NodeValue::BlockQuote => "block_quote",
@@ -666,6 +659,16 @@ impl NodeValue {
666659
NodeValue::Subtext => "subtext",
667660
}
668661
}
662+
663+
pub(crate) fn accepts_lines(&self) -> bool {
664+
matches!(
665+
*self,
666+
NodeValue::Paragraph
667+
| NodeValue::Heading(..)
668+
| NodeValue::CodeBlock(..)
669+
| NodeValue::Subtext
670+
)
671+
}
669672
}
670673

671674
/// A single node in the CommonMark AST.

src/parser/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,11 @@ where
16861686
}
16871687
nl.tight = self.determine_list_tight(node);
16881688
}
1689+
NodeValue::FootnoteDefinition(_) => {
1690+
if let Some(candidate_end) = self.fix_zero_end_columns(node) {
1691+
ast.sourcepos.end = candidate_end;
1692+
}
1693+
}
16891694
_ => (),
16901695
}
16911696

@@ -1768,8 +1773,10 @@ where
17681773
};
17691774
nfd.name = fd.name.to_string();
17701775
nfd.total_references = fd.total_references;
1771-
self.root.append(fd.node);
1772-
} else {
1776+
if !self.options.parse.leave_footnote_definitions {
1777+
self.root.append(fd.node);
1778+
}
1779+
} else if !self.options.parse.leave_footnote_definitions {
17731780
fd.node.detach();
17741781
}
17751782
}

src/parser/options.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ pub struct Extension<'c> {
222222
/// let mut options = Options::default();
223223
/// options.extension.front_matter_delimiter = Some("---".to_owned());
224224
/// let arena = Arena::new();
225-
/// let input ="---\nlayout: post\n---\nText\n";
225+
/// let input = "---\nlayout: post\n---\nText\n";
226226
/// let root = parse_document(&arena, input, &options);
227227
/// let mut buf = String::new();
228228
/// format_commonmark(&root, &options, &mut buf);
@@ -697,8 +697,54 @@ pub struct Parse<'c> {
697697
/// "<h1>Cool input!</h1>\n<p>Wow look at this cool \
698698
/// <a href=\"https://www.rust-lang.org/\" title=\"The Rust Language\">link</a>. \
699699
/// A [broken link] renders as text.</p>\n");
700+
/// ```
700701
#[cfg_attr(feature = "arbitrary", arbitrary(default))]
701702
pub broken_link_callback: Option<Arc<dyn BrokenLinkCallback + 'c>>,
703+
704+
/// Leave footnote definitions in place in the document tree, rather than
705+
/// reordering them to the end. This will also cause unreferenced footnote
706+
/// definitions to remain in the tree, rather than being removed.
707+
///
708+
/// Comrak's default formatters expect this option to be turned off, so use
709+
/// with care if you use the default formatters.
710+
///
711+
/// ```rust
712+
/// # use comrak::{Arena, parse_document, Node, Options};
713+
/// let mut options = Options::default();
714+
/// options.extension.footnotes = true;
715+
/// let arena = Arena::new();
716+
/// let input = concat!(
717+
/// "Remember burning a CD?[^cd]\n",
718+
/// "\n",
719+
/// "[^cd]: In the Old Days, a 4x burner was considered good.\n",
720+
/// "\n",
721+
/// "[^dvd]: And DVD-RWs? Those were something else.\n",
722+
/// "\n",
723+
/// "Me neither.",
724+
/// );
725+
///
726+
/// fn node_kinds<'a>(doc: Node<'a>) -> Vec<&'static str> {
727+
/// doc.descendants().map(|n| n.data().value.xml_node_name()).collect()
728+
/// }
729+
///
730+
/// let root = parse_document(&arena, input, &options);
731+
/// assert_eq!(
732+
/// node_kinds(root),
733+
/// &["document", "paragraph", "text", "footnote_reference", "paragraph", "text",
734+
/// "footnote_definition", "paragraph", "text"],
735+
/// );
736+
///
737+
/// options.parse.leave_footnote_definitions = true;
738+
///
739+
/// let root = parse_document(&arena, input, &options);
740+
/// assert_eq!(
741+
/// node_kinds(root),
742+
/// &["document", "paragraph", "text", "footnote_reference", "footnote_definition",
743+
/// "paragraph", "text", "footnote_definition", "paragraph", "text", "paragraph", "text"],
744+
/// );
745+
/// ```
746+
#[cfg_attr(feature = "bon", builder(default))]
747+
pub leave_footnote_definitions: bool,
702748
}
703749

704750
/// The type of the callback used when a reference link is encountered with no

src/tests/footnotes.rs

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -255,27 +255,62 @@ fn sourcepos() {
255255
[extension.footnotes],
256256
"Here is a footnote reference.[^1]\n"
257257
"\n"
258+
"[^1]: Here is the footnote.\n"
259+
"\n"
258260
"Here is a longer footnote reference.[^ref]\n"
259261
"\n"
260-
"[^1]: Here is the footnote.\n"
261262
"[^ref]: Here is another footnote.\n",
262-
(document (1:1-6:33) [
263+
(document (1:1-7:33) [
263264
(paragraph (1:1-1:33) [
264265
(text (1:1-1:29) "Here is a footnote reference.")
265266
(footnote_reference (1:30-1:33))
266267
])
267-
(paragraph (3:1-3:42) [
268-
(text (3:1-3:36) "Here is a longer footnote reference.")
269-
(footnote_reference (3:37-3:42))
268+
(paragraph (5:1-5:42) [
269+
(text (5:1-5:36) "Here is a longer footnote reference.")
270+
(footnote_reference (5:37-5:42))
270271
])
271-
(footnote_definition (5:1-5:27) [
272-
(paragraph (5:7-5:27) [
273-
(text (5:7-5:27) "Here is the footnote.")
272+
(footnote_definition (3:1-3:27) [
273+
(paragraph (3:7-3:27) [
274+
(text (3:7-3:27) "Here is the footnote.")
274275
])
275276
])
276-
(footnote_definition (6:1-6:33) [
277-
(paragraph (6:9-6:33) [
278-
(text (6:9-6:33) "Here is another footnote.")
277+
(footnote_definition (7:1-7:33) [
278+
(paragraph (7:9-7:33) [
279+
(text (7:9-7:33) "Here is another footnote.")
280+
])
281+
])
282+
])
283+
);
284+
}
285+
286+
#[test]
287+
fn leave_footnote_definitions() {
288+
assert_ast_match!(
289+
[extension.footnotes, parse.leave_footnote_definitions],
290+
"Here is a footnote reference.[^1]\n"
291+
"\n"
292+
"[^1]: Here is the footnote.\n"
293+
"\n"
294+
"Here is a longer footnote reference.[^ref]\n"
295+
"\n"
296+
"[^ref]: Here is another footnote.\n",
297+
(document (1:1-7:33) [
298+
(paragraph (1:1-1:33) [
299+
(text (1:1-1:29) "Here is a footnote reference.")
300+
(footnote_reference (1:30-1:33))
301+
])
302+
(footnote_definition (3:1-3:27) [
303+
(paragraph (3:7-3:27) [
304+
(text (3:7-3:27) "Here is the footnote.")
305+
])
306+
])
307+
(paragraph (5:1-5:42) [
308+
(text (5:1-5:36) "Here is a longer footnote reference.")
309+
(footnote_reference (5:37-5:42))
310+
])
311+
(footnote_definition (7:1-7:33) [
312+
(paragraph (7:9-7:33) [
313+
(text (7:9-7:33) "Here is another footnote.")
279314
])
280315
])
281316
])

0 commit comments

Comments
 (0)