Custom Syntax Highlighting for {distill} Part 1: Modifying the default theme

distill distilltools colour accessibility

A guide to modifying the default {distill} syntax highlighting theme, including colour choice considerations, and its implementation in {distilltools}

Ella Kaye https://twitter.com/ellamkaye
2021-05-25

TL;DR

The {distill} package for R can be used to build easy-to-maintain websites written only in R Markdown, such as this one.1

I wrote a function to modify the default syntax highlighting theme. This modify_default_highlighting function is now part of the {distilltools} package.

Here’s the function in action, to get the theme used on this site:

# get distilltools, requires remotes >= 2.2
remotes::install_github("EllaKaye/distilltools") 

library(distilltools)
modify_default_highlighting(
  name = "ek_syntax_highlighting",
  numeric = "#B6005B", # replaces the default red
  strings = "#008643", # replaces the default green
  functions = "#005BB6", # replaces the default purple
  control = "#5B00B6", # replaces the default blue
  constant = "#B65B00" # replaces the default brown
)

And here’s the theme in action:

library(dplyr)
library(palmerpenguins)

penguins %>%
  mutate(
    long_flipper = case_when(
      species == "Adelie" & flipper_length_mm > 195 ~ TRUE,
      species == "Chinstrap" & flipper_length_mm > 200 ~ TRUE,
      species == "Gentoo" & flipper_length_mm > 225 ~ TRUE,
      TRUE ~ FALSE
    )
  ) %>%
  mutate(
    long_bill = case_when(
      species == "Adelie" & bill_length_mm > 42 ~ TRUE,
      species == "Chinstrap" & bill_length_mm > 52 ~ TRUE,
      species == "Gentoo" & bill_length_mm > 50 ~ TRUE,
      TRUE ~ FALSE
    )
  )

This is the first in a series of two posts on implementing a custom syntax highlighting theme for a website or blog built with {distill}. Read on here for why and how this function was built, what it does and doesn’t do, and its inclusion in the {distilltools} package. This post also outlines the criteria that were important to me when choosing colours for my theme, but take a look at Part 2, custom syntax highlighting for {distill}: creating the palette, for a deep dive into considerations about colour choices, in respect to both colour theory and accessibility, and how I ensured my criteria were met.

But first, the default

In praise of the default

Before I delve into how to create a custom syntax highlighting scheme, I want to take a minute to admire the default. The authors of {distill}, in particular Alison Hill, have thought and worked hard to ensure that {distill} provides a good user experience, both for the site’s author AND for those reading it. One of the key considerations for the latter is a default syntax highlighting scheme with colours that are optimised for accessibility and colour contrast. I say more about what that means below and in Part 2. Also, it appears that the colours in the scheme work well together, and overall, on the many {distill} websites where I’ve seen the scheme used, I think it looks really good! For a great example of the default in action, check out this code-chunk-heavy post by Tom Mock.

So, why change?

When I used the default syntax highlighting theme on my site I found, to my eye, that the red used for numeric variables clashed with the bright pink (closest colour name “razzmatazz”) I’ve used in my logo and elsewhere throughout the site. So, I decided to tweak the default theme swapping the red for my pink and, to match it, more vibrant versions of the remaining colours.

Distill/pandoc documentation

My first task was to find out whether this was possible, and if, so, how. Thankfully, the {distill} documentation contains a section on syntax highlighting, showing that there is an option to give distill_article a path to a custom .theme file. The linked pandoc documentation on syntax highlighting demonstrates how to use pandoc in the command line to save a personal version of the pygments highlighting theme. The documentation points out that that copy of the pygments .theme file can then be edited to create a custom theme.

Finding and saving the default

Once I had a general strategy of copying and editing an existing .theme file, my next task was to find the .theme file for the default used in {distill}, because that’s what I’d already decided to take as my starting point.

I cloned the distill repo from GitHub and opened it in RStudio.2 From there I began my detective work with one of my favourite RStudio features, ‘Find in Files’ (⇧ + ⌘ + f on a Mac), which searches across all files in a project. I searched for “highlight” and followed various trails until I discovered that the default is called arrow.theme and is stored in inst/rmarkdown/templates/distill_article/resources/. Thankfully, because it’s in the inst folder, the file is accessible to users who have the {distill} package installed. In the RStudio project for my website, I created a new script, syntax_highlighting.R, in the R folder I have in my root directory, then I ran the following to save a copy of arrow.theme into my website’s root directory:

