[emacs] powerline.el + windows.el だと mode line が残念なことになったので修正した.

前々から気にはなっていましたが, それほど急いで導入するほどでもないかなーと思っていた powerline を, こちらのサイト を参考にして導入してみました.

とりあえず入れた直後は「おー, こりゃ cool だ! 」といった感じでしたが, 私の環境ではいくつか不都合がありました. (しかも致命的)

  • windows.el を使っていると, そもそも mode-line が消える orz
  • git とかの管理下にあるファイルを開くと mode-line が消える orz

1 点目はとてつもなく致命的で, 基本的に一回でも windows.el でウィンドウ構成を切り替えると, 何もしなければ未来永劫 mode-line は復活しません.

2 点目もかなり致命的で, 私は最近ソースを弄る時には SCM を必ず利用するようにしているため, それらのソースを開くとこれまた mode-line が見えなくなります. ただし, この場合は 1 点目よりはまだましで, SCM の管理下ではないバッファを開けばとりあえず問題はありません.

まだ windows.el を利用している人がどれくらいいるのかは甚だ疑問ではありますが, 自分の環境では上が直らないとせっかくのいけてる powerline.el が使えませんので, 修正してみました.
以下がその diff になります.

*** /home/derui/.emacs.d/auto-install/powerline.el	2012-05-03 09:22:47.390059651 +0900
--- /home/derui/.emacs.d/auto-install/powerline.el.mod	2012-05-03 09:10:22.249108844 +0900
***************
*** 346,356 ****
diff -c /home/derui/.emacs.d/auto-install/powerline.el /home/derui/.emacs.d/auto-install/powerline.el.mod
*** /home/derui/.emacs.d/auto-install/powerline.el	2012-05-03 10:31:52.939418976 +0900
--- /home/derui/.emacs.d/auto-install/powerline.el.mod	2012-05-03 10:29:52.926426900 +0900
***************
*** 345,356 ****
              (propertize string 'face plface 'mouse-face plface 'local-map localmap)
            (propertize string 'face plface))
        "")))
  (defun powerline-make (side string color1 &optional color2 localmap)
!   (cond ((and (eq side 'right) color2) (powerline-make-right  string color1 color2 localmap))
!         ((and (eq side 'left) color2)  (powerline-make-left   string color1 color2 localmap))
!         ((eq side 'left)               (powerline-make-left   string color1 color1 localmap))
!         ((eq side 'right)              (powerline-make-right  string color1 color1 localmap))
!         (t                             (powerline-make-text   string color1 localmap))))
  (defmacro defpowerline (name string)
    `(defun ,(intern (concat "powerline-" (symbol-name name)))
       (side color1 &optional color2)
--- 345,369 ----
              (propertize string 'face plface 'mouse-face plface 'local-map localmap)
            (propertize string 'face plface))
        "")))
+ (defun powerline-print-func (ls)
+   (cond ((stringp ls) ls)
+         ((symbolp ls)
+          (cond ((and (not (eq ls nil)) (not (eq ls t)))
+                 (powerline-print-func (symbol-value ls)))
+                (t "")))
+         ((listp ls)
+          (let ((tmp ""))
+            (dolist (i ls)
+              (setq tmp (concat tmp (powerline-print-func i))))
+            tmp))
+         (t "")))
  (defun powerline-make (side string color1 &optional color2 localmap)
!     (let ((real-string (powerline-print-func string)))
!       (cond ((and (eq side 'right) color2) (powerline-make-right  real-string color1 color2 localmap))
!             ((and (eq side 'left) color2)  (powerline-make-left   real-string color1 color2 localmap))
!             ((eq side 'left)               (powerline-make-left   real-string color1 color1 localmap))
!             ((eq side 'right)              (powerline-make-right  real-string color1 color1 localmap))
!             (t                             (powerline-make-text   real-string color1 localmap)))))
  (defmacro defpowerline (name string)
    `(defun ,(intern (concat "powerline-" (symbol-name name)))
       (side color1 &optional color2)
***************
*** 434,440 ****
  (defpowerline emacsclient mode-line-client)
  (defpowerline vc          (when (and (buffer-file-name (current-buffer))
                                       vc-mode)
!                                   vc-mode-line))
  (defpowerline percent-xpm (propertize "  "
                                        'display
                                        (let (pmax
--- 447,453 ----
  (defpowerline emacsclient mode-line-client)
  (defpowerline vc          (when (and (buffer-file-name (current-buffer))
                                       vc-mode)
!                             vc-mode))
  (defpowerline percent-xpm (propertize "  "
                                        'display
                                        (let (pmax

修正点とか

結局何が問題だったのかは, diff を見ていただければわかると思いますが, windows.el の場合はちょっとわかりづらいし, 自分の備忘録も兼ねて書いておきます.

windows.el を利用している時に mode-line に表示される [a] とかは, windows.el で定義されている win:mode-string という変数に格納されています.

で, これが global-mode-string というグローバル変数に入れられ, それが mode-line に表示されているのですが, windows.el の作法が悪いのか powerline.el の処理が足らなかったのか, その辺はよくわかりませんが, windows.el では以下のような形で global-mode-string に win:mode-string を格納していました.

(or global-mode-string (setq global-mode-string '("")))
(or (memq 'win:mode-string global-mode-string)
    (setq global-mode-string (append global-mode-string '(win:mode-string))))

global-mode-string が nil だったら初期値として空文字列だけを要素とするリストを代入しています. つまりはこの時点で, global-mode-string はリストになっている, ということなのですが.

ここで, powerline.el での肝 (たぶん) となる関数を見てみると・・・.

(defun powerline-make (side string color1 &optional color2 localmap)
  (cond ((and (eq side 'right) color2) (powerline-make-right  string color1 color2 localmap))
        ((and (eq side 'left) color2)  (powerline-make-left   string color1 color2 localmap))
        ((eq side 'left)               (powerline-make-left   string color1 color1 localmap))
        ((eq side 'right)              (powerline-make-right  string color1 color1 localmap))
        (t                             (powerline-make-text   string color1 localmap))))

上の関数は, defpowerline マクロで呼ばれている関数ですが, この第二引数に global-mode-string が渡されています. ちなみに, さらに渡されている powerline-make-* では, propertize に利用されているだけなので, つまりはただの文字列でないとなりません.

・・・というわけで、ここに渡ってきたリストやらなんやらの中身について、シンボルとかリストとかなら展開して、文字列ならそのまま、それ以外は空文字列として扱うことにしました。mewとかもこれで一先ずは動いているようです。

vc-mode の方は多分 typo だとは思いますが, 元の vc-mode-line は関数なので, 評価したところで void-variable となってしまいます. vc-mode というのが, mode-line に出力されている文字列のようでしたので, vc-mode-line を vc-mode に変えただけです.

おわりに

powerline.el は vim script で作成された vim powerline を参考に作られたようです. 最近はてブとかでも, どうにも vimmer の勢力が強くなってきているような感じがひしひしと伝わってきます. 色々弄りつつ 3 年くらい利用してきている人間としてはそろそろ離れるのが辛くなってきているので, これからもよさげなものは vim からもどんどん取り入れていったらいいんじゃないかと思います.
私はあまり elisp を作成するのに積極的ではありませんが・・・

それでは powerline.el で cool になった emacs をお楽しみください.