Introduction

I’ve recently switched to Alacritty as my main terminal emulator (sorry st, I suck a little more, now).

I like it because:

  • It’s minimalistic and doesn’t try to do things tmux does
  • It has support for everything I need and like (undercurl FTW!) out of the box
  • I love that the cursor colour follows the text fg
  • It has a dynamic config reload

Problem

I like to switch between light and dark themes often.

There is no native keybinding to switch colorscheme in Alacritty.

Solution

Luckily, leveraging the dynamic config reload feature, we can just write to the config file using a script and, like magic, the computer will do what we want!!!

Note

If this article seems long to you, don’t worry, the solution is very simple. I’m just being thorough. The TL;DR is the Requirements and then Final Result Linux or Final Result Mac.

Requirements

We will need:

  1. An executable shell script that will
    1. Detect the current colorscheme in the alacritty config file
    2. Overwrite the string that defines the current colorscheme with the alternate colorscheme name string
    3. (Optional) Send a notification to the notification daemon telling us what happened
  2. A way to bind a key to run the shell script

That’s it!

Implementation: Linux

First things first: the script.

Requirement 1.i

above states that we need to detect the current colorscheme in the alacritty config file.

At the time of writing, the alacritty version in Arch linux is

$ alacritty --version
alacritty 0.12.2 (9d9982df)

which means we are still using the .yml config file ~/.config/alacritty/alacritty.yml

I’m using the official themese repo:

So to configure a colortheme, we follow the README verbatim:

# We use Alacritty's default Linux config directory as our storage location here.
$ mkdir -p ~/.config/alacritty/themes
$ git clone https://github.com/alacritty/alacritty-theme ~/.config/alacritty/themes

Add an import to your alacritty.yml (Replace {theme} with your desired colorscheme):

import:
  - ~/.config/alacritty/themes/themes/{theme}.yaml

I use solarized_light.yaml and solarized_dark.yaml.

So how do we “detect” this colorscheme from a shell script?

Well, grep knows how to find strings in files. grep also tells the shell whether it found the string or not using the return status.

$ grep solarized_light ~/.config/alacritty/alacritty.yml
  - ~/.config/alacritty/themes/themes/solarized_light.yaml
$ echo $?
0

Since we are going to be running this script silently, using a keybinding, we don’t want any shell output.

$ grep -q solarized_light ~/.config/alacritty/alacritty.yml
$ echo $?
0

Great! So we can know if the solarized_light colorscheme is present in the config file, and the shell will know, too.

We have satisfied this requirement.

Requirement 1.ii

Next, we need to overwrite the name we found with the other name.

Note

We are only considering “toggling” colorschemes between light and dark here. If you want to have several colorscheme options to choose from on a whim, take a look at the Alternatives section, below.

sed is great at string substitution!

$ sed -i -e "s/solarized_light/solarized_dark/" ~/.config/alacritty/alacritty.yml

In case, you’re not familiar with this command, sed is a Unix program that “edits streams” of text. Here, our text stream is the Alacritty config file, and our edit command, -e tells sed to “s/substitute_this/with_this/.

The -i parameter tells sed to modify the file in place.

And as a bonus, if we check $? we will find that here, too, sed will tell the shell whether or not it was able to succesfully do what we asked it to do.

Requirement 1.iii

It will be obvious if the colorscheme changes (if we’re in the terminal, which should be where we are when we’re deciding if we want a light or dark terminal colorscheme), however, since computers are great at providing information to us, we could also ask the computer to tell us what happened when we pushed the button.

Anywhere we can run Alacritty, we can also display notifications. (That’s not 100% true, but if you’re reading this, you’re almost certainly able to see notifications)

If you’re on a notification-capable linux system, you should have libnotify installed. If that is the case, you’ll have a utility called notify-send. We can use this utility to get the computer to tell us what’s going on. We can pass a timeout value, an application name, summary text, and a message.

I decided to structure the notification like this:

$ notify-send -t 3000 -a alacritty-theme-toggle  'Switched alacritty theme:' 'light/dark'

which will display a nice message for 3 seconds and disappear, letting me know that, once again, the computer is doing what we asked of it.

Final result: Linux

Let’s put it all together now. Remember those return status values?

bash-like shells (such as zsh) have some powerful command execution capabilities. One of those capabilities is called sublists. A sublist is a sequence of two or more “pipelines”, separated by && or ||. For our purposes, a pipeline can be thought of as a simple command (such as grep or sed).

If commands in a sublist are separated by &&, then the second command is executed only if the first one succeeds (returns a zero status). We can use this to our advantage to write a shell script with two sublists. The first one that changes the terminal colorscheme to dark if it is currently light, and the second one that does the reverse.

#!/bin/bash
CONFIG_PATH=~/.config/alacritty/alacritty.yml
TIMEOUT=3000
notify () {
    notify-send -t ${TIMEOUT} -a alacritty-theme-toggle  'Switched alacritty theme:' $1
}
grep -q solarized_light $CONFIG_PATH &&
    sed -i -e "s/solarized_light/solarized_dark/" $CONFIG_PATH &&
    notify "dark" &&
    exit
