Skip to content

Instantly share code, notes, and snippets.

@maxbucknell
Last active Mar 11, 2020
Embed
What would you like to do?
Somebody hit the lights

Alfred

I have a "lights" workflow in Alfred, that is a little AppleScript

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

This just toggles light vs. dark mode, and isn't related to the rest of it, but it's a neat utility, because I work in different places that have different lighting situations.

Shell

I wrote another tiny little Apple Script utility to tell me if dark mode is active, which Vim has used on startup for ages to know whether it should use a light or dark theme.

#! /usr/bin/env osascript
tell application "System Events"
	tell appearance preferences
		dark mode
	end tell
end tell

I use this inside Neovim to know whether the theme should be dark or light. A caveat here is that it echoes true or false, which isn't very Unixy, but Apple Script isn't very unixy and it's cool that we can even run it like this.

iTerm

Make sure you have a profile called "Light", and a profile called "Dark" inside iTerm.

I get iTerm to change the terminal theme when the system theme changes with a custom script built using their Python plugin API. It also sends a notification to every running Neovim instance using Neovim's RPC socket API, which is really neat.

I have a custom Python Script in iTerm that listens for changes to the system theme. You'll need to do "Scripts > Manage > New Python Script", then choose "Full Environment", then choose "Long-Running Daemon". In the dialog that opens up, make a directory called "AutoLaunch" inside the "Scripts" directory that is open, and name your script. I call it "dark_mode_neo", because this is a second attempt, but you can call it whatever you like. In the "PyPI Dependencies" field, enter "pynvim", so we can talk to Neovim.

The actual scripts you'll need to create are files in this gist. Both files should be added to the plugin directory. I had to make two files and call the second one as a separate process because both the iTerm API and the pynvim package use asyncio, and only one event loop is allowed to be created inside a single Python process, and neither package seemed amenable to being given an event loop. You will need to change the directories on line 22 to be correct for you.

Neovim

Then I recommend putting darkmodesocket.vim into your autoload directory, and then calling listenForLights on startup:

augroup startUp
    autocmd!

    autocmd VimEnter * call darkmodesocket#listenForLights
augroup END
#! /usr/bin/env python3
import asyncio
import iterm2
import subprocess
async def main(connection):
async with iterm2.VariableMonitor(connection, iterm2.VariableScopes.APP, "effectiveTheme", None) as mon:
# async with attach('socket', path='/tmp/nvim/nvim57620.sock') as nvim:
while True:
# Block until theme changes
theme = await mon.async_get()
app = await iterm2.async_get_app(connection)
# Themes have space-delimited attributes, one of which will be light or dark.
parts = theme.split(" ")
profile_name = 'Dark' if 'dark' in parts else 'Light'
partial_profiles = await iterm2.PartialProfile.async_query(connection)
profile = None
try:
subprocess.run(['/Users/maxbucknell/Library/ApplicationSupport/iTerm2/Scripts/AutoLaunch/dark_mode_neo/iterm2env/versions/3.8.0/bin/python3', '/Users/maxbucknell/Library/ApplicationSupport/iTerm2/Scripts/AutoLaunch/dark_mode_neo/dark_mode_neo/notify_vim.py'])
except subprocess.CalledProcessError as err:
print('Unable to notify vim: {0}'.format(err))
for partial in partial_profiles:
if partial.name == profile_name:
profile = await partial.async_get_full_profile()
for window in app.windows:
for tab in window.tabs:
for session in tab.sessions:
await session.async_set_profile(profile)
await profile.async_make_default()
iterm2.run_forever(main)
function! darkmodesocket#updateTheme()
let is_dark_mode = system("isdark")
if is_dark_mode == "true\n"
set background=dark
colorscheme maxbucknell_dark
else
set background=light
colorscheme maxbucknell_neo
endif
endfunction
function! darkmodesocket#listenForLights()
let pid = string(getpid())
let socket_name = '/tmp/nvim/nvim' . pid . '.sock'
call mkdir('/tmp/nvim', 'p')
call serverstart(socket_name)
endfunction
import glob
from pynvim import attach
nvims = [attach('socket', path=p) for p in glob.glob('/tmp/nvim/nvim*.sock')]
for nvim in nvims:
nvim.command('call darkmodesocket#updateTheme()')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment