.vimperatorrcにnoremap ; :と記述してもmappingされなくてハマった

環境はMac OS X 10.5.5のVimperator 1.2 with Firefox 3.0.4.


愛用しているMacBookのキーボードがUS配列なので,Vimperatorで:を入力するときにShift + ;と入力しなければならない.これでは小指に優しくないので,normalモードのときだけ;を:にマッピングしようと思い,.vimperatorrcに以下の設定を記述した.

noremap ; :
noremap : ;

ところが,Firefoxを再起動してもマッピングが反映されない.Vimだとこんな感じで大丈夫なんだけど.ぐぬぬ.
もしかしてVimperatorでは:と;はマッピングできないのかと思い,Firefox起動後に上記のマッピング設定を手動で行ったところ,今度はちゃんと反映された..vimperatorrcだと設定できないマッピングがある?


ということをTwitterでボヤいていたら,id:retletさんから以下の助言をいただいた(情報ありがとうございました!).

@mickey24 #vimperator@IRCNetで検証したところldrize_cooperation.jsが悪さをして模様です。>noremap ; :

http://twitter.com/retlet/status/1018217931

むむむ,プラグインのせい?

ソース読み

というわけで早速ldrize_cooperation.jsのソースを読んでみたところ,以下のように;のマッピングを設定している箇所を発見した.

            liberator.mappings.addUserMap([liberator.modes.NORMAL], [";"],

これは私の.vimperatorrcのマッピングとコンフリクトしている..vimperatorrcのマッピングの方は効果がなかったから,もしかしてプラグインのマッピングの方が優先されているのかも.
Vimperatorのソース(liberator.js)を読んでプラグインの読み込み部分を確認してみた.

            // finally, read a ~/.vimperatorrc
            // make sourcing asynchronous, otherwise commands that open new tabs won't work
            setTimeout(function () {

                var rcFile = liberator.io.getRCFile();
                if (rcFile)
                    liberator.io.source(rcFile.path, true);   ← .vimperatorrcを読み込んでいる
                else
                    liberator.log("No user RC file found", 3);

                // also source plugins in ~/.vimperator/plugin/
                try
                {
                    var pluginDir = liberator.io.getSpecialDirectory("plugin");
                    if (pluginDir)
                    {
                        var files = liberator.io.readDirectory(pluginDir.path);
                        liberator.log("Sourcing plugin directory...", 3);
                        files.forEach(function (file) {
                            if (!file.isDirectory() && /\.(js|vimp)$/i.test(file.path))
                                liberator.io.source(file.path, false);   ← プラグインを読み込んでいる
                        });
                    }
                    else
                    {
                        liberator.log("No user plugin directory found", 3);
                    }
                }
(略)
            }, 0);

            liberator.statusline.update();

            liberator.log(liberator.config.name + " fully initialized", 0);   ← \(^o^)/

どうやら.vimperatorrcのマッピングよりもプラグインのマッピングの方が優先されるみたい.これでは.vimperatorrcにマッピングを書いても無意味.プラグインを直接修正する方がよさそう.
さらに,ldrize_cooperation.js以外に;をマッピングしているプラグインを調べてみた.

$ cd ~/.vimperator/plugin
$ grep '";"' *
char-hints-mod.js:chh.mapExtended = ";";          // open in extended mode (see notes below)
char-hints-mod.js:        case ";": chh.focusHint(); break;
ldrize_cooperation.js:            liberator.mappings.addUserMap([liberator.modes.NORMAL], [";"],

char-hints-mod.jsも;をマッピングしている模様.

対処

.vimperatorrcに設定を書いても無理っぽいので, ldrize_cooperation.jsとchar-hints-mod.jsのマッピング箇所を直接修正して対処することにした.各プラグインの;に対するマッピングを:に割り当てた.

$ vim ldrize_cooperation.js
-             liberator.mappings.addUserMap([liberator.modes.NORMAL], [";"],
+             liberator.mappings.addUserMap([liberator.modes.NORMAL], [":"],

$ vim char-hints-mod.js
- chh.mapExtended = ";";          // open in extended mode (see notes below)
+ chh.mapExtended = ":";          // open in extended mode (see notes below)

char-hints-mod.jsにはもう一行";"が含まれている箇所があったけど,そちらは今回行いたいマッピングとは直接関係ないので修正しなくても大丈夫(のはず).

これで: -> ;のマッピングはできた.続いて.vimperatorrcに以下のマッピングを追加した.

noremap ; :

; -> :もOK.そしてFirefoxを再起動したところ,ちゃんと:と;が入れ替わっていることを確認できた.

今回の教訓

  • Vimperatorは.vimperatorrcの設定を読み込んだ後にプラグインをロードする
  • 双方で設定がコンフリクトする場合,(マッピングに関しては)プラグインの設定が優先される

今回の対処の問題点

  • プラグインを直接書き換えて対処したので,今後当該プラグインをアップデートする度に同じ修正を施さなければならない

もっといい対処方法はないのかな.