arrow_theme_path <- system.file(
  "rmarkdown/templates/distill_article/resources/arrow.theme", 
  package = "distill"
)

file.copy(arrow_theme_path, "arrow.theme")

When I had run that once, I commented out the above lines. I don’t want any future changes in arrow.theme in {distill} to break what I do next.

Closer inspection of the default

From there I could open up my copy of the arrow.theme file and manually inspect it. I use a great Mac app for building colour palettes, ColorSlurp.3 The basic version is free, though the pro version has useful features for testing accessibility - more on that in Part 2. I set up a new palette in ColorSlurp and, for each hex colour code I encountered, I saved it there.

There are 29 types of text-styles in the theme, of which:

I was happy to stick with the groupings, grey, off-black and null in the default, so now I knew I had to pick five colours for my theme.

Building my own palette

I had four criteria for building a colour palette to use for my syntax highlighting theme:

I was originally going to write up how I went about building such a palette, both in terms of the thought process and tools used, as part of this post, but it was getting a little long4, so I’ve spun it out into a separate post,custom syntax highlighting for {distill} part 2: creating the palette.

At the end of the process, the palette for my syntax highlighting scheme is as in Figure 1.

A swatch of five colours, a bright pink, orange, green, blue and purple.

Figure 1: The color palette used for syntax highlighting throughout this site.

Modifying arrow.theme

With all the pieces in place, it’s now just a case of swapping out the default colour codes for our own choices. Although it’s possible to manually edit the arrow.theme file we now have in our directory, to aid reproducibility, and with a view to writing this up as a function, I edited it using R code instead. I read in the file, substituted the hex codes, then saved the resulting theme into a new ek_syntax_highlighting.theme file (leaving arrow.theme unchanged). Below are two approaches, one using base R, the other in the tidyverse, that I put in my syntax_highlighting.R script.

# read in the default theme
theme <- readLines("arrow.theme")

# base R approach
theme <- gsub("#AD0000", "#B6005B", theme) # red -> pink
theme <- gsub("#8f5902", "#B65B00", theme) # brown -> brown 
theme <- gsub("#007BA5", "#5B00B6", theme) # blue -> purple
theme <- gsub("#20794D", "#B65B00", theme) # green -> green
theme <- gsub("#4758AB", "#005BB6", theme) # purple -> blue

# alternatively, tidyverse approach
library(stringr)
library(magrittr)

theme <- readLines("arrow.theme") %>%
   str_replace_all("#AD0000", "#B6005B") %>% # red -> pink
   str_replace_all("#8f5902", "#B65B00") %>% # brown -> brown 
   str_replace_all("#007BA5", "#5B00B6") %>% # blue -> purple
   str_replace_all("#20794D", "#008643") %>% # green -> green
   str_replace_all("#4758AB", "#005BB6")     # purple -> blue

# save new theme
writeLines(theme, "ek_syntax_highlighting.theme")

I now have the file ek_syntax_highlighting.theme in my root directory, with my colour choices.

It is, of course, possible to modify it further, either manually or by making further substutions in the code above. There is a quirk, though: if I swap one of the default hex codes for my own colour choice, that implements just fine, but if I swap any of the nulls for a colour, that doesn’t show up when I apply the theme.

Wrapping in a {distilltools} function

When I figure out code to do something that I think I might want to do again, or think others might find useful, I generally like to write it up as a function, and that’s what I’ve done with the above, wrapping it in a function called modify_default_highlighting and putting it in the {distilltools} package. {distilltools} is in the very early stages of development, an (expanding) collection of tools to support the creation and styling of content on websites created using {distill}.

When I first announced the package, I included in the ‘future functionality’ section of the package README the intention to add a create_highlight_theme function. I don’t think what I’ve done is quite versatile or fully-featured enough to warrant that name. Instead, I called it modify_default_highlighting because that’s all it does, allowing you to swap out the five colours in the default scheme for five colours of your choosing. It does, however, create a .theme file in your working directory, that can be further edited manually, or with your own R code, if further modifications are desired.

