Code Line Highlight in html

Author

Shafayet Khan Shafee

Published

January 6, 2023

Modified

April 25, 2023

Note: View the source code of this document by clicking </> Code on top-right corner.

Highlighting Source Line Numbers

Example 01

Suppose we want to highlight the second line of the following code chunk, to do that, we simply use, source-line-numbers: "2". Therefore,

iris |> 
  head(5)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa

Example 02 (with source code line number)

Also, having the source code line numbered in such case would be helpful. We can do that by using source class numberLines (i.e. #| class-source: "numberLines").

Here we have highlighted line number 2 and 6 to 7 and have also added line numbers at the left side using numberLines source-class.

# library call
library(dplyr)

# code
iris |> 
  group_by(Species) |> 
  summarize(mean(Sepal.Length))
# A tibble: 3 × 2
  Species    `mean(Sepal.Length)`
  <fct>                     <dbl>
1 setosa                     5.01
2 versicolor                 5.94
3 virginica                  6.59

Highlighting on markdown formatted codeblocks

Highlighting will also works on syntactically formatted markdown code blocks (non-executable)(e.g. {.r}, {.python}, {.julia} etc)

Use source-line-numbers as code-block attributes (i.e. <attribute-name>=<value>),

```{.r source-line-numbers="1,4"}
library(dplyr)

iris |> 
  group_by(Species) |> 
  summarize(mean(Sepal.Length))
```

Therefore, the above code block is rendered as,

library(dplyr)

iris |> 
  group_by(Species) |> 
  summarize(mean(Sepal.Length))

To get line numbers, use the .numberLines class additionally on the code-block,

```{.python source-line-numbers="3-4" .numberLines}
print("Hello world")

for name in ["Sam", "Jake"]:
    print(f"Hello {name}!")
```

which is then rendered as,

print("Hello world")

for name in ["Sam", "Jake"]:
    print(f"Hello {name}!")

And you can use line-highlighting for code blocks of many different languages (languages for which pandoc supports syntax highlighting. See the list by running pandoc --list-highlight-languages if you have pandoc installed.)

```{.julia .numberLines source-line-numbers="2-4"}
for i = 1:100
    str = i % 3 == 0 ? "Fizz" : ""
    str *= i % 5 == 0 ? "Buzz" : ""
    if isempty(str)
        str = i
    end
    println(str)
end
```
for i = 1:100
    str = i % 3 == 0 ? "Fizz" : ""
    str *= i % 5 == 0 ? "Buzz" : ""
    if isempty(str)
        str = i
    end
    println(str)
end

But of course, line highlighting also works on code blocks without language class name, but you will not get the syntax highlighting,

```{.numberLines source-line-numbers="2-4"}
for i = 1:100
    str = i % 3 == 0 ? "Fizz" : ""
    str *= i % 5 == 0 ? "Buzz" : ""
    if isempty(str)
        str = i
    end
    println(str)
end
```
for i = 1:100
    str = i % 3 == 0 ? "Fizz" : ""
    str *= i % 5 == 0 ? "Buzz" : ""
    if isempty(str)
        str = i
    end
    println(str)
end

Using Highlight Marker instead of line numbers (Added in Version 1.2.0)

It is also possible to mark a line to be highlighted in the code chunk using the highlight directive #<<. Note the syntax for the highlight directive, it starts with # (which is the commenting character for r, python and julia code chunk), followed by two < sign.

iris |> 
  head(5) 
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa

And if both the source-line-numbers chunk option and highlight directive is used in a code chunk, only the lines with highlight-directive #<< will be highlighted and source-line-numbers will not have any effect.

iris |> 
  head(5)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa

Now #<< will work as a valid highlight directive only for r, python, julia code chunk, since # is a commenting character in these languages. But what if we want to highlight line in mermaid or dot code chunk. For that, #<< will not work and syntax error will be issued. Instead, we need to use these language specific commenting characters.

But this extension uses #<< as a highlight directive by default. To use different syntax for highlight directive for a code chunk, use chunk option ht-pattern to specify the highlight directive to be used for that code chunk, where the syntax should be <language-specific-commenting-character><<.

Therefore, for mermaid cell, ht-pattern should be %%<< and for dot cell, ht-pattern should be //<<. Then use these to mark a code line to be highlighted.

flowchart LR
  A[Hard edge] --> B(Round edge)
  B --> C{Decision}
  C --> D[Result one] 
  C --> E[Result two]
flowchart LR
  A[Hard edge] --> B(Round edge)
  B --> C{Decision}
  C --> D[Result one] %%<<
  C --> E[Result two]
graph G {
  layout=neato
  run -- intr;
  intr -- runbl;
  runbl -- run;
  run -- kernel;
  kernel -- zombie;
  kernel -- sleep;
  kernel -- runmem; 
  sleep -- swap;
  swap -- runswap;
  runswap -- new;
  runswap -- runmem;
  new -- runmem; 
  sleep -- runmem;
}
G run run intr intr run–intr kernel kernel run–kernel runbl runbl intr–runbl runbl–run zombie zombie kernel–zombie sleep sleep kernel–sleep runmem runmem kernel–runmem sleep–runmem swap swap sleep–swap runswap runswap swap–runswap runswap–runmem new new runswap–new new–runmem

It is also possible to use #<< to highlight lines in syntatically formatted markdown code blocks,

library(dplyr)

iris |> 
  group_by(Species) |> 
  summarize(mean(Sepal.Length)) 
print("Hello world")

for name in ["Sam", "Jake"]: 
    print(f"Hello {name}!")

Highlighting Output Line Numbers

Highlighting output line numbers a bit tricky. To enable output line number highlighting, we need to use both output class highlight and numberLines along with output-line-numbers.

Example 01

So to highlight second line of output, we use output-line-numbers: "2" and class-output: "highlight numberLines" (Sorry couldn’t make it any more easier :D :p).

mtcars |> 
  summarize(
    avg_mpg = mean(mpg)
  )
   avg_mpg
1 20.09062

Example 02

iris |> 
  group_by(Species) |> 
  summarize(mean(Sepal.Length))
# A tibble: 3 × 2
  Species    `mean(Sepal.Length)`
  <fct>                     <dbl>
1 setosa                     5.01
2 versicolor                 5.94
3 virginica                  6.59

Code Blocks within the panel-tabset, callout-blocks

To get the line-highlighting for code blocks within the panel-tabsets or Callout Blocks, you need to run the line-highlight filter after the quarto filter, like this,

---
[..other options..]
filters:
  - quarto
  - line-highlight
[..other options..]
---

This document itself has been rendered by following above (since it contains examples for the case of panel-tabset and callout-blocks). You can verify it by clicking </> Code button on top-right corner

And then line-highlight will also work for code blocks within the panel tabsets and callout blocks.

Panel Tabsets

iris |> 
  head(5)
library(dplyr) 

# code
iris |> 
  group_by(Species) |> 
  summarize(mean(Sepal.Length))

Callout Blocks

Example 1
library(dplyr)

iris |> 
  group_by(Species) |> 
  summarize(mean(Sepal.Length)) 
Example 2
print("Hello world")

for name in ["Sam", "Jake"]:
    print(f"Hello {name}!")
Example 3
for i = 1:100 
    str = i % 3 == 0 ? "Fizz" : ""
    str *= i % 5 == 0 ? "Buzz" : ""
    if isempty(str)
        str = i
    end
    println(str) 
end