zsh: diffの結果をvimで色付けして表示するグローバルエイリアス

コードを書いていると、以前のコードと現在のコードとのdiffを取りたいことがよくあります。
でも、diffの結果はちょっと読みにくい。もしdiffの結果が色付けされていたら、もっと読みやすいじゃないかと、今日ふと思いました。

そこで、zshのグローバルエイリアスを使って、diffの結果をvimで色付けして表示するようにしてみました。(.vimrcには「syntax on」と書いておきます。)

% vim ~/.zshrc
[...]
# View command results(stdout) by vim
export VIM_TMP=/tmp/vim.tmp
alias -g V="> $VIM_TMP$$; vim $VIM_TMP$$"

仕組みは簡単で、一時ファイルにコマンドの実行結果を保存して、vimでその一時ファイルを開いているだけです。一時ファイルを作っている所が、ちょっとダサいです。。。
以下のように、vimが標準入力を開くようにすれば、スマートになりますが、vimを終了するときに「:q」ではなく、「:q!」で終了しなければならなくなってしまいます。なので、僕は一時ファイルでクッションをかませる方を使うようにしました。

alias -g V="| vim -"

以下のようなコマンドを実行すれば、色付けされたdiffの結果がvimで表示されます。コマンドの最後に「 V」を付けてやるだけです。

% svn diff V
% diff -u Makefile.in.orig Makefile.in V

わかりやすさのために、diffを例にしてみましたが、上記の.zshrcのグローバルエイリアスのコードからわかるように、diff以外にも応用可能です。vimが解釈可能な形式なら何でもシンタックスハイライトしてくれます。でも、今はちょっとdiff以外への応用例は思いついていません。

追記 (2006/11/02 18:15)

hibomaのはてなダイアリー - colordiffでdiffの色づけ

diffの色づけするだけだったらcolordiff.plというのがありまっせ。
http://colordiff.sourceforge.net/

おお!そんなのがあるんですね。早速、yumでインストールしてみました。

% sudo yum install colordiff

vimでの色付けと、何かちょっとテイストが違いますね。

