vimperatorでキャレットブラウズモード

キャレットブラウズモードを知っているかい? F7または、ツール*1 -> オプション を開いて、詳細の一般タブから設定できるやつだよ。これをオンにするとページにテキストボックス内でのキャレット見たいのが現れて、矢印キーとかで移動できるようになるんだ。マウスがなくても分かりやすく操作するための設定だね。

残念ながらvimperator0.5.2は対応してなくてキャレットの操作ができない。キャレットだってh,j,k,lで操作したいってことで、ちょっとムキッとなってvimperatorプラグインを書いてみた。

HOME/.vimperator/plugin/caretBrowse.js

(function(){
var gPrefService = Components.classes['@mozilla.org/preferences-service;1']
                             .getService(Components.interfaces.nsIPrefBranch);
var caretBrowseObserver = { 
  initialize: function(){
    var service = Components.classes['@mozilla.org/preferences-service;1']
                            .getService(Components.interfaces.nsIPrefBranch2);
    service.addObserver('accessibility.browsewithcaret',caretBrowseObserver,false);
  },  
  observe: function(aSubject,aTopic,aData){
    overWriteMapping(gPrefService.getBoolPref(aData));
    vimperator.echo(aTopic + '[' + aData + ']');
  }
};

var defaultMaps = { 
  h: function(count){ vimperator.buffer.scrollColumns(-(count > 1 ? count : 1)); },
  j: function(count){ vimperator.buffer.scrollLines(count > 1 ? count : 1); },
  k: function(count){ vimperator.buffer.scrollLines(-(count > 1 ? count : 1)); },
  l: function(count){ vimperator.buffer.scrollColumns(count > 1 ? count : 1); }
};
var caretMaps = { 
  h: function(){goDoCommand('cmd_scrollLeft');},
  j: function(){goDoCommand('cmd_scrollLineDown');},
  k: function(){goDoCommand('cmd_scrollLineUp');},
  l: function(){goDoCommand('cmd_scrollRight');},
};
function createMaps() {
  return  [ 
    new Map(vimperator.modes.NORMAL,['$'],
      function(){ goDoCommand('cmd_endLine'); },
      { short_help: 'Move caret to end of line.' }
    ),
    new Map(vimperator.modes.NORMAL,['^'],
      function(){ goDoCommand('cmd_beginLine'); },
      { short_help: 'Move caret to begin of line.' }
    ),
    new Map(vimperator.modes.NORMAL,['w'],
      function(){ goDoCommand('cmd_wordNext'); },
      { short_help: 'Move caret to next word.' }
    ),
    new Map(vimperator.modes.NORMAL,['W'],
      function(){ goDoCommand('cmd_wordPrevious'); },
      { short_help: 'Move caret to previous word.' }
    )
  ];
} 
function overWriteMapping(bool){
  var additionals = createMaps();
  if (bool) {
    for (var i in caretMaps){
      vimperator.mappings.getDefaultMap(1,i).action = caretMaps[i];
    }
    for (var i=0; i<additionals.length; i++){
      vimperator.mappings.add(additionals[i]);
    }
  } else {
    for (var i in defaultMaps){
      vimperator.mappings.getDefaultMap(1,i).action = defaultMaps[i]
    }
    for (var i=0; i<additionals.length; i++){
      var map = additionals[i];
      for (var j=0; j<map.names.length; j++){
        vimperator.mappings.remove(map.mode,map.names[j]);
      }
    }
  }
}
overWriteMapping(gPrefService.getBoolPref('accessibility.browsewithcaret'));
caretBrowseObserver.initialize();
})();

// vim:set sw=2 ts=2 sts=0 fdm=marker:

モードの切り替わりと共にキャレットブラウズモード用のキーマップを追加/削除している。
因みに、デフォルトのキーマップを上書きしている(:-P vimperator.mappings.getDefaultMapメソッドからMapオブジェクトを引き抜いてMap.actionメソッドを交換しているわけだ。少々強引だけど、こうでもしないと書き換えられそうにないのだ。

本当はvimperatorのオプションも追加して切り替わりと共にキーマップを変更しようとしたが、追加するメソッドがなかったので諦めて、accessibility.browsewithcaret設定を監視することで解決させた。

vimperatorオプションから設定が出来ないのが不満だが、observerの勉強になったから+-=0かな。

あと、キャレットの移動とかで使えるコマンド名はmozilla1.8 mozilla/dom/src/base/nsGlobalWindowCommands.cppあたりに載っている。chrome://global/content/platformHTMLBindings.xml#browserを見たほうが早いかもしれないけど...

*1:UNIX系では設定