My Daily Programming Life...

XVimの紹介

Vim Advent Calendar 2012 27日目の記事です。

XcodeでのVimキーバインドを実現するXVimの開発経緯と使い方をご紹介したいと思います。まず初めにURLだけ貼っておきます。
https://github.com/Jugglershu/XVim

さて、本題。ちょうど今から1年前、僕は友達ともにiOS向けアプリの作成を趣味で行っていました。当時僕はMacはあまり使ったことがなく、Objective-Cの個性あふれるシンタックスに苦しんでおりました。iOSアプリの開発なので、当然Xcodeを使うわけですが、シンタックスに苦しんでいるところへXcodeではデフォルトだとVimのキーバインドではなくEmacsのそれとなっており、そのままだと使い物になりません。

Vimのキーバインドにするにはどうしたらいいのか友人に聞いたら、「ない」との答え・・・またまた〜、そんなことないでしょ〜。まあきっとどこかの誰かがそういうの作ってくれてるよと、軽い気持ちでググり、いまどきVimキーバインドがないなんて、そんなわけが・・・「ほんまや!」

というわけで、ないわけです。とても不思議です。世界中のVimプログラマはどうやってiOSアプリを書いているのでしょうか。確かにVimオンリーで書くという選択肢もありそうです。実際、Cocoa.vimなるプラグインもあった(いまも動く?)ようですが、ちょっと使ってみた感じだとあまりうまく動きませんでした。なにより、Xcodeの補完機能や、その場でエラー・ワーニングチェックなどiOSアプリを書く上では非常に有効な機能を捨ててしまうのはあまりにも惜しいです。

しかし、なぜXcode向けのVimキーバインド(プラグイン)が存在しないのか。もしかするとXcodeがプラグインに正式に対応していないというのが大きな理由かもしれません。実際プラグインの作り方に関するドキュメントなどはどこにもありません。幸い、これまでWindowsでAPIフックなどのプログラムを書いてきたこともあり、自分で作ったライブラリさえXcodeプロセスに読み込ませられれば、あとはなんとかできる自信があったため、とにかくその方法を探しました。実はXcodeは内部的にはプラグインのサポートがされているようで、その機能を使うことでXcodeのプラグインを読み込ませることができることがわかりました。

ただし、分かっているのは作ったプラグインがロードされ、初期化時に特定のメソッドが呼び出されることだけです。ここからはひたすら試行錯誤。幸いObjective-Cは動的バインド言語であり、Xcodeのクラスやメソッドの名前などはすべて確認することができ、またどのようなメソッドが呼び出されているかも簡単なコードを追加するだけで確認できます。また、特定のクラスのメソッドのフックもバイナリを直接編集することなくObjective-Cのライタイムを頼って実現することができます。

そこから2週間ほどかけてとりあえず動くものを作りました。うれしいことに、テキスト編集自体の機能はNSTextViewやXcodeが内部的に使っているDVTSourceTextViewクラスに実装されており、キーイベントに対応させてそれらを呼び出すことで基本的な編集機能は実装できました。

それからいろいろな方の協力もあり、現在は以下の様にステータスバーがあったり、太いカーソルになったりと見た目も良くなっております。
だいぶ、Vimの話からずれてしまいました。ここからはXVimの便利な機能をご紹介したいと思います。XVimはVimのキーバインドを実現するためのものなので、Xcode上でVimのキーバインドで編集できることはごく標準的な機能です(まだまだ対応していないバインドはありますが)。一方でXcode特有の機能を使うために実装したXVim特有のコマンドもあります。

最も個人的に使う頻度が高いのが、メニューの特定のコマンドを呼び出すコマンド
:xccmd
です。Cocoaアプリではメニュー内の各項目にはAction名が割り振られているため、そのアクション名を指定することでメニュー上にあるコマンドはすべて実行することができます。たとえば、
:xccmd jumpToNextCounterpart
と入力した場合、.hと.mファイルの切り替えを行います。切り替えのためだけにこれを打ち込むのはばかばかしいので、XVimの.vimrcにあたる、.xvimrcファイルを作成し
nmap <c-n> :xccmd jumpToNextCounterpart<CR>
と書いておきます。これでによって、この機能を呼び出すことができるのです。
xccmdの引数部分はhttps://github.com/JugglerShu/XVim/blob/master/Documents/Developers/MenuActionList.txt
に一覧があります。

ほかには、開発時によく行うビルドと実行はそれぞれ

:make
:run
で起動できるようになっています。もちろん上に書いたように自分の好きなキーを割り当ててもよいです。メニューのショートカットについてはXcode自体に設定があるのでそれを利用しても良いですが、XVimで設定するとnmap, imapなどに対応している点が良い点だと思います(と言いつつ、個人的にはこれら違いによるショートカットを使っていなかったりしますが。)

もう一つ有効な機能として、
:xhelp
コマンドがあります。これはクイックヘルプを呼び出すために実装してあるコマンドです(:xccmdコマンドでも実行できます。)これは現在のカーソル位置にあるメソッドやクラスのヘルプをその場に表示してくれるというもので、引数の意味などを確認するのにとても便利です。

一部のキーバインドは、Vimの定義ではなくXcodeの機能で置き換えれています。"gd"が、典型的な例で、Vimでは"Goto locfal Declaration."ということで、宣言へのジャンプとなっていますが、これはXVimではXcodeの"Jump to Definition"を呼び出すようになっています。そのため、定義部分で入力すれば、宣言部分にジャンプしますし、宣言部分で入力すれば定義部分にジャンプします。またカーソル下のファイル名のオープンはVimではgfですが、Xcodeではこの"Jump to Definition”でジャンプできるため、ファイル名上にカーソルを置いて、"gd"コマンドでヘッダファイルのオープンなどができます。

このように、Vimキーバインドプラグインですが、Xcodeとうまく連携するようにということを意識して作成しています。現在の機能一覧は以下を参照してください。
FeatureList

さて、XVimの開発状況なのですが、最近ちょっと滞っております。というのもこれ以上機能を追加しようとすると少しバグが多く発生するような状況になってきており、少し根本的な設計見直しが必要と判断しているためです。現在github上の別ブランチにて作業をしておりmasterはあまり更新されておりません。ただし、比較的安定しているはずですので、しばらくはそちらを利用していただくのが良いと思います。

今後開発予定の機能としては、矩形選択、検索・置換機能の強化が大きなところとなりそうです。対応コマンドの充実などやりたいことはたくさんあるのですが、なかなか前に進めない状況だったりもします。

なお、XcodeのVimキーバインドとして、最近ライバルが出現しました。http://viciousapp.com/がそれです。ちなみに20ドルだそうです。負けないように頑張りたいと思います。

Vim Advent Calendar 2012 明日は@sonotsさんです。
feedSubscribe to my feed