OSのダークモードにVimのcolorschemeを追従させるプラグイン

この記事はVimAdventCalendar2020、20日目の記事です。
19日目はyutakatayさんの超融合!時空を越えた絆 Neo Vim(VSCode)を試してみたでした。

はじめに

katoと申します。(twitter)そこらへんのこーこーせーです()
スカウターで計測したvimrcの戦闘力は93ですのでたぶんよわいvimmerです。
この記事ではmacOS/Windows(多分)上で動く、OSのダークモードに合わせてVimのColorschemeを切り替えるプラグインを書いた話をします。

成果物

https://github.com/kato-k/vim-auto-color-switcher

GIFのようにmacOSの外観モードの変更に合わせて即座にカラースキームを切り替えらるプラグインです。

Windows用のソースも用意したのですが、うごきませんでした。
jobあたりでコケているはずですが、WindowsのVimの環境を作っていないので検証していません。
私にとってのWindowsはゲーム機なので仕方ないです。HITMANたのしい

発端

私はmacOS Mojaveから追加されたダークモードを頻繁に利用します
ですが、外観モードを変更する度にVimのカラースキームを変更しなければならないことに不満を抱いていました。
そこで自分で作ってみることにしました。

MacVim用であれば同じことが可能なプラグインがあるのですが、これはMacVim独自のOSAppearanceChangedと、v:os_appearanceが必要でした。
(実はこのプラグインについては作った後にVim-jp Slack教えていただきました。ありがとうございます)

使い方

詳しくはGithubのREADMEを見ていただきたいのですが、軽く説明させていただきます。

インストール

Macを利用している方で、Dein・Vim-plug等のプラグインマネージャを利用している場合、 リポジトリをvimrc等に追記・buildのオプションにmakeを追加をすることでバイナリのビルドを含めたインストールができます。

それ以外の場合

はじめに下記のようにして、バイナリを作成してください。

$ curl -l https://raw.githubusercontent.com/kato-k/vim-auto-color-switcher/main/plugin/auto_color_switcher.swift > ~/Downloads/auto_color_switcher.swift
$ swiftc ~/Downloads/auto_color_switcher.swift -o ~/Downloads/auto_color_switcher

このバイナリのパスをvimrcなどに
let g:auto_color_switcher#binary_path=expand('バイナリのパス')
のように教えてやるととひとまず動作します。

補足

この記事を投稿した後、Vim-jpでプラグインマネージャには自動でmakeする機能があることを教えていただきました。
ありがとうございます!

オプション

このままでは、backgroundを切り替えるだけなので対応していないカラースキームではよくない動作を引き起こします。
ですので、その場合は

let g:auto_color_switcher#command={
    \ 'light': 'colorscheme xcodelight',
    \ 'dark' : 'colorscheme xcodedark'
    \}

こちらのようにして、動作を上書きすることができます。

概要

OSの外観モードが変更されたタイミングでstdoutに状態を出力するコマンドを作り、Vimとお喋りさせてます。

Vim側の動作

Vimで外部プログラムと非同期に通信するには、job機能を利用します。
サーバーを立ててごにょごにょする手もあるようなのですが、そこまで高度なことをする必要もないと判断したためjobで起動したコマンドの標準出力を引っ掛けるout_cbを利用しました。

コマンドの動作 (macOSの場合)

Vim単体ではOSの外観モードを取得できないor遅い(AppleScriptを利用)ので、swiftを利用して変更の検知と通知をするコマンドを書きました。
FoundationのUserDefaultsから次のように現在の状態を取得しています。
UserDefaults.standard.string(forKey: "AppleInterfaceStyle") ?? "Light"

OSの設定の変更を検知するためにcocoaのobserver(???)を使い、変更があった時のみ↑の結果を取得するようにしています。

他OSのサポートについて

Windows

こちらはとりあえず動くソースをC#で書いてみたんですが、(多分)うごきませんでした。
WindowsのVimはまったくわかりません。
そもそも1フレームごとにレジストリにアクセスする仕様なのでHDD/SSDに負荷をかけそうで怖いです。(キャッシュに乗ってるのでしょうか)

Linux

こちらは調べてみましたが、無理です。
例えば、Ubuntuでは設定から、ダークモード・ライトモード等を切り替えることができるように見えます。
ですが、これはGNOMEの一テーマであるyaru-dark/yaru-lightを切り替えているに過ぎずwmレベル(詳しくないので間違ったこと言ってるかも)でのLight/Darkモードではありません。
UbuntuのGNOMEですらもこの有様ですから、さすがに無理と判断しました。

まとめ

このプラグインとXcodeカラースキームを一緒に利用したところ、非常にmacに馴染むVimができました。うれしいです。

OSとの親和性が気になるmacOSをお使いのVimmerの皆さん!
ぜひお使いください。

ちなみにこの記事はCotEditorで書きました。
SKK勉強してAlacrittyでも日本語打てるようにしてみようかしら?

おまけ

これまでに作ったVimプラグイン
https://github.com/kato-k/nyancat.vim
https://github.com/kato-k/vim-colorscheme-settings