emacs上のterm.elで正しくansi colorを256色表示する方法

はじめに

少し前に256色対応の設定を弄くり、、
lsで表示されるファイルの色(LS_COLORS)を様々な言語や拡張子に合わせて設定してみた Web系も関数型言語もあるよ - GeekなNooblog
ターミナルの色を最高にかっこよくする方法 - GeekなNooblog
最近は久しぶりにemacsのカスタマイズを始めました。そこでterminalもemacs上で動かしたいと思うようになり、term.elにterm+.elを追加して利用することにしました。
term+.elを選んだ理由はeshellなどとは異なり普段から使っているzshを動かすことができるためです。
その設定をするうえで色の設定でいくつか悩んだ点があったので、問題を解決するまでの過程を交えて解決方法を紹介しようと思います。


emacs 24.3を対象にした解決方法であり、恐らく過去のバージョンではうまく動作しません。
※以下の設定は通常のターミナルで既に256カラーを正しく表示できている前提で説明しています。

導入

まずはterm+.elを導入します。。
el-getを利用している場合は以下のコマンドだけでインストールできます。

M-x el-get-install
# term+ を選択

githubから持ってくる場合にはいつもどおりcloneして、init.elのload-pathにcloneしたディレクトリを登録してください。

git clone https://github.com/tarao/term-plus-el.git
(setq load-path (append                    
                 '("~/.emacs.d/term-plus-el")                          
                 load-path))               


続いてinit.elに以下の設定を追加します。

(require 'term+)
(require 'xterm-256color)

以上でterm+.elの導入は完了です。

動作確認

emacsを起動してM-x termと実行しシェルを選択します。
ミニバッファに実行するシェルを選択するよう促されるので、自分が使いたいシェルを選択してください。私はzshを選択しています。

Run program: /bin/zsh

するとemacs上でterminalが表示されます。

早速lsを実行してみると・・・

右が通常のterminal上でlsを実行したときの色、左がemacsのterm上でlsを実行したときの色です。


まったく別の色になってしまっています。

問題点解決

ぐぐってみると以下のような質問と回答が見つかりました。

Q. How can I adjust the term face in the new Emacs to get the same control that was possible with ansi-term-color-vector?

Adjusting term faces in the new Emacs 24.3 - Stack Overflow
Ans.
;; term
(defface term-color-black 
  '((t (:foreground "#3f3f3f" :background "#272822"))) 
  "Unhelpful docstring.")
(defface term-color-red
  '((t (:foreground "#cc9393" :background "#272822"))) 
  "Unhelpful docstring.")
(defface term-color-green
  '((t (:foreground "#7f9f7f" :background "#272822"))) 
  "Unhelpful docstring.")
(defface term-color-yellow
  '((t (:foreground "#f0dfaf" :background "#272822"))) 
  "Unhelpful docstring.")
(defface term-color-blue 
  '((t (:foreground "#6d85ba" :background "#272822"))) 
  "Unhelpful docstring.")
(defface term-color-magenta 
  '((t (:foreground "#dc8cc3" :background "#272822"))) 
  "Unhelpful docstring.")
(defface term-color-cyan
  '((t (:foreground "#93e0e3" :background "#272822"))) 
  "Unhelpful docstring.")
(defface term-color-white
  '((t (:foreground "#dcdccc" :background "#272822"))) 
  "Unhelpful docstring.")
'(term-default-fg-color ((t (:inherit term-color-white))))
'(term-default-bg-color ((t (:inherit term-color-black))))

;; ansi-term colors
(setq ansi-term-color-vector
  [term term-color-black term-color-red term-color-green term-color-yellow 
    term-color-blue term-color-magenta term-color-cyan term-color-white])

正しくterminalの色を適用するためには、ansi-term-color-vectorに変数を設定すればよさそうです。またansi-colorを通常のterminalと別の色にしたい場合はterm-color-whiteなどを設定してあげる必要がありそうです。
今回は通常のターミナルカラーとterm.elのカラーを同じ色に設定したいので、ansi-term-color-vectorの設定のみをinit.elに追加することにしました。

(setq ansi-term-color-vector
      [term                 
       term-color-black     
       term-color-red       
       term-color-green     
       term-color-yellow    
       term-color-blue      
       term-color-magenta   
       term-color-cyan      
       term-color-white])   


動作確認でlsを実行してみると以下のようなエラーメッセージが表示されます。

error in process filter: Args out of range: [term term-color-black term-color-red erm-color-green term-color-yellow term-color-blue term-color-magenta term-color-cyan term-color-white], 10

エラーメッセージを見るとansi-term-color-vectorのリストの外部にアクセスしているようです。
しかしエラーメッセージが表示されないこともあります。
もう少し動作確認してみると、ANSI colorの16色*1のうち通常8色を表示する場合にはエラーメッセージが表示されず、brightの8色を表示するときにエラーメッセージが表示されることがわかりました。


以上の症状からbrightの8色を表示しようとしたときにansi-term-color-vectorを参照しようとするが、値が設定されていないためにエラーとなるのではないかと考えました。

そこで単純にリストの数の不足分を補うように同じ設定を8個リストに追加してみました。

(setq ansi-term-color-vector                                                
      [term                                                                 
       term-color-black                                                     
       term-color-red                                                       
       term-color-green                                                     
       term-color-yellow                                                    
       term-color-blue                                                      
       term-color-magenta                                                   
       term-color-cyan                                                      
       term-color-white                                                     
       term-color-black                                                     
       term-color-red                                                       
       term-color-green                                                     
       term-color-yellow                                                    
       term-color-blue                                                      
       term-color-magenta                                                   
       term-color-cyan                                                      
       term-color-white])                              

もう1度確認してみると


無事エラーメッセージが表示されることなくターミナルと同様の色で表示されるようになりました。

おわりに

これでzsh on emacs 生活の始まりです!

term+.elの詳しい使い方は以下を参考にしてください。
Emacs上のターミナルを最強に: term+.el - 貳佰伍拾陸夜日記


term.elだけでは使う気にはなれませんでしたが、term+.elのおかげでまともに利用することが可能になりました。すばらしいelispありがとうございます!

*1:http://en.wikipedia.org/wiki/ANSI_escape_code#Colors]