Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# [v0.42.0] - unreleased

Changed APIs:

* `html::collect_text` now returns a `String`. `html::collect_text_append` is
added if you still want to start with your own (`String`) buffer.
* There was no particular reason for this populating a `Vec<u8>` instead of a
`String`; it was just old.


# [v0.41.1] - 2025-09-14

Bug fixes:
Expand Down
26 changes: 2 additions & 24 deletions examples/headers.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// Extract the document title by srching for a level-one header at the root level.

use comrak::{
nodes::{AstNode, NodeCode, NodeValue},
parse_document, Arena, Options,
};
use comrak::{html::collect_text, nodes::NodeValue, parse_document, Arena, Options};

fn main() {
println!("{:?}", get_document_title("# Hello\n"));
Expand All @@ -25,27 +22,8 @@ fn get_document_title(document: &str) -> String {
continue;
}

let mut text = String::new();
collect_text(node, &mut text);

// The input was already known good UTF-8 (document: &str) so comrak
// guarantees the output will be too.
return text;
return collect_text(node);
}

"Untitled Document".to_string()
}

fn collect_text<'a>(node: &'a AstNode<'a>, output: &mut String) {
match node.data.borrow().value {
NodeValue::Text(ref literal) | NodeValue::Code(NodeCode { ref literal, .. }) => {
output.push_str(literal)
}
NodeValue::LineBreak | NodeValue::SoftBreak => output.push(' '),
_ => {
for n in node.children() {
collect_text(n, output);
}
}
}
}
35 changes: 19 additions & 16 deletions src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,8 @@ fn render_heading<'a, T>(
context.write_all(b">")?;

if let Some(ref prefix) = context.options.extension.header_ids {
let mut text_content = Vec::with_capacity(20);
collect_text(node, &mut text_content);

let mut id = String::from_utf8(text_content).unwrap();
id = context.anchorizer.anchorize(id);
let text_content = collect_text(node);
let id = context.anchorizer.anchorize(text_content);
write!(
context,
"<a href=\"#{}\" aria-hidden=\"true\" class=\"anchor\" id=\"{}{}\"></a>",
Expand All @@ -648,12 +645,10 @@ fn render_heading<'a, T>(
}
}
Some(adapter) => {
let mut text_content = Vec::with_capacity(20);
collect_text(node, &mut text_content);
let content = String::from_utf8(text_content).unwrap();
let text_content = collect_text(node);
let heading = HeadingMeta {
level: nh.level,
content,
content: text_content,
};

if entering {
Expand Down Expand Up @@ -1587,22 +1582,30 @@ fn render_wiki_link<'a, T>(

// Helpers

/// Recurses through a node and all of its children in depth-first (document)
/// order, returning the concatenated literal contents of text, code and math
/// blocks. Line breaks and soft breaks are represented as a single whitespace
/// character.
pub fn collect_text<'a>(node: &'a AstNode<'a>) -> String {
let mut text = String::with_capacity(20);
collect_text_append(node, &mut text);
text
}

/// Recurses through a node and all of its children in depth-first (document)
/// order, appending the literal contents of text, code and math blocks to
/// an output buffer. Line breaks and soft breaks are represented as a single
/// whitespace character.
pub fn collect_text<'a>(node: &'a AstNode<'a>, output: &mut Vec<u8>) {
pub fn collect_text_append<'a>(node: &'a AstNode<'a>, output: &mut String) {
match node.data.borrow().value {
NodeValue::Text(ref literal) | NodeValue::Code(NodeCode { ref literal, .. }) => {
output.extend_from_slice(literal.as_bytes())
}
NodeValue::LineBreak | NodeValue::SoftBreak => output.push(b' '),
NodeValue::Math(NodeMath { ref literal, .. }) => {
output.extend_from_slice(literal.as_bytes())
output.push_str(literal)
}
NodeValue::LineBreak | NodeValue::SoftBreak => output.push(' '),
NodeValue::Math(NodeMath { ref literal, .. }) => output.push_str(literal),
_ => {
for n in node.children() {
collect_text(n, output);
collect_text_append(n, output);
}
}
}
Expand Down