The first argument to modify_default_highlighting is name, the name you want to give your theme (which will create the file name.theme). It then takes five colour arguments, which can be specified either in the hex form “#RRGGBB” or as a named colour, from the colour names in grDevices::colors(). For a list of the colour names available in R, see page 3 of the R color cheatsheet for a one page summary, or Colors in R for a slightly less visually overwhelming list. The final argument, overwrite (defaults to TRUE) specifies whether to overwrite name.theme if it already exists in the working directory. Here’s the function in action again, this time using colour names (note that I have not tested the visual properties of this as a palette, just dropped in some colour names into the function):

library(distilltools)
modify_default_highlighting(
  name = "ek_syntax_highlighting",
  numeric = "deeppink", # replaces the default red
  strings = "forestgreen", # replaces the default green
  functions = "darkorchid3", # replaces the default purple
  control = "royalbkue3", # replaces the default blue
  constant = "darkorange1" # replaces the default brown
)

Using the theme

Once you have you custom .theme file, you’ll want to apply it to your site. According to the {distill} documentation, you can apply a syntax highlighting theme with the following YAML:

---
output:
  distill::distill_article:
    highlight: my_highlighting.theme
---  

Here, the available options for highlight include default, rstudio (the default RStudio editor theme), and the haddock, kate, monochrome, pygments and tango pandoc highlighting themes. Also, most importantly for us, it can also take the path to a .theme file.

Presumably, we should be able to add this to our _site.yml file to have the theme apply site-wide (though note you’ll have to rebuild the site and re-knit any posts where you want to it apply). However, that’s not working for me. I have raised an issue about it. If you face the same problem, it would be helpful if you could comment there too.

There is a workaround, though, which is that the above YAML can also be included in individual .Rmd articles, in which case the theme applies just fine, though note that if your .theme file is in you root directory, you’ll need to give the full path to it.5 And if it sounds like a bit of a pain to have to add that every time you write a new post, consider creating a template for your posts, including those lines, and then starting new posts with the {distilltools} function create_post_from_template().6


  1. For more on resources and inspirations for setting up a {distill} website, see my previous post, Welcome to my {distill} website.↩︎

  2. From RStudio, go to ‘File’ in the menu bar, then ‘New Project…’ Chose ‘Version Control’, then ‘Git’, then enter https://github.com/rstudio/distill.git as the ‘Repository URL:’ and click ‘Create Project’↩︎

  3. I don’t have experience of colour apps on other operating systems, but a quick search for ColorSlurp alternatives suggest there are a bunch to pick from.↩︎

  4. As part of the process of writing the post, I learnt much more about colour theory, and alternatives to the approach that I had originally taken, and I wanted to share it all!↩︎

  5. If you happen to inspect the source code for this post, you might notice that I have copied ek_syntax_highlighting.theme into the directory. This is not necessary for my site (using the full path to the .theme folder in my root directory is sufficient). However, I needed to do this to get the theme to show in the version of this post in the distillery.↩︎

  6. Note that the create_post_from_template() function is likely to get wrapped into {distill} itself, or its functionality included in distill::create_post(), and will be depreciated from {distilltools} if so. (I have had some discussion with the {distill} team about this and will be submitting a PR in the near future.)↩︎

Corrections

If you see mistakes or want to suggest changes, please create an issue on the source repository.

Reuse

Text and figures are licensed under Creative Commons Attribution CC BY-SA 4.0. Source code is available at https://github.com/EllaKaye/ellakaye-distill, unless otherwise noted. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".

Citation

For attribution, please cite this work as

Kaye (2021, May 25). ELLA KAYE: Custom Syntax Highlighting for {distill} Part 1: Modifying the default theme. Retrieved from https://ellakaye.rbind.io/posts/2021-05-25-custom-syntax-highlighting-for-distill-part-1-modifying-the-default-theme/

BibTeX citation

@misc{kaye2021custom,
  author = {Kaye, Ella},
  title = {ELLA KAYE: Custom Syntax Highlighting for {distill} Part 1: Modifying the default theme},
  url = {https://ellakaye.rbind.io/posts/2021-05-25-custom-syntax-highlighting-for-distill-part-1-modifying-the-default-theme/},
  year = {2021}
}