useやusingなどの宣言を綺麗にソートする(Vim編)


2010年 12月 20日

問題

先日紹介した
gitで1つのコミットを複数のコミットに分割する
例では
using等の宣言の羅列をソートする」
などのリファクタリング的な修正が別のコミットに混じっていたため、
これを1つのコミットとして分割しました。

この手の宣言文の羅列ですが、
最初のうちは綺麗にソートされた状態になるよう変更が積み重ねられていくものです。
しかし歴史のあるコードベースだと大抵誰かがひょっこりと変な位置に宣言文を追加しています。
例えば以下のような感じです:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Linq;

これは気持ち悪いのでソートしましょう。
Vimでは:sortコマンドで行のソートができます。
この場合は宣言文のどこかにカーソルを置いてvip:sort<Enter>でソートできます:

using System.Collections.Generic;
using System.Linq;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web;
using System;

ところがセミコロン(;)は0x3Bでピリオド(.)は0x2Eです。
単純にソートすると上図のように悲しい結果となります。
これを名前空間の階層に沿った綺麗な順序にソートするにはどうすればよいでしょうか。

解決方法

実は:sortには色々なオプションを指定することができます。
この例の場合、ソートの基準となるテキストは
System.Collections.Generic
などの識別子であってセミコロンは含みません。
このようにソートする場合は以下のコマンドでできます:

:sort /\S\+\ze;/ r

試しに宣言文のどこかにカーソルを置いて
vip:sort /\S\+\ze;/ r<Enter>
を実行すると結果は以下のようになります:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

/.../で正規表現が指定でき、rはその正規表現でマッチしたテキストでソートするオプションです。
\S\+\ze;はちょうどSystem.Collections.Genericなどの識別子にマッチする正規表現なので、
望み通りのソートができます。
この手法はusingに限らずC言語系文法の言語の大抵の文に応用することができますし、
正規表現を調整すれば他の用途にも応用できるでしょう。

(次回はEmacs編です)