Highlighting improvements

There are two things missing for the syntax highlighting to be really nice:

  1. line numbers: https://github.com/getzola/zola/issues/232
  2. ability to highlight spans/lines: https://github.com/getzola/zola/issues/127

For 2, syntect directly added support for highlighting so it should be straightforward.

The main blocker is how to let a user turn on those options.
See https://gohugo.io/content-management/syntax-highlighting/ for how Hugo does it but they use a shortcode instead of the classic Markdown codeblock.
This is a possibility as I don’t have a good idea on how to implement that with triple backticks since a syntax name is optional.

3 Likes

The typical approach I’ve seen is to add it to the opening code fence, treating it as comma-separated. This is how options are done in rustdoc (e.g. ```rust,ignore,compile_fail,no_run,should_panic, to use a bunch that don’t actually fit well together!).

Something like this could do it:

```rust, linenos, hl_lines=3-8 10-20

But I must remark with this that I consider line highlighting to be insufficient: I require character highlighting. My FizzBuzz article is an example; I achieved that in my current Hyde-powered site by extending its syntax highlighting with an extra step that roughly turns « into <mark> and » into </mark>. (It doesn’t work perfectly with all languages, as the « may mess up the syntax highlighter, it still being there during syntax highlighting—but it worked for Rust, and that’s all I needed at the time. For best results, this would need to be integrated into the highlighter more perfectly.)

I’m slowly working on migrating to Zola, and I expect I’ll indefinitely maintain a fork for this and other reasons. (Another sample reason: inline syntax highlighting, which pure shortcodes are insufficient for.)

It’s moderately irrelevant, but I also find myself today wanting to combine languages, like diff+javascript to highlight JavaScript in a diff. I wonder whether I’ll need to write a syntax file with it, or if there’s some other way to handle it…

That was my idea as well but markdown doesn’t require a language to be set. We could special case some keywords like linenos, hl_lines etc to avoid that issue though.

That approach definitely needs to be part of the syntax highlighter, to use the theme highlight colour. Granted you could also change the mark css manually. I had never though of character level highlighting though, that is interesting.

Sublime Text doesn’t do that so it is unlikely to happen automatically

Some themes have an insufficient contrast ratio. The default theme base16-ocean-dark for example:

  • background color: #383838
  • comment color: #95815e
  • contrast ratio: 3.1

For small text (< 18pt), the Web Content Accessibility Guidelines require a contrast ratio of 4.5 for AA compliance and 7 for AAA compliance.

That is a problem of the themes themselves, Zola is not tweaking any values.

But the themes ship with Zola, so there’s at least some form of responsibility.

https://github.com/Aloxaf/silicon has line numbers with syntect. Completely different usecases but it might be useful to look into it

It seems that we can now highlight lines thanks to this pull request : https://github.com/getzola/zola/pull/1131

Could you update the documentation page at https://www.getzola.org/documentation/content/syntax-highlighting/ about this ? for exemple :

'''bash, linenos, hl_lines=1 6 10 12-23

Secondly, what about line numbers ? isn’t it easier to add ?

1 Like

Not really, you basically need to first come up with a nice HTML structure that works and then overwrites what syntect is producing to fit in it.
It would be helpful to see how some nice JS libraries are doing it and essentially try to copy the structure, ditching the basic syntect output.

For line numbers, what about CSS counters like this post: https://www.sylvaindurand.org/using-css-to-add-line-numbering/
Doing it this way could even let you start the line numbers for a snippet on a particular number (maybe linenos=27?), which I imagine could be useful if you had code blocks that were snippets from a larger codeblock.

To implement it, would only require a tag wrapped around every line and a counter-reset style (with the initial line number) on the pre tag.

Zola themes would need to add some CSS to make this work, and a name would need to be chosen for what the line number counter should be called.

I would prefer something that doesn’t require CSS if possible.
It could be a table like Syntax Highlighting | Hugo which would make highlighting easier as well I think? It would still require some CSS though :confused:

Line Numbers

Some possible ways to do line numbers.

Table: Two rows (from Hugo)

  • (pro) Can easily select code without selecting numbers
  • (con) Need to know process full codeblock before outputting any HTML
    • This isn’t a big deal since all markdown output is queued to handle auto heading references anyway
  • (con) Numbers don’t line up with code if lines wrap (need overflow-x: scroll | auto;)
<pre style="background-color: #2b303b;">
  <code class="language-rust">
    <table>
      <tr>
        <td>1
2
3</td>
        <td>
<span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span style="color:#c0c5ce;">() {</span>
<mark style="background-color: rgb(101 115 126);">
<span style="color:#c0c5ce;">	println!("</span><span style="color:#a3be8c;">Hello World!</span><span style="color:#c0c5ce;">");
</span>
</mark>
<span style="color:#c0c5ce;">}
</span>
        </td>
      </tr>
    </table>
  </code>
</pre>

Table: Row per line

  • This is what I started working on before I looked closely at the Hugo page.
  • (pro) Code lines can wrap.
  • (con) Selecting code selects line numbers
    sample:
<pre style="background-color: #2b303b;">
  <code class="language-rust">
    <table>
      <tr>
        <td>1</td><td><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span style="color:#c0c5ce;">() {</span></td>
      </tr>
      <tr>
<td>2</td><td><mark style="background-color: rgb(101 115 126);"><span style="color:#c0c5ce;">	println!("</span><span style="color:#a3be8c;">Hello World!</span><span style="color:#c0c5ce;">");</span></mark></td>
      </tr>
      <tr>
<td>3</td><td><span style="color:#c0c5ce;">}</span></td>
        </td>
      </tr>
    </table>
  </code>
</pre>

CSS counter + wrapper

  • (pro) Lines can wrap
  • (pro) Numbers aren’t selected.
  • (con) Complex styling
  • (con) To style well, would require knowing how many lines are in codeblock (can’t process line by line).
  • (Just for fun)
<pre style="background-color: #2b303b; counter-reset: linenumbers 1; --linenum-max-digits: 1;">
  <code class="language-rust">
    <div class="line"><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span style="color:#c0c5ce;">() {</span></div>
    <div class="line"><mark style="background-color: rgb(101 115 126);"><span style="color:#c0c5ce;">	println!("</span><span style="color:#a3be8c;">Hello World!</span><span style="color:#c0c5ce;">");</span></mark></div>
<div class="line"><span style="color:#c0c5ce;">}</span></div>
  </code>
</pre>
``
Thoughts?

I think I prefer the Hugo approach (although I need to check how others JS highlighters or even Github handle it) since selecting line numbers is reaaaaaally annoying when trying to make copy/pastable snippets.

Gitlab uses per-row table lines, but places the line number in a data attribute and visualizes that via CSS.

With user-select: none; (what Github uses) any method could work.

In my opinion, a website that does not let me select any text is broken. It’s not a desktop application…

Sorry, I meant Github uses user-select: none; on only the line number portion of the line. You can still select the code.

it becomes something every theme has to add though. I’m not against it though.

@evan-brass ping me when you have something ready, I’m not paying too close attention to the PRs