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

Attributes on fenced code block should go on the outer <pre>, not the inner <code> #152

Open
LeaVerou opened this issue Jul 23, 2023 · 2 comments

Comments

@LeaVerou
Copy link

In general, it seems reasonable that when a Markdown structure returns multiple nested elements, that setting attributes on it would go on the container, rather than any descendant. Currently, setting attributes on a fenced code block sets them on the inner <code> element instead of the outer <pre>.

Markdown-it versions:

├── markdown-it-anchor@8.6.7
├── markdown-it-attrs@4.1.6
├── markdown-it@13.0.1

Example input:

```js { data-file="index.js" }
foo();

Current output:

<pre><code data-file="index.js" class="language-js">foo();
</code></pre>

Expected output:

<pre data-file="index.js"><code class="language-js">foo();
</code></pre>
@arve0
Copy link
Owner

arve0 commented Jul 23, 2023

Hi 👋 I believe that is a common issue that has been reported multiple times, addressed in the readme: https://github.com/arve0/markdown-it-attrs#custom-rendering

This plug-in do not alter original rendering from markdown-it.

Let me know if I’m wrong (away from computer right now 🏖️).

@TrebledJ
Copy link

TrebledJ commented Sep 5, 2024

Got this to work by copying and modifying the original fence rule.

  md.renderer.rules.fence = function (tokens, idx, options, env, slf) {
    const token = tokens[idx]
    const info = token.info ? unescapeAll(token.info).trim() : ''
    let langName = ''
    let langAttrs = ''
    
    if (info) {
      const arr = info.split(/(\s+)/g)
      langName = arr[0]
      langAttrs = arr.slice(2).join('')
    }
    
    let highlighted
    if (options.highlight) {
      highlighted = options.highlight(token.content, langName, langAttrs) || escapeHtml(token.content)
    } else {
      highlighted = escapeHtml(token.content)
    }
    
    if (highlighted.indexOf('<pre') === 0) {
      return highlighted + '\n'
    }
    
    // If language exists, inject class gently, without modifying original token.
    // May be, one day we will add .deepClone() for token and simplify this part, but
    // now we prefer to keep things local.
    if (info) {
      const i = token.attrIndex('class')
      const tmpAttrs = token.attrs ? token.attrs.slice() : []
    
      if (i < 0) {
        tmpAttrs.push(['class', options.langPrefix + langName])
      } else {
        tmpAttrs[i] = tmpAttrs[i].slice()
        tmpAttrs[i][1] += ' ' + options.langPrefix + langName
      }
    
      // Fake token just to render attributes
      const tmpToken = {
        attrs: tmpAttrs
      }

-     return `<pre><code${slf.renderAttrs(tmpToken)}>${highlighted}</code></pre>\n`
+     return `<pre${slf.renderAttrs(tmpToken)}><code class="${options.langPrefix}${langName}">${highlighted}</code></pre>\n`
    }

-   return `<pre><code${slf.renderAttrs(token)}>${highlighted}</code></pre>\n`    
+   return `<pre${slf.renderAttrs(token)}><code>${highlighted}</code></pre>\n`
  }

A bit of a dirty hack, but should be more robust than the example presented in the Custom Rendering section (which I tried, but it missed various features). This should also be more performant compared to calling the default rule then replacing with regex.

TrebledJ added a commit to TrebledJ/trebledj.github.io that referenced this issue Sep 5, 2024
11ty-syntax-hl doesn't work well with markdown-it-attr. So taking a hint from [this issue](11ty/eleventy-plugin-syntaxhighlight#72), I'm switching to markdown-it-prism, which also renders PrismJS in node.

At the same time, I decided to use a custom fence renderer which will render attributes in the `pre` block instead of the `code` block. Relevant issue: arve0/markdown-it-attrs#152.

I should also mention markdown-it-prism has a bonus of highlighting inline code blocks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants