Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insert anchor as full heading #1916

Merged
merged 3 commits into from
Jul 10, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

### Breaking

- Switch to pulldown-cmark anchor rather than ours, some (very niche) edge cases are not supported anymore, you can
- Switch to pulldown-cmark anchor system rather than ours, some (very niche) edge cases are not supported anymore, you can
also specify classes on headers now
- Now outputs empty taxonomies instead of ignoring them
- Unify all pages sorting variable names in templates to `lower`/`higher` in order to make it easy to re-use templates and it
was becoming hard to come up with names
was becoming hard to come up with names to be honest

### Other
- Fix markup for fenced code with linenos
Expand All @@ -24,11 +24,12 @@ any pages related to that taxonomy
- Ignore sections with `render=false` when looking for path collisions
- Add support for backlinks
- Add a warning mode for internal/external link checking in case you don't want zola to stop the build on invalid links
- Always follow symlinks
- Always follow symlinks when loading the site/assets
- Add `rel="alternate"` to Atom post links
- Fix taxonomy `current_path`
- Fix feed location for taxonomies not in the default language
- Add `title_bytes` sorting method
- Add `insert_anchor = "heading"`

## 0.15.3 (2022-01-23)

Expand Down
17 changes: 15 additions & 2 deletions components/markdown/src/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ static EMOJI_REPLACER: Lazy<EmojiReplacer> = Lazy::new(EmojiReplacer::new);
/// [uri-schemes]: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
static STARTS_WITH_SCHEMA_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^[0-9A-Za-z\-]+:").unwrap());

/// Matches a <a>..</a> tag, getting the opening tag in a capture group.
/// Used only with AnchorInsert::Heading to grab it from the template
static A_HTML_TAG: Lazy<Regex> = Lazy::new(|| Regex::new(r"(<\s*a[^>]*>).*?<\s*/\s*a>").unwrap());

/// Efficiently insert multiple element in their specified index.
/// The elements should sorted in ascending order by their index.
///
Expand Down Expand Up @@ -516,7 +520,8 @@ pub fn markdown_to_html(
let anchor_idx = match context.insert_anchor {
InsertAnchor::Left => start_idx + 1,
InsertAnchor::Right => end_idx,
InsertAnchor::None => 0, // Not important
InsertAnchor::Heading => 0, // fixed later
InsertAnchor::None => unreachable!(),
};
let mut c = tera::Context::new();
c.insert("id", &id);
Expand All @@ -530,7 +535,15 @@ pub fn markdown_to_html(
&None,
)
.context("Failed to render anchor link template")?;
anchors_to_insert.push((anchor_idx, Event::Html(anchor_link.into())));
if context.insert_anchor != InsertAnchor::Heading {
anchors_to_insert.push((anchor_idx, Event::Html(anchor_link.into())));
} else {
if let Some(captures) = A_HTML_TAG.captures(&anchor_link) {
let opening_tag = captures.get(1).map_or("", |m| m.as_str()).to_string();
anchors_to_insert.push((start_idx + 1, Event::Html(opening_tag.into())));
anchors_to_insert.push((end_idx, Event::Html("</a>".into())));
}
}
}

// record heading to make table of contents
Expand Down
3 changes: 3 additions & 0 deletions components/markdown/tests/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ fn can_insert_anchors() {
let body =
common::render_with_insert_anchor(&cases.join("\n"), InsertAnchor::Right).unwrap().body;
insta::assert_snapshot!(body);
let body =
common::render_with_insert_anchor(&cases.join("\n"), InsertAnchor::Heading).unwrap().body;
insta::assert_snapshot!(body);
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
source: components/markdown/tests/markdown.rs
expression: body
---
<h1 id="hello"><a class="zola-anchor" href="#hello" aria-label="Anchor link for: hello">Hello</a></h1>
<h1 id="world"><a class="zola-anchor" href="#world" aria-label="Anchor link for: world">World</a></h1>
<h1 id="hello-1"><a class="zola-anchor" href="#hello-1" aria-label="Anchor link for: hello-1">Hello!</a></h1>
<h2 id="rust"><a class="zola-anchor" href="#rust" aria-label="Anchor link for: rust"><a href="https://rust-lang.org">Rust</a></a></h2>
<h1 id="hello-2"><a class="zola-anchor" href="#hello-2" aria-label="Anchor link for: hello-2">Hello*_()</a></h1>

7 changes: 7 additions & 0 deletions components/utils/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,12 @@ use serde::{Deserialize, Serialize};
pub enum InsertAnchor {
Left,
Right,
Heading,
None,
}

impl InsertAnchor {
pub fn uses_template(&self) -> bool {
matches!(self, InsertAnchor::Left | InsertAnchor::Right)
}
}
5 changes: 4 additions & 1 deletion docs/content/documentation/content/linking.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ links working.

## Anchor insertion
It is possible to have Zola automatically insert anchor links next to the heading, as you can see on this documentation
if you hover a title.
if you hover a title or covering the full heading text.

This option is set at the section level: the `insert_anchor_links` variable on the
[section front matter page](@/documentation/content/section.md#front-matter).
Expand All @@ -47,6 +47,9 @@ The anchor link template has the following variables:
- `lang`: the current language, unless called from the `markdown` template filter, in which case it will always be `en`
- `level`: the heading level (between 1 and 6)

If you use `insert_anchor = "heading"`, the template will still be used but only the opening `<a>` tag will get extracted
from it, everything else will not be used.

## Internal links
Linking to other pages and their headings is so common that Zola adds a
special syntax to Markdown links to handle them: start the link with `@/` and point to the `.md` file you want
Expand Down
3 changes: 2 additions & 1 deletion docs/content/documentation/content/section.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ paginate_reversed = false
# This determines whether to insert a link for each header like the ones you can see on this site if you hover over
# a header.
# The default template can be overridden by creating an `anchor-link.html` file in the `templates` directory.
# This value can be "left", "right" or "none".
# This value can be "left", "right", "heading" or "none".
# "heading" means the full heading becomes the text of the anchor.
insert_anchor_links = "none"

# If set to "true", the section pages will be in the search index. This is only used if
Expand Down