hexojs/hexo-renderer-pandoc

Unexpected Changes in Article Headerlink and Missing Headerlink Icon

Closed this issue · 7 comments

After installing hero-renderer-pandoc and uninstalling hexo-renderer-marked, I've noticed some unexpected behavior in my articles. The URLs for the article Header have been altered (such as an article titled 'header 123' would generate a URL like this: https://example.com/myarticle/#header-123 originally. However, with the changes, the URL format has been altered to https://example.com/myarticle/#header123) , and the headerlink icons(as shown in the screenshot below) that usually appear at the end of the titles are missing.
image

I would appreciate some guidance on resolving this issue or any insights into what might be causing these changes.

Thank you for your assistance!

I've run into the same problem when switching from hexo-renderer-marked to hexo-renderer-pandoc.

The problem is that hexo-renderer-marked has some special handling, which adds a link element to the headings, but hexo-renderer-pandoc doesn't. Many themes depend on this behavior to show the anchor icon.

<!-- hexo-renderer-marked -->
<h3 id="Filter-Coordinate"><a href="#Filter-Coordinate" class="headerlink" title="Filter Coordinate"></a>Filter Coordinate</h3>

<!-- hexo-renderer-pandoc -->
<h3 id="filter-coordinate">Filter Coordinate</h3>

To align the behavior of hexo-renderer-pandoc with hexo-renderer-marked, I've created a Hexo script plugin, which adds the missing link element to the headings.

// FILE: scripts/fix-header-link.js
const { stripHTML } = require('hexo-util');

// When using hexo-renderer-marked, the header link is generated as follows:
// <h3 id="Filter-Coordinate"><a href="#Filter-Coordinate" class="headerlink" title="Filter Coordinate"></a>Filter Coordinate</h3>
// However, the header link generated by hexo-renderer-pandoc is:
// <h3 id="filter-coordinate">Filter Coordinate</h3>
// There are themes that rely on the "headerlink" element to show the anchor icon.
// So we need to mimic the behavior of hexo-renderer-marked.

hexo.extend.filter.register('after_post_render', (data) => {
  // https://github.com/hexojs/hexo-renderer-marked/blob/master/lib/renderer.js#L59
  data.content = data.content.replace(
    /<h([1-6]) id="(.+)">(.+?)<\/h[1-6]>/g,
    (match, level, id, content) => {
      const title = stripHTML(content);
      return `<h${level} id="${id}"><a href="#${id}" class="headerlink" title="${title}"></a>${content}</h${level}>`;
    }
  );

  return data;
});

Hope this helps. :)

One could also make a Pandoc filter, which works directly on Pandoc's internal syntax trees and is more robust than regular expressions.

I've run into the same problem when switching from hexo-renderer-marked to hexo-renderer-pandoc.

The problem is that hexo-renderer-marked has some special handling, which adds a link element to the headings, but hexo-renderer-pandoc doesn't. Many themes depend on this behavior to show the anchor icon.

<!-- hexo-renderer-marked -->
<h3 id="Filter-Coordinate"><a href="#Filter-Coordinate" class="headerlink" title="Filter Coordinate"></a>Filter Coordinate</h3>

<!-- hexo-renderer-pandoc -->
<h3 id="filter-coordinate">Filter Coordinate</h3>

To align the behavior of hexo-renderer-pandoc with hexo-renderer-marked, I've created a Hexo script plugin, which adds the missing link element to the headings.

// FILE: scripts/fix-header-link.js
const { stripHTML } = require('hexo-util');

// When using hexo-renderer-marked, the header link is generated as follows:
// <h3 id="Filter-Coordinate"><a href="#Filter-Coordinate" class="headerlink" title="Filter Coordinate"></a>Filter Coordinate</h3>
// However, the header link generated by hexo-renderer-pandoc is:
// <h3 id="filter-coordinate">Filter Coordinate</h3>
// There are themes that rely on the "headerlink" element to show the anchor icon.
// So we need to mimic the behavior of hexo-renderer-marked.

hexo.extend.filter.register('after_post_render', (data) => {
  // https://github.com/hexojs/hexo-renderer-marked/blob/master/lib/renderer.js#L59
  data.content = data.content.replace(
    /<h([1-6]) id="(.+)">(.+?)<\/h[1-6]>/g,
    (match, level, id, content) => {
      const title = stripHTML(content);
      return `<h${level} id="${id}"><a href="#${id}" class="headerlink" title="${title}"></a>${content}</h${level}>`;
    }
  );

  return data;
});

Hope this helps. :)

Wow, it works, I really appreciate you.

One could also make a Pandoc filter, which works directly on Pandoc's internal syntax trees and is more robust than regular expressions.

Following your advice, I've added a Lua script (header-link-filter.lua) in the ./source/_data directory of my Hexo project. Here's the script for reference:

-- header-link-filter.lua
function Header(el)
    -- Create a link
    local link = pandoc.Link("", "#" .. el.identifier, "", pandoc.Attr("", {"headerlink"}))
  
    -- Insert the link into the header content
    table.insert(el.content, pandoc.Space())
    table.insert(el.content, link)
  
    return el

I've also updated my _config.yml to include the Lua filter along with other Pandoc arguments:

pandoc:
  args:
    - "-f"
    - "markdown"
    - "-t"
    - "html"
    - "--mathjax"
    - '--lua-filter'
    - './source/_data/header-link-filter.lua'

Everything is working smoothly now, and the headerlink icons are appearing as expected.

On a related note, I have also achieved the same functionality by modifying the source code of the hexo-renderer-pandoc plugin. You can view my changes here.

I'm considering making a pull request with these changes. Do you think that would be a good idea, or should I stick with the current approach using the Lua filter?

Thanks again for your helpful advice!

@moon-jam Nice job! Since _config.yml provides the interface, it is better not to hard-code it into the source code and maintain it as a separate module in a separate repo. We woundn't want to force everyone to use this filter; this should be an opt-in feature.

But maybe we should start a section in readme to give references to filters!

Okay, thanks. I created a separate repository for the header-link-filter.lua script.

I hope this makes it easier for you to reference the filter in README. Let me know if there's anything else I can do to help!

Thank you! I have updated readme. Please feel free to modify it if you don't like what I wrote.