Update pulldown_cmark
This commit is contained in:
parent
40d7208493
commit
a67370b8d8
|
@ -2,6 +2,15 @@
|
|||
|
||||
## 0.16.0 (unreleased)
|
||||
|
||||
### Breaking
|
||||
|
||||
- Switch to pulldown-cmark anchor rather than ours, some (very niche) edge cases are not supported anymore, you can
|
||||
also specify classes on headers now
|
||||
|
||||
### Other
|
||||
- Fix markup for fenced code with linenos
|
||||
- Make `ignored_content` work with nested paths and directories
|
||||
- `zola serve/build` can now run from anywhere in a zola directory
|
||||
|
||||
## 0.15.3 (2022-01-23)
|
||||
|
||||
|
|
|
@ -2372,9 +2372,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.8.0"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
|
||||
checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"memchr",
|
||||
|
|
|
@ -25,7 +25,7 @@ svg_metadata = "0.4"
|
|||
slotmap = "1"
|
||||
lexical-sort = "0.3"
|
||||
walkdir = "2"
|
||||
pulldown-cmark = { version = "0.8", default-features = false }
|
||||
pulldown-cmark = { version = "0.9", default-features = false, features = ["simd"] }
|
||||
gh-emoji = "1"
|
||||
elasticlunr-rs = {version = "2", default-features = false, features = ["da", "no", "de", "du", "es", "fi", "fr", "it", "pt", "ro", "ru", "sv", "tr"] }
|
||||
ammonia = "3"
|
||||
|
|
|
@ -2,11 +2,13 @@ use libs::gh_emoji::Replacer as EmojiReplacer;
|
|||
use libs::once_cell::sync::Lazy;
|
||||
use libs::pulldown_cmark as cmark;
|
||||
use libs::tera;
|
||||
use std::fmt::Write;
|
||||
|
||||
use crate::context::RenderContext;
|
||||
use crate::table_of_contents::{make_table_of_contents, Heading};
|
||||
use errors::{Error, Result};
|
||||
use front_matter::InsertAnchor;
|
||||
use libs::pulldown_cmark::escape::escape_html;
|
||||
use utils::site::resolve_internal_link;
|
||||
use utils::slugs::slugify_anchors;
|
||||
use utils::vec::InsertMany;
|
||||
|
@ -37,11 +39,39 @@ struct HeadingRef {
|
|||
end_idx: usize,
|
||||
level: u32,
|
||||
id: Option<String>,
|
||||
classes: Vec<String>,
|
||||
}
|
||||
|
||||
impl HeadingRef {
|
||||
fn new(start: usize, level: u32) -> HeadingRef {
|
||||
HeadingRef { start_idx: start, end_idx: 0, level, id: None }
|
||||
fn new(start: usize, level: u32, anchor: Option<String>, classes: &[String]) -> HeadingRef {
|
||||
HeadingRef { start_idx: start, end_idx: 0, level, id: anchor, classes: classes.to_vec() }
|
||||
}
|
||||
|
||||
fn to_html(&self, id: &str) -> String {
|
||||
let mut buffer = String::with_capacity(100);
|
||||
buffer.write_str("<h").unwrap();
|
||||
buffer.write_str(&format!("{}", self.level)).unwrap();
|
||||
|
||||
buffer.write_str(" id=\"").unwrap();
|
||||
escape_html(&mut buffer, id).unwrap();
|
||||
buffer.write_str("\"").unwrap();
|
||||
|
||||
if !self.classes.is_empty() {
|
||||
buffer.write_str(" class=\"").unwrap();
|
||||
let num_classes = self.classes.len();
|
||||
|
||||
for (i, class) in self.classes.iter().enumerate() {
|
||||
escape_html(&mut buffer, class).unwrap();
|
||||
if i < num_classes - 1 {
|
||||
buffer.write_str(" ").unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
buffer.write_str("\"").unwrap();
|
||||
}
|
||||
|
||||
buffer.write_str(">").unwrap();
|
||||
buffer
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -131,10 +161,15 @@ fn get_heading_refs(events: &[Event]) -> Vec<HeadingRef> {
|
|||
|
||||
for (i, event) in events.iter().enumerate() {
|
||||
match event {
|
||||
Event::Start(Tag::Heading(level)) => {
|
||||
heading_refs.push(HeadingRef::new(i, *level));
|
||||
Event::Start(Tag::Heading(level, anchor, classes)) => {
|
||||
heading_refs.push(HeadingRef::new(
|
||||
i,
|
||||
*level as u32,
|
||||
anchor.map(|a| a.to_owned()),
|
||||
&classes.iter().map(|x| x.to_string()).collect::<Vec<_>>(),
|
||||
));
|
||||
}
|
||||
Event::End(Tag::Heading(_)) => {
|
||||
Event::End(Tag::Heading(_, _, _)) => {
|
||||
heading_refs.last_mut().expect("Heading end before start?").end_idx = i;
|
||||
}
|
||||
_ => (),
|
||||
|
@ -161,7 +196,6 @@ pub fn markdown_to_html(
|
|||
|
||||
let mut code_block: Option<CodeBlock> = None;
|
||||
|
||||
let mut inserted_anchors: Vec<String> = vec![];
|
||||
let mut headings: Vec<Heading> = vec![];
|
||||
let mut internal_links = Vec::new();
|
||||
let mut external_links = Vec::new();
|
||||
|
@ -174,6 +208,7 @@ pub fn markdown_to_html(
|
|||
opts.insert(Options::ENABLE_FOOTNOTES);
|
||||
opts.insert(Options::ENABLE_STRIKETHROUGH);
|
||||
opts.insert(Options::ENABLE_TASKLISTS);
|
||||
opts.insert(Options::ENABLE_HEADING_ATTRIBUTES);
|
||||
|
||||
if context.config.markdown.smart_punctuation {
|
||||
opts.insert(Options::ENABLE_SMART_PUNCTUATION);
|
||||
|
@ -389,45 +424,34 @@ pub fn markdown_to_html(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let mut heading_refs = get_heading_refs(&events);
|
||||
let heading_refs = get_heading_refs(&events);
|
||||
|
||||
let mut anchors_to_insert = vec![];
|
||||
|
||||
// First heading pass: look for a manually-specified IDs, e.g. `# Heading text {#hash}`
|
||||
// (This is a separate first pass so that auto IDs can avoid collisions with manual IDs.)
|
||||
for heading_ref in heading_refs.iter_mut() {
|
||||
let end_idx = heading_ref.end_idx;
|
||||
if let Event::Text(ref mut text) = events[end_idx - 1] {
|
||||
if text.as_bytes().last() == Some(&b'}') {
|
||||
if let Some(mut i) = text.find("{#") {
|
||||
let id = text[i + 2..text.len() - 1].to_owned();
|
||||
inserted_anchors.push(id.clone());
|
||||
while i > 0 && text.as_bytes()[i - 1] == b' ' {
|
||||
i -= 1;
|
||||
}
|
||||
heading_ref.id = Some(id);
|
||||
*text = text[..i].to_owned().into();
|
||||
}
|
||||
}
|
||||
let mut inserted_anchors = vec![];
|
||||
for heading in &heading_refs {
|
||||
if let Some(s) = &heading.id {
|
||||
inserted_anchors.push(s.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
// Second heading pass: auto-generate remaining IDs, and emit HTML
|
||||
for heading_ref in heading_refs {
|
||||
for mut heading_ref in heading_refs {
|
||||
let start_idx = heading_ref.start_idx;
|
||||
let end_idx = heading_ref.end_idx;
|
||||
let title = get_text(&events[start_idx + 1..end_idx]);
|
||||
let id = heading_ref.id.unwrap_or_else(|| {
|
||||
find_anchor(
|
||||
|
||||
if heading_ref.id.is_none() {
|
||||
heading_ref.id = Some(find_anchor(
|
||||
&inserted_anchors,
|
||||
slugify_anchors(&title, context.config.slugify.anchors),
|
||||
0,
|
||||
)
|
||||
});
|
||||
inserted_anchors.push(id.clone());
|
||||
));
|
||||
}
|
||||
|
||||
// insert `id` to the tag
|
||||
let html = format!("<h{lvl} id=\"{id}\">", lvl = heading_ref.level, id = id);
|
||||
inserted_anchors.push(heading_ref.id.clone().unwrap());
|
||||
let id = inserted_anchors.last().unwrap();
|
||||
|
||||
let html = heading_ref.to_html(&id);
|
||||
events[start_idx] = Event::Html(html.into());
|
||||
|
||||
// generate anchors and places to insert them
|
||||
|
@ -454,8 +478,13 @@ pub fn markdown_to_html(
|
|||
|
||||
// record heading to make table of contents
|
||||
let permalink = format!("{}#{}", context.current_page_permalink, id);
|
||||
let h =
|
||||
Heading { level: heading_ref.level, id, permalink, title, children: Vec::new() };
|
||||
let h = Heading {
|
||||
level: heading_ref.level,
|
||||
id: id.to_owned(),
|
||||
permalink,
|
||||
title,
|
||||
children: Vec::new(),
|
||||
};
|
||||
headings.push(h);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use libs::tera::Tera;
|
||||
|
||||
use config::Config;
|
||||
use errors::Result;
|
||||
use front_matter::InsertAnchor;
|
||||
use rendering::{render_content, RenderContext, Rendered};
|
||||
use rendering::{render_content, RenderContext};
|
||||
use templates::ZOLA_TERA;
|
||||
use utils::slugs::SlugifyStrategy;
|
||||
|
||||
|
@ -47,11 +45,6 @@ fn can_make_zola_internal_links() {
|
|||
fn can_handle_heading_ids() {
|
||||
let mut config = Config::default_for_test();
|
||||
|
||||
// Tested things: manual IDs; whitespace flexibility; that automatic IDs avoid collision with
|
||||
// manual IDs; that duplicates are in fact permitted among manual IDs; that any non-plain-text
|
||||
// in the middle of `{#…}` will disrupt it from being acknowledged as a manual ID (that last
|
||||
// one could reasonably be considered a bug rather than a feature, but test it either way); one
|
||||
// workaround for the improbable case where you actually want `{#…}` at the end of a heading.
|
||||
let cases = vec![
|
||||
// Basic
|
||||
"# Hello",
|
||||
|
@ -79,6 +72,8 @@ fn can_handle_heading_ids() {
|
|||
"# **hi**",
|
||||
// See https://github.com/getzola/zola/issues/569
|
||||
"# text [^1] there\n[^1]: footnote",
|
||||
// Chosen slug that already exists with space
|
||||
"# Classes {#classes .bold .another}",
|
||||
];
|
||||
let body = common::render_with_config(&cases.join("\n"), config.clone()).unwrap().body;
|
||||
insta::assert_snapshot!(body);
|
||||
|
|
|
@ -101,10 +101,10 @@ console.log(foo(5));
|
|||
<tr><td>ext</td><td>extension to be used for dest files.</td></tr>
|
||||
</tbody></table>
|
||||
<p>Right aligned columns</p>
|
||||
<table><thead><tr><th align="right">Option</th><th align="right">Description</th></tr></thead><tbody>
|
||||
<tr><td align="right">data</td><td align="right">path to data files to supply the data that will be passed into templates.</td></tr>
|
||||
<tr><td align="right">engine</td><td align="right">engine to be used for processing templates. Handlebars is the default.</td></tr>
|
||||
<tr><td align="right">ext</td><td align="right">extension to be used for dest files.</td></tr>
|
||||
<table><thead><tr><th style="text-align: right">Option</th><th style="text-align: right">Description</th></tr></thead><tbody>
|
||||
<tr><td style="text-align: right">data</td><td style="text-align: right">path to data files to supply the data that will be passed into templates.</td></tr>
|
||||
<tr><td style="text-align: right">engine</td><td style="text-align: right">engine to be used for processing templates. Handlebars is the default.</td></tr>
|
||||
<tr><td style="text-align: right">ext</td><td style="text-align: right">extension to be used for dest files.</td></tr>
|
||||
</tbody></table>
|
||||
<h2 id="links">Links</h2>
|
||||
<p><a href="http://duckduckgo.com">link text</a></p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: components/rendering/tests/markdown.rs
|
||||
assertion_line: 89
|
||||
assertion_line: 84
|
||||
expression: body
|
||||
|
||||
---
|
||||
|
@ -11,7 +11,7 @@ expression: body
|
|||
<h1 id="hello">Hello</h1>
|
||||
<h1 id="Something_else">Hello</h1>
|
||||
<h1 id="Workaround_for_literal_{#…}">Workaround for literal {#…}</h1>
|
||||
<h1 id="Auto_{#matic}">Auto {#<em>matic</em>}</h1>
|
||||
<h1 id="*matic*">Auto</h1>
|
||||
<h1 id=""></h1>
|
||||
<h1 id="-1"></h1>
|
||||
<h1 id="About"><a href="https://getzola.org/about/">About</a></h1>
|
||||
|
@ -22,5 +22,6 @@ expression: body
|
|||
<h1 id="text__there">text <sup class="footnote-reference"><a href="#1">1</a></sup> there</h1>
|
||||
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
|
||||
<p>footnote</p>
|
||||
<h1 id="classes" class="bold another">Classes</h1>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
source: components/rendering/tests/markdown.rs
|
||||
assertion_line: 84
|
||||
assertion_line: 79
|
||||
expression: body
|
||||
|
||||
---
|
||||
|
@ -11,7 +11,7 @@ expression: body
|
|||
<h1 id="hello">Hello</h1>
|
||||
<h1 id="Something_else">Hello</h1>
|
||||
<h1 id="workaround-for-literal">Workaround for literal {#…}</h1>
|
||||
<h1 id="auto-matic">Auto {#<em>matic</em>}</h1>
|
||||
<h1 id="*matic*">Auto</h1>
|
||||
<h1 id=""></h1>
|
||||
<h1 id="-1"></h1>
|
||||
<h1 id="about"><a href="https://getzola.org/about/">About</a></h1>
|
||||
|
@ -22,5 +22,6 @@ expression: body
|
|||
<h1 id="text-there">text <sup class="footnote-reference"><a href="#1">1</a></sup> there</h1>
|
||||
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
|
||||
<p>footnote</p>
|
||||
<h1 id="classes" class="bold another">Classes</h1>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -19,10 +19,10 @@ For example:
|
|||
## Example code <- example-code-1
|
||||
```
|
||||
|
||||
You can also manually specify an id with a `{#…}` suffix on the heading line:
|
||||
You can also manually specify an id with a `{#…}` suffix on the heading line as well as CSS classes:
|
||||
|
||||
```md
|
||||
# Something manual! {#manual}
|
||||
# Something manual! {#manual .header .bold}
|
||||
```
|
||||
|
||||
This is useful for making deep links robust, either proactively (so that you can later change the text of a heading
|
||||
|
|
Loading…
Reference in New Issue