Switch colorscheme in terminal, vim and tmux front dark to light with one command

9

1

I'm using zsh, tmux and vim and I'd like to know how to switch between solarized dark/light in the terminal, vim, vim-airline and tmux status line with just one command.

Arturo

Posted 2017-03-19T12:36:09.890

Reputation: 91

I would love a good solution to this problem myself. Adding a bounty. – Nathan Long – 2017-08-29T17:43:40.977

Which operating system and which terminal? – 8bittree – 2017-08-29T18:29:39.440

Now that is the type of bounty I like to see!! – Pimp Juice IT – 2017-08-29T23:52:42.770

I'm using iTerm2 on MacOS. – Nathan Long – 2017-08-31T13:15:46.580

Ooh, and based on Arturo's dotfiles link, they're also using iTerm2. That will make things a bit easier, I think. – 8bittree – 2017-08-31T13:52:34.997

Haven't tried this yet, but it appears to be an answer: https://blog.browntreelabs.com/base-16-shell-and-why-its-so-awsome/

– Nathan Long – 2017-11-30T17:08:54.433

Answers

5

I've figured out a method to simultaneously toggle Solarized between light and dark for iTerm2, tmux, and Vim, with a single command from within Vim:

  1. Set up two profiles in iTerm2's preferences, one with the Solarized Dark color scheme, and one with the Solarized Light color scheme. The color presets are very helpful here, since they include both versions of Solarized.

    iterm solarized profiles

  2. Add a keyboard shortcut to each profile to switch to the other (dark switches to light, light switches to dark). I used the same shortcut for both, so it just toggles between them. You can use different shortcuts if you want, you'll just need to make a small modification to a later step.

    iterm keyboard shortcut

    In case you're not familiar with the glyphs, that's Control-Option-Shift-s. Feel free to pick something different, but remember it, we'll need it later. And I'm only showing Solarized Dark here, but don't forget to set it up for both profiles.

  3. Get yourself some tmux color schemes. I used the ones from this repository on Github. I'll refer to it's location on your computer as ~/tmux-colors-solarized.

  4. Install Solarized for Vim via your preferred method. Since we've set the 16 ANSI colors to the Solarized values in the iTerm2 profiles, we can use the standard Solarized color scheme, rather than the degraded 256 color version.

  5. Add a function to your .vimrc, and optionally a command:

    function! Solar_swap()
        if &background ==? 'dark'
            set background=light
            execute "silent !tmux source-file " . shellescape(expand('~/tmux-colors-solarized/tmuxcolors-light.conf'))
        else
            set background=dark
            execute "silent !tmux source-file " . shellescape(expand('~/tmux-colors-solarized/tmuxcolors-dark.conf'))
        endif
        silent !osascript -e 'tell app "System Events" to keystroke "s" using {shift down, option down, control down}'
    endfunction
    
    command! SolarSwap call Solar_swap()
    

    Line-by-line...ish explanation:

    function! Solar_swap()
    

    Define a function named Solar_swap that takes no parameters (). The ! on the end of function causes it to silently replace an existing function of the same name, handy if you end up sourcing your .vimrc again.

        if &background ==? 'dark'
    

    Simple check if Vim's background is currently dark. ==? does a case insensitive comparison. The & is necessary to use a setting (such as background) in an expression.

            set background=light
    

    Just setting Vim's background to light.

            execute "silent !tmux source-file " . shellescape(expand('~/tmux-colors-solarized/tmuxcolors-light.conf'))
    

    execute the following string as an Ex (i.e. :) command. silent saves us from having to press return every time. ! runs an external (to Vim) command, in this case tmux source-file [path]. The . concatenates the expanded, escaped path on to the rest of the command string.

        else
            set background=dark
            execute "silent !tmux source-file " . shellescape(expand('~/tmux-colors-solarized/tmuxcolors-dark.conf'))
        endif
    

    This chunk is basically just the light-to-dark version of the above lines.

        silent !osascript -e 'tell app "System Events" to keystroke "s" using {shift down, option down, control down}'
    

    silent ! is the same as before. osascript will run some AppleScript for us. -e means to execute the following argument as one line of a script. The line that we're running is one to send that keyboard shortcut from step 2 to the active application, which should, as far as the operating system is concerned, be iTerm2.1 You may need to modify the line to fit your choice of shortcut. Note that if you had two different shortcuts to switch iTerm2 you'll need to move this line up into the if's branches, and change the keystrokes to match.

    endfunction
    
    command! SolarSwap call Solar_swap()
    

    And finally, we close the function and define a command called SolarSwap, which calls the function we just made. ! silently replaces any existing command of the same name.

    Now, from within Vim, just run :SolarSwap and Vim, tmux, and iTerm2 should all toggle between Solarized Light and Dark. You can, of course, add a mapping to your .vimrc to make toggling even easier.


