Skip to content

Instantly share code, notes, and snippets.

@scmx
Last active January 21, 2022 00:54
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scmx/2617c680eb4927d80dfdfac3822362ea to your computer and use it in GitHub Desktop.
Save scmx/2617c680eb4927d80dfdfac3822362ea to your computer and use it in GitHub Desktop.
Script Toggle Dark Mode On/Off for Mac OS, Hyper term, Tmux and Vim #macos #hyper #tmux #vim #darkmode #applescript

Script to Toggle Dark Mode On/Off for Mac OS, Hyper term, Tmux and Vim

I had some fun pimping my development setup during my summer vacation 🏖 🏝 and here's what I came up with. A script toggle-dark-mode that toggles dark mode for not only Mac OS, but also Hyper, tmux and vim at once. I'm gonna be so productive now.. 😁

toggle-dark-mode

(I've customized Hyper term to remove dead space on top for maximized windows, but that currently also means smaller windows are missing the top row as well.)

Mac OS

tell application "System Events"
  tell appearance preferences
    set dark mode to not dark mode
  end tell
end tell

First an applescript that toggles Mac OS dark mode on/off. The osascript command can be used to run the script passed in as a heredoc.

I've currently replaced iTerm with Hyper term which is configured with ~/.hyper.js and live-reloads all windows on changes. I took the simple approach and used sed to substitute a dark mode plugin with a light mode plugin.

I use tmux heavily and have a binding since previously to toggle between dark and light status bar using a few commands. But now we want to change this for all tmux sessions 🤔. My solution (thanks @Hologos) is to run set-option without -t to send some commands to all sessions.

I'm a full-time Vim-user, specifically Neovim these days, and I typically have one or more instances in every tmux session, might be 20+. So I want all these instances to change colorscheme on command. neovim-remote to the rescue! List all neovim instances with nvr --serverlist to list the instances. After that it's easy to loop over them and send a command to change colorscheme. nvr --servername $name -cc ":colorscheme onehalfdark"

The resulting script toggle-dark-mode

#!/usr/bin/env bash

set -e

# toggle mac os dark mode
case "$1" in
  "on"|"dark")
    next_dark_mode_value="true"
    ;;
  "off"|"light")
    next_dark_mode_value="false"
    ;;
  *)
    next_dark_mode_value="not dark mode"
    ;;
esac

osascript <<APPLESCRIPT
  tell application "System Events"
    tell appearance preferences
      set dark mode to $next_dark_mode_value
    end tell
  end tell
APPLESCRIPT

hyper_config=$HOME/.hyper.js
hyper_dark_plugin=hyper-one-dark-vivid
hyper_light_plugin=hyper-one-light

if [[ $(is-dark-mode) == "true" ]]; then
  touch $HOME/.dark-mode
else
  rm -f $HOME/.dark-mode
fi

# toggle hyper term dark mode
if [[ -f $HOME/.dark-mode ]]; then
  sed -i -e "s/$hyper_light_plugin/$hyper_dark_plugin/" "$hyper_config"
else
  sed -i -e "s/$hyper_dark_plugin/$hyper_light_plugin/" "$hyper_config"
fi

if [[ $? -eq 0 ]]; then
  if [[ -f $HOME/.dark-mode ]]; then
    tmux set-option -g status-left-bg black
    tmux set-option -g status-bg black
    tmux set-option -g status-fg white
    tmux set-option -g window-status-current-bg white
    tmux set-option -g window-status-current-fg black
  else
    tmux set-option -g status-left-bg colour15
    tmux set-option -g status-bg colour15
    tmux set-option -g status-fg black
    tmux set-option -g window-status-current-bg colour12
    tmux set-option -g window-status-current-fg black
  fi
fi

# toggle vim dark mode
vim_instances=($(nvr --serverlist))

if [[ $? -eq 0 ]]; then
  for name in ${vim_instances[@]}; do
    if [[ -f $HOME/.dark-mode ]]; then
      nvr --servername "$name" -cc ":colorscheme onehalfdark"
    else
      nvr --servername "$name" -cc ":colorscheme onehalflight"
    fi
  done
fi

Gotchas

Swapping a hyper plugin in .hyper.js with sed is not optimal since it requires an internet connection when hyper runs npm install. I think another approach would be to have a separate hyper plugin that allows toggling two other plugins. Or perhaps a plugin that contains both a dark and light colorscheme and some functionality to switch between them?

@Hologos
Copy link

Hologos commented Nov 5, 2019

Hi, you don't have to call tmux set-option for every session, you can just omit -t "session-name", it's an optional parameter.

@scmx
Copy link
Author

scmx commented Nov 6, 2019

Hi, you don't have to call tmux set-option for every session, you can just omit -t "session-name", it's an optional parameter.

Cool thanks, updated! :)

@ferologics
Copy link

Did you figure out how to change the color of the status foreground? It doesn't seem to refresh when set from a script on a running session.

@scmx
Copy link
Author

scmx commented Oct 18, 2020

Did you figure out how to change the color of the status foreground? It doesn't seem to refresh when set from a script on a running session.

I think that problem happens when mixing set -g with set without -g. Setting globally will change everywhere unless it has been set locally to something else.

These days I have a little different setup. And the syntax is a little bit more concise after tmux version upgrade with new syntax.
.tmux.dark.conf

set -g status-left-style bg=black,fg=white
set -g status-style bg=black,fg=white
set -g window-status-current-style bg=blue,fg=black

.tmux.light.conf

set -g status-left-style bg=colour15,fg=black
set -g status-style bg=colour15,fg=black
set -g window-status-current-style bg=blue,fg=colour15

.tmux.conf

if-shell "[ -f ~/.dark-mode ]" \
  'source ~/.tmux.dark.conf' \
  'source ~/.tmux.light.conf'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment