新しくなったMinibufferの感想

一日遅れで LDRize minibuffer reblog command を作ってみた感想をこちらに。

まずはじめにLDRizeの(一部だった)minibuffer用にシェルを組んでみたを書いてからほんの数日で、自分がちょっと時間かかりそうだなーとあきらめた、ちゃんとしたコマンドの補完機能だけでなく、エイリアスにヒストリまで実装されていて(Ctrl-Rで検索可能だし)、そしてコードもきれいで圧倒されました。

感想と言っても細かいことばかりなのですが、いくつか。

SITEINFOを参照したい

いまのreblogコマンドは、ピンの立てられたパラグラフからXPathでreblog用のリンクを取り出しています。できれば、このXPathもSTEINFOに書いてしまってコマンド側からはそれを参照して使うようになっているほうがメリットがあるのではと思います。

いまのreblogコマンドはreblogコマンド自身の中にXPathを書いているのでtumblr dashboardのデザインが変わってXPathを変更しないといけなくなったときに

  1. 誰かが壊れているのに気がつく
  2. 誰かXPathが書ける人が修正する
  3. reblogコマンド修正版をアップロードする
  4. 使っている人それぞれがreblogコマンドをアップデートする

という過程を経て正常に機能するようになります。

SITEINFOを参照して動くようになっていれば

  1. 誰かが壊れているのに気がつく
  2. 誰かXPathが書ける人がSITEINFOを修正する
  3. 使っている人のSITEINFOキャッシュが切れて更新されたら正常に機能するようになる

というふうに、誰かが直せばみんながハッピー、という状況を作り出せるのでSITEINFOを参照できるようにしてほしいです!

デフォルトのstdin

はじめ毎回pinned-nodeと書いてパイプで繋げるのがめんどくさいので、MinibufferでもLDRizeのようにデフォルトでstdinにピンを立てているparagraphesが入ってきたらいいのに、と思ったのですが、エイリアスが作れるのに気がつきました。どっちでもいいと思いますがpinned-nodeが使われることが多いようだったらデフォルトにしてもいい気もします。

evalハック

ほかのスクリプトからLDRizeやMinibufferのインスタンス本体を直接は操作できないようにメソッドだけを渡しているのは、むやみにメソッドを公開しない設計なのだと思っているのですがいくつかどうしても入れたい部分があったので 実用 – Firefox、evalの第二引数、プライベートメンバ/クロージャーの実行コンテキストへのアクセス に書かれているevalで隠蔽されているインスタンスにアクセスして上書きしています。

ひとつだけ、ぜひ採用してほしいのがMinibufferをopen/closeしたときのイベントを

 var Minibuffer = {
+   listeners: [],
+   dispatchEvent: function ( event_name, data ) {
+     Minibuffer.listeners.forEach( function ( listener ) {
+            if (event_name in listener) {
+                try {
+                    listener[event_name].apply(listener, [data]);
+                } catch (e) {
+                   trace(e);
+                }
+            }
+     } );
+   },
+   removeEventListener: function (obj) {
+       this.listeners = Minibuffer.listeners.filter( function ( listener ) {
+           return ( obj != listener);
+       } );
+   },
+   addEventListener: function (obj) {
+       Minibuffer.listeners.push(obj);
+   },
@@ -153,6 +194,7 @@
   },
   complete: function(candidates, callbackExit, prompt) {
      Minibuffer.init();
+     Minibuffer.dispatchEvent("show_minibuffer", null);
      if(prompt) Minibuffer.htmlprompt.innerHTML = prompt;
      Minibuffer.callbackExit = callbackExit;
      Minibuffer.candidate_command_hash = candidates;
@@ -183,9 +225,11 @@
      document.body.removeChild(Minibuffer.container);
      document.removeEventListener('keypress', Minibuffer.handleKey, true);
      Minibuffer.callbackExit();
+     Minibuffer.dispatchEvent("hide_minibuffer");
   },
   KEYBIND : {
      'C-m'  : 'bindDoAndExit',
      'RET'  : 'bindDoAndExit',

こんなかんじでlistenできたらと思っています。なんでそんなのが必要かというと、カーソルキーをMinibufferが開いていないときはj,kとして機能するようにして、Minibufferが開いているときには元に戻して↑↓でコマンドを選択できるようにしたいのですー。

あとはbugfix的なものだけ貼っておきます。
pinned-node | のようにパイプで繋いだあとコマンドを入力するとき↑↓を押すと、パイプより前のコマンドが消えちゃうので

   selectCandidate : function(oldNode, newNode){
-     Minibuffer.input.value = newNode.innerHTML;
+     var currentNode = Minibuffer.input.value.match( /.*?\|\s*/ ) || '';
+     Minibuffer.input.value = currentNode + newNode.innerHTML;
      newNode.setAttribute('class','gm_minibuffer_selected');
      if(oldNode) oldNode.removeAttribute('class',0);
   },

パイプより前の部分を入れるようにしました。

backspaceで入力したコマンドを削っていったときに補完候補が変化しなかったので

  bindDeleteForwardChar : function(){
      var begin = Minibuffer.input.selectionStart;
      var end   = Minibuffer.input.selectionEnd;
      var text  = '';
      var pos;
      if(begin == end){
          text = Minibuffer.input.value.slice(0, begin) + Minibuffer.input.value.slice(end + 1);
      }else{
          text = Minibuffer.input.value.slice(0, begin) + Minibuffer.input.value.slice(end)
      }
      Minibuffer.input.value = text;
      Minibuffer.input.setSelectionRange(begin, begin);
-     if(Minibuffer.input.value == '') Minibuffer.updateComplationList();
+     Minibuffer.updateComplationList();
  },

ifを削って変化するようにしました。


About this entry