Convince vim to use correct background color mode on Mac OS X catalina

Alec Jacobson

November 06, 2020

weblog/

Some combination of upgrading my mac os x or switching to fish shell caused my vim to be tricked into thinking the terminal is in dark mode all the time (so the colors were too light on the white background). I never found the root issue. I set out to find a way to determine if the current os configuration is in dark or light mode. This was a mess.

It seems you used to be able to issue defaults read -g AppleInterfaceStyle and it would report light or dark. Now, in catalina if you're in "Auto" mode and it's currently light, this command will fail with message:

The domain/default pair of (kCFPreferencesAnyApplication, AppleInterfaceStyle) does not exist

This deterred me and I set out to find more robust way to find the dark mode status. I tried applescript:

osascript -e 'tell application "System Events" to tell appearance preferences to get dark mode' 

This will return 'true' or 'false' for dark mode. But it's so slow!! It takes about 0.1secs to return a value.

After digging around it seems that the exit status of defaults read -g AppleInterfaceStyle can actually be used reliable to determine light or dark mode. Even if you're in "Auto" mode, this command exits successfully if and only if you're actually in dark mode. So you can just ignore the output defaults read -g AppleInterfaceStyle >/dev/null 2>&1.

This command is pretty fast but still about 20ms. Calling this in vim upon load/file open would feel a little sluggish. As a trick, I call it "after zero seconds". This lets vim load the file and then instantaneously as it's opened the background is set. As opposed to feeling the pause after issuing the open/load command:

function! SetBackgroundMode(...)
  let s:sys = system("defaults read -g AppleInterfaceStyle 2&>/dev/null")
  if v:shell_error
    set background=light
  else
    set background=dark
  endif
endfunction
" call once 'after zero seconds' so that loading is not paused
au BufRead,BufNewFile * call timer_start(0, "SetBackgroundMode", {"repeat": 0})