sky-color-clockと仲良くする
Emacsのモードラインにいい感じの時計をいい感じに置いてみる
sky-color-clockパッケージ
sky-color-clock.elを知っていますか?時刻によって背景の色が変わる、Emacsのモードライン上に置く用の時計を実現するEmacs lispパッケージです。視覚的に時の流れを感じようという目的から、記事を読めば分かる通り、その時刻の空の色を緯度から計算していたり、月齢を計算して月の絵文字を表示したり、OpenWeatherMapのAPIを利用して天気を考慮して表示したり...などさまざまな工夫が込められており、めっちゃすごいパッケージです。
ですが、sky-color-clock.elはEmacs lispのライブラリのようなパッケージです。昔この記事を初めて読んだとき私はEmacs lispに慣れていなかったので、面白そうだなと読むだけで終わってしまいました。
さて、時は経って私のEmacs lisp力もまあまあなものになってsky-color-clockを試してみました。そしたら、いろいろといい感じにする方法がわかったので、それを記事にしたいと思います。
ということで、この記事ではsky-color-clockをいい感じに使う方法について書きます。
モードラインのどこにおくか
先の作者の解説記事ではsky-color-clockを試す方法として、sky-color-clock-initialize
などを済ました上で、以下のようにすることが挙げられています。
;; デフォルトの mode-line-format の先頭に sky-color-clock を追加 (push '(:eval (sky-color-clock)) (default-value 'mode-line-format))
こうすると sky-color-clock がモードラインの左端に現れます。
これはお手軽なのですが、私はデフォルトのモードラインが結構好きなので、急に左端に置かれてしまうのはあまり好ましくありません。sky-color-clockはモードラインの右のほう、というか右寄せして表示させたいです。
モードラインで右寄せする方法については、zk-phiさん(sky-color-clockの作者)のinit.elが非常に参考になります。また、これについて私は以前ブログの記事にしました。これを参考に右寄せします。
右寄せするために以下のような関数を定義します。
(defun sky-color-clock--form () (let* ((sky-color-clock-str (propertize (sky-color-clock) 'help-echo (format-time-string "Sky color clock\n%F (%a)"))) (mode-line-right-margin (propertize " " 'display `(space :align-to (- right-fringe ,(length sky-color-clock-str)))))) (concat mode-line-right-margin sky-color-clock-str)))
sky-color-clock--form
関数は「『right-fringeまでからsky-color-clockの長さ分だけ引いたスペース』と『sky-color-clock』をくっつけた(concat
した)文字列」を返します。これを「モードラインの一番右に表示する文字列」とすれば、sky-color-clockを右寄せで表示できますね。せっかくなので、sky-color-clockにマウスオーバーするとツールチップで今日の日付を出してくれる機能を付けました(’help-echo
の部分)。
定義した関数sky-color-clock--form
をmode-line-format
変数の中に入れます。ところで、Emacsのmode-line-format
はデフォルトでリストであり、一番後ろにmode-line-end-spaces
という変数がセットされています。これは端末でEmacsを開くときに表示される、右端まで伸びてる------に使われる変数です。今回はこの変数の中身を単純に置き換えることで、右寄せを実現します。
(setq mode-line-end-spaces '(:eval (sky-color-clock--form)))
こうすることで、(scroll-bar-mode
がdisableのとき)ちょうど右端にsky-color-clockが現れます。
右端に表示できていい感じですね。scroll-bar-mode
がenableでもdisableでもいい感じにしたい場合は、先ほど挙げた私の過去の記事が参考になると思います。
時計らしく時刻だけ表示
sky-color-clockはデフォルトで「月の絵文字」と「その日の日にち」、「時刻」を並べて表示します。「その日の日にち」の表示がいらないなら以下のようにします。
(setq sky-color-clock-format "%H:%M")
時計として使うために1分ごとに再描画
ウルトラスーパー素敵なsky-color-clockパッケージですが、私にとって少しアレだと思ったところがありました。それはEmacsをほったらかしにしておくと、時刻の表示が更新されず、時計として不正確になることです。
Emacsのモードラインは必要なときだけ再描画されます。例えば、表示してるバッファ名が変わったとき、カーソルの置かれている行数が変わったときなどです。これはつまり、逆に言えばEmacsをほったらかすと、モードラインは全然再描画されないということです。sky-color-clockはEmacsでの作業中にふと目をやる状況を想定しているので、正確に時刻を表示する必要はないのかもしれません。ですが、私は時計である以上、時刻が変わったらsky-color-clockの表示時刻も変わってほしいと思いました。
いろんなやり方があると思いますが、標準のtime.elのdisplay-time-mode
を参考にしたらなんとかいい感じにできました。
(defvar sky-color-clock--timer (run-at-time t 60 #'sky-color-clock-handler)) (defun sky-color-clock-handler () (force-mode-line-update 'all) (let* ((current (current-time)) (timer sky-color-clock--timer)) (timer-set-time timer (timer-next-integral-multiple-of-time current 60) 60)))
run-at-time
でタイマーを動かします。このタイマーは60秒ごとにsky-color-clock-handler
関数を呼び出してforce-mode-line-update
します。
60秒ごとに呼び出されても、それがちょうど0秒のときでないと意味がないので、timer-set-time
を使ってタイマーを調整しsky-color-clock-handler
(の中のforce-mode-line-update
)がちょうど0秒の時に呼び出されるようにしました。
これでEmacsを放置してても、時刻の分が切り替わるときにsky-color-clockは再描画されて、ちゃんと時計の機能を果たすようになりました。
終わり
この記事を書こうと思ったモチベの9割くらいは、1分ごとに再描画する方法について書きたかったことでした。
あと自分のプルリクがマージされて嬉しかったので書いたのもあります。
やっぱりEmacsはいろいろ拡張できていいですね。
補足
GUIなEmacsでカラー絵文字が使えていて不思議に思った人もいたかもしれません。 私はmacOSでMac port1版のEmacsを使っています。Mac port版のEmacsではカラー絵文字が表示できます。
また、(今後リリースが予定されている)Emacs 27からはGNU/Linuxでは--with-cairo付きのビルド、macOSではデフォルトでカラー絵文字が使えるようになります。 これについては、--with-cairoしてみた記事を参考にしてみてください。