サクラエディタ上に Vim を実装した話

これは Vim Advent Calendar 2015 の 9 日目の記事です。

はい、タイトルは盛りました。正直「実装」と言えるほどのものではないので最初に謝っておきます。すみませんすみません。

サクラエディタ (以下サクラ) というのは Windows 用のテキストエディタなんですが、とある事情でこのエディタを Vim ライクなキーバインドで使えるようにしたことがありました。これはその時の思い出話になります。

自己紹介

当時、私はとある零細下請け SIer で働くシステムエンジニアでした。回ってくるのは客先常駐の堅い現場ばかり。ネットに繋がっていない PC で作業することが殆どでした。

サクラエディタとは

サクラエディタ

サクラエディタはMS Windows上で動作する日本語テキストエディタです.

行く先々の現場では必ずと言っていいほどサクラが使われていて、私もほとんどのショートカットキーを覚えるほど使い込みました。特に気に入っていたのは正規表現ライブラリが付属している点で、テキストの整形なんかはコマンドラインよりサクラでやることが多かったです。

そんなふうに永らくサクラユーザだった私は、ある日たまたま読んだ記事でとあるエディタと運命的な出会いを果たします。

Vim との出会い

そう、 Vim です。たしか 2012 年くらいだったと思います。もともと Solaris の vi を仕事で使っていたことがあったので、モードの概念や特徴的なキーバインドに抵抗はありませんでした。ちょうど、珍しくネットを使える現場に配属されたところだったので仕事でも Vim を使うようになりました。私はすぐにその強力なエディタの虜になりました。

Vim との別れ

そんな幸せな時間もつかの間、またネットのない現場に異動させられてしまいました。用意されていたのは当然サクラエディタ。まぁ、何とかなるだろうとその時は思っていました。私はヘビーな Vim ユーザではなかったからです。一応自分の vimrc はありますが、キーバインドはデフォルトを崩さない派ですし、入れているプラグインの数も多くありません。以前使っていたエディタに戻るだけじゃないか。そんな風に考えていました。

... ダメだ ...!

カーソル移動ひとつとってもホームポジションを離れなければいけませんでした。耐えられない。Vim でなければ満足できない。もはや私は Vim 依存症だったのです。

f:id:tchssk:20151209202759p:plain

Powered by 悪循環画像ジェネレータ

どうにかしてサクラを Vimキーバインドで作業できるようにしたい。私は模索を始めました。

サクラの仕様調査

サクラにはキーバインド設定のインポート / エクスポート機能があります。 Vim のモード毎に設定ファイルを作って切り替えれば擬似的にモードを再現できると思いましたが、設定ダイアログからしかインポートができないことがわかり、この方法はボツに。

次に思いついたのはマクロを使う方法。サクラのマクロ機能ではサクラ独自記法の他に、 Windows Script Host (VBScriptJScript) が利用可能です。そして特定のキーが押された時にマクロを実行するよう設定することができます。これを使えば何とかできるかもしれない。

謎のモチベーションと勢いでコードを書き続け、半日ほどで何となく動くものができました。

サクラ上に Vim を実装する

Vim の特徴のひとつにモードがあります。これを再現できなければ話になりません。しかしサクラのマクロ (というより VBS) には、スクリプトをまたいで使いまわせるグローバルな変数などありません。どうやってエディタ上に状態を保持させるか。

これは制御用のファイルを作ることで解決しました。処理は以下の流れです。

  1. あるキーが押される
  2. キーに割り当てられたマクロ (VBS) が実行される
  3. マクロが制御ファイルから現在のモードを判定
  4. マクロがモードに応じた処理を実行

制御ファイルは 0 バイトファイルです。状態はファイル名に持たせていました。なのでモードが変わるたびにファイル名も変わります。

Set fs = CreateObject("Scripting.FileSystemObject")

For Each f In fs.GetFolder("..").Files
    If InStr(1, f.Name, "mode") = 1 Then
        Select Case Replace(f.Name, "mode=", "")
            Case "n"
                Editor.Right
                f.Name = "mode=i"
            Case "i" Editor.InsText("a")
        End Select
        Exit For
    End If
Next

これは当時を思い出しながら書いてみたコードです。 InStr() で判定しているように、制御ファイルは mode= で始まるファイル名となっています。mode= のあとはモードによって書き換わるようになっています。ノーマルモードn 、挿入モードは i というように決めて、 Select Case の分岐でモードに応じた処理がされるようにしていました。

その後

コツコツと機能を追加して、ビジュアルモードなども使えるようにしました。半年ほどしてその現場を離れることになり、少し名残惜しさもありましたがコードはすべて削除しました。ネットが使えないので持ち出すことはできないですし、そもそもネットが使えたら書くこともなかったコードです。あれはそういう蜃気楼のようなコードだったのです。

ですが、上記のコードを書いたついでに一部分だけコードを再現してみました。

github.com/tchssk/sakura-vim

使えるのは以下のキーです。

h 左に移動
j 下に移動
k 下に移動
l 右に移動
w 次の単語に移動
b 前の単語に移動
gg 1 行目に移動
x カーソル位置の文字を削除
a カーソル位置の後に文字列を追加
i カーソル位置の前に文字列を追加

最初はもっと再現しようと思っていたのですが辛くなってきたのでやめました。こんなコードは必要に迫られなければ書けたものではありません。

ちなみに今は Web な会社に転職して「本物の」 Vim で毎日 Go を書いています。 Go 楽しいです。

おわり。