grep -q solarized_dark $CONFIG_PATH &&
    sed -i -e "s/solarized_dark/solarized_light/" $CONFIG_PATH &&
    notify "light"

That’s it!

Well, not quite. This script needs to be saved as a file in a directory that is in your $PATH variable. Setting your $PATH variable is outside the scope of this article, but there are plenty of resources available.

We also need to make the script “executable”:

$ chmod u+x ./your_amazing_script.sh

Now try opening a new shell and typing the name of the script followed by return. If you did everything correctly, the terminal’s colors should change and you should see a notification. Good Job!

To dig into the logic of the code a little, this script works because the grep command in each sublist works kind of like a conditional statement. If that command succeeded, then we can run the substitution, because it means we found the colorscheme name. If not, we skip over to the next sublist.

notify (){...} is a function that we define to make the notification command reusable in the script, and it helps readability. We pass either “light” or “dark” to this function, and this string becomes parameter 1 ($1), which we then pass along to notify-send.

Note

We have to add exit to our first sublist because we don’t want to execute the second one if we succeeded the first time. Otherwise we would just switch the colorscheme from light to dark and then dark to light again, every time.

Requirement 2

OK, we’re almost there. We have our script, and when we run it in our shell, Alacritty will reload the config file and change the current colorscheme.

Now we need a way to run this script without having to type the command in the shell every time.

I won’t go into too much detail here. How you bind keys to commands will depend a lot on the system you use. Most systems will have a keyboard shortcuts setting, or an application launcher, or both. Just find a way to get a key (I use F6) to run a command. The command that you will need to run will be the name of your script.

Here’s documentation from Ubuntu to get you going.

If something isn’t working for you at this step, make sure that the script is executable, and that the location of your script is in your $PATH.

Final result: MacOS

The good thing about MacOS is that you have all the utilities we took advantage of on Linux at your disposal. This means our script will look almost identical.

The only change we will have to make is the notification.

Requirement 1

The osascript command lets us run AppleScript from the shell.

Here’s what my notification line looks like:

$ osascript -e "display notification \"${1}\" with title \"alacritty-theme-toggle\" subtitle \"Switched alacritty theme:\""

So the final script will look like:

#!/bin/bash
CONFIG_PATH=~/.config/alacritty/alacritty.yml
notify () {
    osascript -e "display notification \"${1}\" with title \"alacritty-theme-toggle\" subtitle \"Switched alacritty theme:\""
}
grep -q solarized_light $CONFIG_PATH &&
    sed -i -e "s/solarized_light/solarized_dark/" $CONFIG_PATH &&
    notify "dark" &&
    exit
grep -q solarized_dark $CONFIG_PATH &&
    sed -i -e "s/solarized_dark/solarized_light/" $CONFIG_PATH &&
    notify "light"

I took out the TIEMOUT variable because I’m not sure how to set a timeout value with display notification, and the default duration that the notification stays for is pretty good, anyway.

Here, too, we have to make the script executable

$ chmod u+x ./your_amazing_script.sh

And place it somewhere in the $PATH.

Personally, I keep all my personal scripts in a directory such as ~/src/bin and then symlink to them from /usr/local/bin, which is in the $PATH.

$ ln -s ~/src/bin/your_amazing_script.sh /usr/local/bin/alacritty_colorscheme_toggle

Requirement 2

This one is a little more complicated on Mac.

I still haven’t found a native solution to bind keyboard shortcuts to run commands.

But I have found Karabiner-Elements, which is a super powerful keyboard customizer.

In addition to simple modifications like binding a key to a different key, Karabiner-Elements also provides “complex modifications” that can do almost anything.

I won’t go into the configuration details here, but to bind F6 (or whatever key you decided to use) to run our toggle script, use the following “rule”:

{
  "title": "Toggle Alacritty colorscheme",
  "rules": [
    {
      "description": "F6 launch toggle shell script",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "f6",
            "modifiers": { "optional": ["fn"] }
          },
          "to": [
            {
              "shell_command": "/bin/sh /usr/local/bin/alacritty_colorscheme_toggle"
            }
          ]
        }
      ]
    }
  ]
}

You will need to save this to a file, such as alacritty_colorscheme_toggle.json, and then place this file in the Karabiner-Elements complex modifications directory: ~/.config/karabiner/assets/complex_modifications/

After that, follow the instructions here to enable this rule.

Conclusion

If you’re reading this, good for you! You made it!

You should now be able to change your terminal colorscheme with the push of a button, as it were.

Enjoy!

Alternatives

Alacritty Colorscheme

There’s a well-documented utility out there called Alacritty Colorscheme.

If you prefer not mess with shell scripts and such, the instructions in the documentation for this utility are very thorough, and that tool will do what you want.

It is also the right solution if you goal is to have the ability to select among several different colorschemes.

Personally, I think the solution detailed here is much simpler and sufficient to toggle light/dark.

The disclaimer is that I haven’t actually tried this utility.

System theme switcher via shell script

After writing this I found a somewhat similar writeup, but with a much larger scope and level of detail.

This post is very much worth reading and is super awesome: https://shapeshed.com/vim-tmux-alacritty-theme-switcher/