Last active
March 28, 2025 09:48
-
-
Save towry/155c5e9577107d8e27b55754bab3dca5 to your computer and use it in GitHub Desktop.
macos auto dark mode with kitty+tmux+neovim. read order: install_dark_mode_notify.sh -> ke.bou.dark-mode-notify.plist -> dark_mode_changed.sh -> color_mode.py | YOU NEED TO CHANGE SOME PATH&VARIABLE to make this work.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import os | |
import sys | |
import subprocess | |
# author: https://github.com/olimorris/dotfiles/blob/main/commands/color_mode.py | |
kitty_path = "~/.config/kitty" | |
# starship_path = "~/.config/starship" | |
tmux_path = "~" | |
nvim_path = "~/.config/nvim" | |
# If we toggle dark mode via Alfred, we end up in a infinite loop. The dark-mode | |
# binary changes the MacOS mode which in turn causes color-mode-notify to run | |
# this script. This script then calls dark-mode (via the app_macos method) | |
# which kick starts this loop all over again. We use this boolean var | |
# to detect when we've run the command via the cmdline or alfred. | |
ran_from_cmd_line = False | |
# The order in which apps are changed | |
apps = [ | |
"kitty", | |
#"starship", | |
"neovim", | |
# tmux must come after neovim. | |
"tmux", | |
#"fish", | |
] | |
def app_macos(mode): | |
""" | |
Change the macOS environment | |
""" | |
path_to_file = "~/.color_mode" | |
# Open the color_mode file | |
with open(os.path.expanduser(path_to_file), "r") as config_file: | |
contents = config_file.read() | |
# Change the mode to ensure on a fresh startup, the color is remembered | |
if mode == "dark": | |
contents = contents.replace("light", "dark") | |
if ran_from_cmd_line: | |
subprocess.run(["dark-mode", "on"]) | |
if mode == "light": | |
contents = contents.replace("dark", "light") | |
if ran_from_cmd_line: | |
subprocess.run(["dark-mode", "off"]) | |
with open(os.path.expanduser(path_to_file), "w") as config_file: | |
config_file.write(contents) | |
def app_kitty(mode): | |
""" | |
Change the Kitty terminal | |
""" | |
kitty_file = kitty_path + "/theme_env.conf" | |
# Begin changing the modes | |
if mode == "dark": | |
contents = "include ./Gruvbox Material Dark Soft.conf" | |
if mode == "light": | |
contents = "include ./gruvbox/gruvbox_light_soft.conf" | |
with open(os.path.expanduser(kitty_file), "w") as config_file: | |
config_file.write(contents) | |
# Reload the Kitty config | |
# Note: For Kitty 0.23.1, this breaks it | |
try: | |
pids = subprocess.run(["pgrep", "kitty"], stdout=subprocess.PIPE) | |
pids = pids.stdout.splitlines() | |
for pid in pids: | |
try: | |
subprocess.run(["kill", "-SIGUSR1", pid]) | |
except: | |
continue | |
except IndexError: | |
pass | |
def app_starship(mode): | |
""" | |
Change the prompt in the terminal | |
""" | |
if mode == "dark": | |
return subprocess.run( | |
[ | |
"cp", | |
os.path.expanduser(starship_path + "/starship_dark.toml"), | |
os.path.expanduser(starship_path + "/starship.toml"), | |
] | |
) | |
if mode == "light": | |
return subprocess.run( | |
[ | |
"cp", | |
os.path.expanduser(starship_path + "/starship_light.toml"), | |
os.path.expanduser(starship_path + "/starship.toml"), | |
] | |
) | |
def app_tmux(mode): | |
subprocess.run( | |
[ | |
"/usr/local/bin/tmux", | |
"source-file", | |
os.path.expanduser(tmux_path + "/.tmux.conf"), | |
] | |
) | |
# return os.system("exec zsh") | |
def app_neovim(mode): | |
""" | |
Change the Neovim color scheme | |
""" | |
print("start process") | |
from pynvim import attach | |
import signal | |
# sucks https://github.com/neovim/pynvim/issues/231 | |
def handler(signum, frame): | |
raise Exception("end of time") | |
signal.signal(signal.SIGALRM, handler) | |
nvim_config = nvim_path + "/lua/towry/settings_env.lua" | |
# in your neovim config, require the settings_env.lua file by pcall. | |
# you can add settings_env.lua to gitignore. | |
if not os.path.isfile(os.path.expanduser(nvim_config)): | |
with open(os.path.expanduser(nvim_config), 'w') as fp: | |
pass | |
nvim_contents = 'vim.opt.background = "{mode}"'.format(mode=mode) | |
nvim_contents = nvim_contents.strip() | |
with open(os.path.expanduser(nvim_config), "w") as config_file: | |
config_file.write(nvim_contents) | |
# Now begin changing our open Neovim instances | |
# Get the neovim servers using neovim-remote | |
print("start nvr call") | |
servers = subprocess.run(["nvr", "--serverlist"], stdout=subprocess.PIPE) | |
servers = servers.stdout.splitlines() | |
# must exit after 2s | |
signal.alarm(2) | |
# Loop through them and change the theme by calling our custom Lua code | |
for server in servers: | |
try: | |
print("attaching to nvim") | |
nvim = attach("socket", path=server) | |
print("calling command") | |
nvim.command("call v:lua.tw.ToggleTheme('" + mode + "')") | |
print("finish call") | |
except Exception as e: | |
print(e) | |
continue | |
return | |
def app_fish(mode): | |
return subprocess.run(["/opt/homebrew/bin/fish"]) | |
def run_apps(mode=None): | |
""" | |
Based on the apps in our list, sequentially run and trigger them | |
""" | |
if mode == None: | |
mode = get_mode() | |
for app in apps: | |
getattr(sys.modules[__name__], "app_%s" % app)(mode) | |
return | |
def get_mode(): | |
""" | |
Determine what mode macOS is currently in | |
""" | |
mode = os.environ.get("DARKMODE", 1) | |
if mode == 1 or mode == "1": | |
return "dark" | |
else: | |
return "light" | |
if __name__ == "__main__": | |
# If we've passed a specific mode then activate it | |
try: | |
print("start py1") | |
if sys.argv[1]: | |
ran_from_cmd_line = True | |
run_apps(sys.argv[1]) | |
except IndexError: | |
print("start py2") | |
try: | |
run_apps() | |
except Exception as e: | |
print(e) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# called by the dark-mode-notify daemon. | |
set -e | |
export PYENV_ROOT="$HOME/.pyenv" | |
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH" | |
eval "$(pyenv init -)" | |
pyenv shell 3.11.1 | |
if ! [ $? -eq 0 ]; then | |
echo "missing python 3.11.1" | |
exit 0 | |
fi | |
echo "mode is: $DARKMODE" | |
python3 $HOME/.dotfiles/conf/commands/color_mode.py |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
Repo_Dark_Mode_Notify="https://ghproxy.com/https://github.com/pze/dark-mode-notify" | |
function build_dark_mode_bin() { | |
if [ -f "/usr/local/bin/dark-mode-notify" ]; then | |
echo "~> Bin exists" | |
return | |
fi | |
echo "~> Installing dark mode notify daemon" | |
cd /tmp | |
echo "~> Clone source repo into /tmp/dark-mode-notify" | |
git clone --depth 1 $Repo_Dark_Mode_Notify dark-mode-notify | |
cd dark-mode-notify | |
echo "~> Builing from source" | |
make build | |
echo "~> Install to /usr/local/bin/dark-mode-notify" | |
make install | |
} | |
function install_dark_mode_notify() { | |
pwd=`pwd` | |
build_dark_mode_bin | |
echo "~> Copy daemon file" | |
cp ~/.dotfiles/conf/tasks/ke.bou.dark-mode-notify.plist ~/Library/LaunchAgents/ | |
cp ~/.dotfiles/conf/commands/dark_mode_changed.sh /usr/local/bin/ | |
echo "~> Install other deps" | |
# make sure the python deps is installed by correct pip3(not system). | |
# make sure we use one specific python version. | |
export PYENV_ROOT="$HOME/.pyenv" | |
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH" | |
eval "$(pyenv init -)" | |
pyenv shell 3.11.1 | |
if ! [ $? -eq 0 ]; then | |
echo "missing python 3.11.1" | |
exit 0 | |
fi | |
pyenv exec pip install pynvim neovim-remote | |
echo "~> Launch the daemon" | |
# may have errors at first install, but just ignore it. | |
launchctl unload ~/Library/LaunchAgents/ke.bou.dark-mode-notify.plist | |
launchctl load -w ~/Library/LaunchAgents/ke.bou.dark-mode-notify.plist | |
cd $pwd | |
echo "~> 👌 Done" | |
} | |
install_dark_mode_notify |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" | |
"http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>Label</key> | |
<string>ke.bou.dark-mode-notify</string> | |
<key>KeepAlive</key> | |
<true/> | |
<key>StandardErrorPath</key> | |
<string>/tmp/dark-mode-notify-stderr.log</string> | |
<key>StandardOutPath</key> | |
<string>/tmp/dark-mode-notify-stdout.log</string> | |
<key>ProgramArguments</key> | |
<array> | |
<string>/usr/local/bin/dark-mode-notify</string> | |
<string>/usr/local/bin/dark_mode_changed.sh</string> | |
</array> | |
</dict> | |
</plist> |
Warn1
Make sure you have correct python3 && pip3 installed, otherwise the script will hang up.
So, set the PATH
in dark_mode_changed.sh correctly.
Like this:
#!/usr/bin/env bash
echo "mode is: $DARKMODE"
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH:/usr/local/bin:/usr/bin"
eval "$(pyenv init -)"
pyenv shell 3.8.2
if ! [ $? -eq 0 ]; then
echo "missing python 3.8.2"
exit 0
fi
python --version
if ! [ -x "$(command -v nvr)" ]; then
echo "nvr command not exists"
fi
echo "running color_mode.py"
python3 $HOME/.dotfiles/conf/commands/color_mode.py
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In your tmux conf, after the settings of appearance:
change code as you need. tmux depends on the neovim setting file.