Drift Diary XV

Code beautifier and formatter with Xcode

Posted by drikin on 2009年4月19日 22:32
ReplyIconView.m
最近とある事情により数年ぶりにEclipseを使う日々。2002年頃以来なので、OSXでの進化っぷりに感動するも、やっぱりちょっと違和感を感じる日々だったのですが、唯一、Eclipseの強力なコード整形機能だけは、惹かれていて、これだけのためにEclipseメインな環境も悪くないかなとか思ってしまう今日この頃でした。

が!!、週末、半ば偶然にもhipposさんのuncrustifyをXCodeで便利に使うという記事を拝見し、自分の中で、密かな、長年のテーマであった「Xcodeにおけるコード整形」を実現したので、ほとんどhipposさんの記事の焼き直しですが、メモっておきたいと思います。

基本的な流れは、外部のコード整形プログラムをXcodeのスクリプトメニューから呼び出せるように設定し、コンパイル時に、ここのソースコードにスクリプトを適応するという内容です。今回調べた感じだと、Objective-Cに対応した、ソースコードの整形プログラムは、bcppとuncrustifyくらいでした。bcppのほうがシンプルな感じでしたが、どっちも試しつつ、今回は細かい設定が可能なuncrustifyで説明します。

Step 1: uncrustifyのインストール

uncrustifyのインストールは至って簡単で、HPから最新のソースコードをダウンロードして、展開したフォルダに移動し
  • ./configure
  • make
  • sudo make install
するだけ。これで、/usr/local/bin/uncrustifyあたりにuncrustifyがインストールされます。また、展開して、ビルドしたuncrustifyフォルダには、tests/configあたりに、たくさんのサンプル設定があります。僕も現状は、ここにあったobj-c.cfgをベースにしています。
Uncrustify自体は、ターミナルなどであれば
$ uncrustify -q -l oc -c obj-c.cfg --replace [files ...]
みたいな感じで、-lで言語をoc(Objective-C)、-cで設定ファイルを指定して、あとは、整形したいファイルを指定するだけです。--replaceをつけると、オリジナルのファイルが書き換えられてしまうので注意してください。

Step 2: Xcodeからuncrustifyの呼び出し

次に、UncrustifyをXcodeのスクリプトメニューに登録し、編集中のファイルに対して、メニューから呼び出し、簡単にコード整形を実行できるようにします。
Picture 4
XcodeのスクリプトメニューからEdit User Scripts...を選択すると
Edit User Scripts

みたいなウインドウが表示されるので、左下の+から、任意の場所にUncrustifyの呼び出しメニューを追加します。僕の場合、実行するたびにソースコード全体を整形対象にしたいので、InputやOutputの設定がhipposさんの設定とは異なっています。肝心のスクリプト部分には、
#!/bin/sh

echo -n "%%%{PBXSelection}%%%"
/usr/local/bin/uncrustify -q -l oc+ -c $HOME/Dropbox/Public/uncrustify/obj-c_dk.cfg <&0
echo -n "%%%{PBXSelection}%%%"
を、cfgファイルの場所など自分の環境に置き換えて設定してみてください。(僕の場合、最近この手の設定はDropboxで共有できる場所に置いてます)

これで、編集中のソースコードに対して、スクリプトメニューからいつでもコード整形を呼び出すことができます。

Step 3: ビルド時の自動整形設定

Step 2までで、満足な方も多いとは思いますが、あくまでもものぐさな自分としては、ビルド時に、すべてのソースを一括して、整形してほしいので、Xcodeプロジェクトのターゲット設定に、整形を実行するスクリプトを追加してみました。
Picture 6

↑ターゲットを右クリックしてAdd→New Run Script Build Phaseで、スクリプトを追加すると下のようなウインドウが出てくるので
Picture 8

ここで、プロジェクトの中から、*.hと*.mなファイルを検索し、それらすべてにコード整形を適用するようにしています。具体的には
find ${SRCROOT} -name "*.h" -exec /usr/local/bin/uncrustify -q -l oc -c ${HOME}/Dropbox/Public/uncrustify/obj-c_dk.cfg --replace {} \;
find ${SRCROOT} -name "*.m" -exec /usr/local/bin/uncrustify -q -l oc -c ${HOME}/Dropbox/Public/uncrustify/obj-c_dk.cfg --replace {} \;
こんな感じで、スクリプトを適用しています。

また、マニアックに長くなりましたが、こんな感じで、どんなに汚くコードをかいても、ビルドさえすれば、いつでも綺麗に整形されたコードが手に入るようになりました。hipposさんも
(僕は根がいい加減なくせにコードのインデントには結構こだわるところがあって、2タブじゃないと嫌だとかブレースはGNUスタイルが好きだとかいろいろあるんですが、やっぱりチャランポランな性格ゆえ誰かのコードを拝借してペーストとかしているうちコードスタイルもちゃんぽんになってきてある日思い立って「よし!修正しよう!」とか思ったりもするんですがコミットコメントに「インデントの修正」とか書いていたら嫌がられるだろうなぁなどと思って放置していたりする人間なんです。←長すぎる注釈)
と書かれてますが、僕もこの気持ちめっちゃわかります。自分も、すごいずぼらで、めんどくさがりやな性格なのに、なぜか、コード末尾の無駄な空白スペースとかが気になって、気づくと躍起になってdeleteしてたりするんですよね。その割に、コード全体としては、特に徹底されてないという。。。

ただ、現状、一つだけ問題があります。
どうも、まだUncrustifyがObjective-Cに完全対応してないためか、複数行に渡ったメソッド定義時に、引数のラベルをうまくバランスしてくれません。具体的には
Picture 10

みたいに整形したいコードがUncrustifyで整形すると
Picture 9

こんな感じで整形されちゃいます。これが、すごーーーーく気分悪いんですが、いろいろconfigをいじってみてもどうにもうまくいかなかったので、現状ちょっとあきらめ気味です。ただ、XcodeのEdit→Format→Re-Indent機能を使えば、上のようなコードを得られるので、Re-Indentにショートカットを割り当てて、必要に応じてすぐ呼び出すことで、とりあえずしのいでます。

僕の設定を、obj-c_dk.cfgとしてリンクしておきます。obj-c.cfgをベースにGoogle Objective-Cスタイルガイドを基準にチマチマと調整してます。Uncrustifyの設定には、こちらのページのオプション解説が大変参考になりました。(ローカルで利用してるcfgをDropbox経由でダイナミックに公開してるので、適宜内容が書き変わってる場合があるので注意してください。)
もし、ラベルのバランスについて、最適な設定方法を見つけた方がいたら、ぜひ連絡くださいー。

ふぅ、最近マニアック&長文ネタが続いてすいません。。。汗汗
このエントリーをはてなブックマークに追加
comments powered by Disqus