1 iTerm2 does have a proper AppleScript API of its own, however, I could not locate any means of directly changing the current tab's profile. Just ways to create new tabs, windows, or splits with a specified profile, or get the (read only) name of the current session's profile. Thus the roundabout path of setting up keyboard shortcuts and using them to switch profiles.

8bittree

Posted 2017-03-19T12:36:09.890

Reputation: 2 595

Wow! You've done a lot of work on this, and it seems right. Right now if I have a tmux split with vim on the left and a terminal on the right (two windows), this doesn't change the color of the terminal. Is that expected to work? (Going to re-check in case I missed something.) – Nathan Long – 2017-09-05T14:36:03.397

Sorry - when I said "a terminal on the right" I should have said "a zsh shell session". – Nathan Long – 2017-09-05T14:48:24.300

It seems that changing iTerm2 profiles doesn't affect zsh in my setup. – Nathan Long – 2017-09-05T14:50:05.340

I haven't quite gotten this working, but I'm awarding you the bounty. This seems really close and/or will point my way to a solution; I just haven't taken time yet to thoroughly troubleshoot. May ask more questions later. – Nathan Long – 2017-09-05T15:04:52.163

@NathanLong Thanks! I'm not entirely sure how one goes about changing the theme in zsh. My assumption would be to reset the prompts. For changing all instances of zsh, you might be able to do something by iterating through the tmux windows or tmux's child processes and sending text to any zsh instances, but I'd need to do some more research and testing to see exactly how to do that, or if it's even possible. – 8bittree – 2017-09-05T15:10:32.350

3

I'm struggling with this problem myself. I've landed on an imperfect, hacky semi-solution, but from what I've gathered, taming terminal colors is not exactly a trivial problem.

What I've found is that both tmux and vim borrow the 16 ANSI color values defined in your terminal color scheme (black, red, green, yellow, blue, magenta, cyan, white, and all their ‘bright’ variants). If in your light terminal color scheme, you invert the definitions of ANSI black & white (i.e., set black/brightblack as the light background colors and white/brightwhite as the dark foreground colors), tmux and vim will follow suit. As long as you're only using the light/dark variants of a single colorscheme, it should work decently.

enter image description here

As you can see in this screenshot, it's not perfect (front is terminal, rear is MacVim — note the differences in the airline text, as well as the illegible block of black near the middle, which is supposed to be light text on a dark background), but it gets 99% of the way there without having to touch any vim/tmux/vim-airline settings.

enter image description here

Ryan Lue

Posted 2017-03-19T12:36:09.890

Reputation: 393

1

If you're looking for a way to change the scheme from outside of vim and automatically update vim's interface, see :h t_RB. This answer references an update to the terminal query mechanism in vim version 8.0.1129, 2017.

If you want to use neovim after v0.4.0-239-g36378c33c you can use a new "Signal" autocmd: autocmd Main Signal * call Solar_swap(). Then just send neovim instances SIGUSR1 from your shell script to trigger the autocmd. For my use in linux, see my answer here.

Bart

Posted 2017-03-19T12:36:09.890

Reputation: 186