確かにcolordiffも便利だと思います。ただ、diffの結果が画面に収まらないくらいの量だと、スクロールの問題が出てきます。colordiffを使うと、例えば

  • lessとの相性が悪い
  • screenのバックスクロール機能(Ctrl + t(a) + [)の操作性が△

といった問題があります。
なので、グローバルエイリアスのやつの方に軍配が上がりますね。。。

本筋である、zshのグローバスエイリアスvimを噛ませてうんぬん、はいろいろ応用が利きそうですね。素敵な発想なので期待アゲです。

また何か面白い発想が出たら紹介したいと思います。

追記2 (2006/11/02 18:30)

すみません。lessで-Rオプションをつけたら、colordiffの色付けもちゃんと出るみたいです。

追記3 (2006/11/03 13:00)

vimで色付けして表示するグローバルエイリアスがイイ

どうやら読み込み専用モードで開けば一時ファイルを使わなくても良さそうです。

alias -g V="| vim -R"

本当ですね!これで一時ファイルを作らなくても済みますね。
ありがとうございます。

あ、このエイリアス、標準入力から読むようにするために、最後に「-」付けとかないとダメですね。

alias -g V="| vim -R -"

追記4 (2006/11/03 21:30)

spiritlooseのはてなダイアリー - ページャでsyntax highlight

Vim 使いは less.sh + less.vim つかってるんじゃないかなぁと思ってたんだけど。

less.vim、知りませんでした。。。まだまだ知らないことばかりです。
時間があいた時にちょっと試してみようかと思います。


鳥獣保護区 - コマンドの結果を Vim で表示

ところで zsh ならグローバルエイリアスだけでなく、プロセス置換という手もあります。

% vim =(diff fileA fileB)

一時ファイルを作ってそれを開いてるんですが、vim を終了すれば消えてしまうし、読み込み専用でないので少し編集して保存したい時なんかに使ってます。

zshのプロセス置換。これもはじめて知りました。
面白いトリックです。
このトリックも、グローバルエイリアスのやつと同様に、色々応用ができそうですね。

追記5 (2006/12/17 10:45)

ひげぽん OSとか作っちゃうかMona- - Color-SVN

IRCで教えてもらった、colorsvnで svn コマンドの出力に色がつく。

入れてみたが良いかもしれない。

ターミナルの出力を色づけするツールは、バリエーションが沢山あって面白いですね。
Color-SVNソースコードをちょっと見てみました。

% wget http://freshmeat.net/redir/colorsvn/66402/url_tgz/colorsvn-0.3.1.tar.gz
% tar zxvf colorsvn-0.3.1.tar.gz
% cd colorsvn-0.3.1
% vim colorsvn-original
#! /usr/bin/env perl

# colorsvn
#
# based on colorgcc
#
# Requires the ANSIColor module from CPAN.
#
# Usage:
#
# In a directory that occurs in your PATH _before_ the directory
# where svn lives, create a softlink to colorsvn:
#
#    svn -> colorsvn
#
# That's it. When "svn" is invoked, colorsvn is run instead.
#
# The default settings can be overridden with ~/.colorsvnrc.
# See the colorsvnrc-sample for more information.
#
# Note:
#
# colorsvn will only emit color codes if:
# 
#    (1) tts STDOUT is a tty.
#    (2) the value of $TERM is not listed in the "nocolor" option.
#    (3) the svn command is not a commit or import (as the text editor
#    opened by svn will often be hampered by colorsvn).
#
# If colorsvn colorizes the output, svn's STDERR will be
# combined with STDOUT. Otherwise, colorsvn just passes the output from
# svn through without modification.
#
[...]

use Term::ANSIColor;
use IPC::Open3;

[...]

# Keep the pid of the svn process so we can get its return
# code and use that as our return code.
$svn_pid = open3('<&STDIN', \*SVNOUT, \*SVNOUT, $svnPath, @ARGV);

[...]

# Colorize the output from the svn program.
while(<SVNOUT>)
{
    chomp;
    if (m/^ (.).+/) # Property changed only
    {   
            print($propcolors{$1}, $_, color("reset"));
    }   
    elsif (m/^(.)(\s+).+/) # S filename
    {   
        print($colors{$1}, $_, color("reset"));
    }   
    elsif (m/warning:/) # warning
    {   
        print($colors{"warning"}, $_, color("reset"));
    }   
    elsif (m/^$svnName[^:]*: / || m/^svn server: /) # server message
    {   
        print($colors{"server"}, $_, color("reset"));
    }   
    else # Anything else
    {   
        # Print normally.
        print(color("reset"), $_);
    }   
    print "\n";
}
[...]

Color-SVNPerlで書かれているみたいで、CPANモジュールのTerm::ANSIColorで色づけしているようです。
仕組みとしては簡単で、

  1. svnコマンドをIPC::Open3のopen3()で起動し、svnコマンドのSTDOUTとSTDERRを乗っ取る
  2. svnコマンドが出力するSTDOUTとSTDERRに対して、あるルールに従ってTerm::ANSIColorで色づけ

といった感じです。

Term::ANSIColorがこんな所でも使われているのですね。勉強になりました。

あと、

これ最高です!
ありがとうございました!

追記6 (2006/12/17 11:15)

先ほど追記しましたColor-SVNは「colorgcc」というツールをベースにしているようです。スルーしてました(汗

% vim colorsvn-original
#! /usr/bin/env perl

# colorsvn
#
# based on colorgcc
[...]

colorgccは、gccがあるプログラムをコンパイル中に出力する警告やエラーメッセージを色づけしてくれます。これはすごい!

これまで、僕は、gccが吐くそれらのメッセージをTerm::ANSIColorで色づけする自作スクリプトと、zshのグローバルエイリアスを組み合わせてました。
「make C」をzshで実行すると、以下のグローバルエイリアスが働いて、例えばgccのエラーメッセージを色づけするという具合です。

% vim ~/.zshrc
[...]
alias -g C=" 2>&1 | perl ~/bin/colorize.pl"

colorgccなんていうツールがあるなら、乗り換えようかなぁ。