by Joel Tari

Switch Effortlessly Between Light and Dark Colors, in your Shell and in your IDE

These days, every editor and every terminal provide a way to configure its colors of its UI. The set of colors is commonly known as the color scheme (or colorscheme). There are hundreds of color schemes out there for you to pick. These include “Gruvbox”, “Nord”, “Monokai”, “OneDark”. Some of them mix together a large range of the color palette, while others lean on variations of a single color, like green or blue etc…

For the purpose of this post, I will simply classify them in 2 broad categories:

  • The light color schemes,
  • the dark color schemes.
a terminal editor with light colorscheme a terminal editor with dark colorscheme
Screen captures of light and dark colorschemes from Neovim

For most devs, picking their color scheme comes down to personal preference. This preference might evolve over a period of time, maybe a few weeks or months. Hence, for them there is no need to tinker with the color scheme configuration that often.

However, for the experienced outdoor roboticist, the choice of color scheme is more practical. Suppose you are the field on a sunny day, and you are monitoring and debugging your mobile robot through an ssh connection with your laptop. Working with a dark color scheme in those conditions is next to impossible as you cannot see anything on the screen. Conversely, in a shadowy area a light color scheme might be too contrasted. Then, you might want to switch back to your favorite setting in normal (office) conditions.

Switching back and forth the colors manually in all our terminals1 and all our IDEs can be tedious. Additionally, we might not want to quit our opened terminals because we want to analyze realtime logs.

Thankfully, in Linux, we can easily craft some solutions to adapt the colors quickly and efficiently.

In this post, I detail how I switch between light and dark in a few keystrokes, both in an IDE (neovim) and in the terminal (alacritty) 2.

Switch colors in alacritty terminal

The alacritty configuration is saved into the $XDG_CONFIG_HOME/alacritty/alacritty.yml file. With no surprise, the colors field is what we are looking for.

My configuration is as follows:

# my dark colors
gruvboxDark: &gruvboxDark
  primary:
    background: "#282828"
    foreground: "#ebdbb2"
  normal:
    black: "#282828"
    red: "#cc241d"
    green: "#98971a"
    yellow: "#d79921"
    blue: "#458588"
    magenta: "#b16286"
    cyan: "#689d6a"
    white: "#a89984"
  bright:
    black: "#928374"
    red: "#fb4934"
    green: "#b8bb26"
    yellow: "#fabd2f"
    blue: "#83a598"
    magenta: "#d3869b"
    cyan: "#8ec07c"
    white: "#ebdbb2"

# my light colors
gruvboxLight: &gruvboxLight
  primary:
    background: "#ffffff"
    foreground: "#1a1b17"
  normal:
    black: "#fbf1c7"
    red: "#cc241d"
    green: "#5F5F10"
    yellow: "#d79921"
    blue: "#458588"
    magenta: "#b16286"
    cyan: "#689d6a"
    white: "#7c6f64"
  bright:
    black: "#928374"
    red: "#9d0006"
    green: "#79740e"
    yellow: "#b57614"
    blue: "#076678"
    magenta: "#8f3f71"
    cyan: "#427b58"
    white: "#3c3836"

# the loaded colors
colors: *gruvboxDark #Light

The fields gruvboxLight and gruvboxDark are custom entries that contain the color values in hex format. By themselves they have no effect on the drawn colors, unless they are selected by the colors field through this pointer inspired syntax. In this instance, the dark colors are pointed to.

To switch to light colors, I can edit the last line to:

colors: *gruvboxLight #Dark

It is a nice perk of alacritty that live terminal sessions are reactive to change in the config file.

Of course, we don’t want to manually edit that. In fact, I use a sed command to switch this line for me.

You might notice that I’ve left out a trailing comment #Light/#Dark in the line of interest. This is because I want my sed program to capture the current color (resp. Light or Dark) and the commented color (resp. Dark or Light), and then switch places.

This is achieved by using “captured group” in the regular expression:

sed 's/colors: \*gruvbox\(.*\) #\(.*\)/colors: \*gruvbox\2 #\1/' \
      $XDG_CONFIG_HOME/alacritty/alacritty.yml \
      -i --follow-symlinks

Inside the sed “find” regular expression, the current color gets saved into the first capture \1, and the commented color gets saved into the second capture group \2. The “replace” regular expression simply flip the positions of both captured items.

The sed flags:

  • -i edit the file in-place,
  • --follow-symlinks edits the file anyway if $XDG_CONFIG_HOME/alacritty/alacritty.yml is in fact a symlink. As implied, this flag is not necessary unless, your config files (dotfiles) are located in an out-of-tree repository that distributes soft symbolic links in your $XDG paths.

This command can then be easily called in the shell since it is now in your $PATH. You can even bind a shortcut to it in your desktop manager.

Adapting this approach to some other color scheme than gruvbox is straightforward. We could even be agnostic to the color scheme name by simply using mycolorsDark instead of gruvboxDark and defer the interpretation of mycolors to another variable in the config.

We now turn our attention to switching the colors in our editor (or IDE).

Switch colors in neovim

Switching dark and light colors, with a shortcut, is a smoother process. In neovim (and vim for that matter), we can get or set the current color via the option background (use :set background in ex mode).

Trivially, I map the shortcut <space>y (‘space’ then ‘y’) to make the switch in my init.lua config:

vim.keymap.set("nv","<space>y",function()
  if vim.o.background=="light" then
    vim.o.background="dark"
  else
    vim.o.background="light"
  end
end,{noremap=true,silent=true})

Here, I have used the vim.keymap.set API to add this shortcut in normal and visual mode (the "nv" part). If the current background option is set to light (resp. dark), it becomes dark (resp. light).

Alternatively, you could also change the function content, where instead of changing the background option, you would load another color scheme via vim.cmd("colorscheme myFavoriteColorschemeForLightMode").


Footnotes

  1. In a ROS framework, the number of monitoring terminals (e.g. rostopic echo /cmd_vel) is at least linear in the number of nodes of interest in the system. Even if you group them with a tool like tmux, as I will recommend in an upcoming post, you might still open several instances to view them simultaneously.

  2. As is often the case in this blog, what’s important is not so much the specific terminal/IDE software used, but the approach proposed and its philosophy, which in my experience can be easily transfered on other free & open source software.