Hatena::Groupkeysnail

basyura snail

|

2010-07-16

開きっぱなしのプロンプトにもう一度フォーカスを当てたい

00:14 |  開きっぱなしのプロンプトにもう一度フォーカスを当てたい - basyura snail を含むブックマーク はてなブックマーク -  開きっぱなしのプロンプトにもう一度フォーカスを当てたい - basyura snail

プロンプトを表示したままフォーカスを外すと、再度 shell.input() を呼び出しても「Prompt is already used by another command」となってアクティブにならない(クリックしないとコマンド入力できない)事への対応。

key.setViewKey(':', function () {
    prompt.finish();
    shell.input();
}, 'Command System');

prompt.finish() を呼びだすといけるっぽ。

できてなかった orz

追記

こうか。

key.setViewKey(':', function () {
  if (document.getElementById("keysnail-prompt") != undefined) { 
    prompt.finish(true,true);
  }
  shell.input();
}, 'Command System');

finish で入力内容を引き継ぐかどうかは迷うところ。

トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100716

2010-04-13

アクセスキーを殺・・・しきれなかった

| 22:39 |  アクセスキーを殺・・・しきれなかった - basyura snail を含むブックマーク はてなブックマーク -  アクセスキーを殺・・・しきれなかった - basyura snail

Wikipedia のアクセスキーが鬱陶しいという声があったので。

次のようなコードを .keysnail.js の末尾にでも張り付けておけば、おそらくうまくいく。

http://d.hatena.ne.jp/mooz/20091206

全部殺しちゃうと投稿できない・・・。投稿のとこだけ他のキーに差し替えたいけどうまくいかなかったので、それだけは殺さないことで諦めた・・・それほど実害ないし(言い訳)

for (let i = 0; i < nodes.snapshotLength; i++)
{
  let node = nodes.snapshotItem(i);
  // 追加
  if(node.getAttribute('accesskey') == "u") {
    continue;
  }
  let clone = node.cloneNode(true);
  clone.removeAttribute('accesskey');
  node.parentNode.replaceChild(clone, node);
トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100413

2010-04-10

新しいツイートが◯件あります

| 22:41 |  新しいツイートが◯件あります - basyura snail を含むブックマーク はてなブックマーク -  新しいツイートが◯件あります - basyura snail

f:id:basyura:20100410223739j:image

クリックして新しいツイートを表示すると、実は古いツイートとの境界に薄い線が出る。これを強調して分かりやすくする。ついでに広告を(ry

_keysnail.js

style.register(<><![CDATA[
@-moz-document url-prefix("http://twitter.com/") {
	#introduce_retweet_banner {
		display : none !important;
	}
	ol.statuses > li.last-on-page, ol.statuses > li.last-on-refresh {
		border-bottom:10px solid #8ec1da !important;
	}
}
]]></>.toString(), style.XHTML);
トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100410

2010-03-28

Ruby API 検索 その3 - メソッドも補完

| 22:07 |  Ruby API 検索 その3 - メソッドも補完 - basyura snail を含むブックマーク はてなブックマーク -  Ruby API 検索 その3 - メソッドも補完 - basyura snail

最初はクラス名を補完。# を入力した後はそのクラスのインスタンスメソッドを補完。

補完用ファイルをゴリッと作ったらサイズがでかくなったので、テキストファイルサーバに置いておいて XMLHttpRequest で取得するように修正。

微妙にファイルサイズがでかいので、キャッシュして持っておくのもなんだなぁと思うので、ウイークリファレンス的なことをしたいんだけど無理?。リファレンスページを開いた時点で変数(ruby_completes)に null を突っ込んでもいいけど、このメモリってちゃんと回収されるんだろうか?定義ファイルを読み込み直した時点で null で初期化されるけど。

サーバRuby で補完候補を都度作って通信してもいいけど、Ruby のバージョン分沢山用意するのもめんどい。速度はそんなに遅くないと思うけど試してない。

リファレンスページのヒット率が高いのか低いのかが謎 (><)

let ruby_completes = null;
shell.add("refe" , M({ja: "Ruby リファレンス検索", en: "ruby reference search"}) ,
  function (args, extra) {
    function generate_url(word) {
      let site   = "http://doc.okkez.net/188";
      let clazz  = word.split("#")[0];
      let method = word.split("#")[1];
      //let clazz  = word.split("\.")[0];
      //let method = word.split("\.")[1];
      // not match. search by google with site: .
      if(ruby_completes["classes"].indexOf(clazz) == -1) {
        let w = encodeURIComponent(word + " site:" + site);
        return "http://www.google.co.jp/search?q=" + w + "&ie=utf-8&oe=utf-8";
      }
      // no method. open clazz's
      if(method == undefined) {
        return site + "/view/class/" + clazz;
      }
      // try to find clazz's method
      let url = site + "/view/method/" + clazz + "/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find object's method
      url = site + "/view/method/Object/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      /*
      // try to find singleton's method
      url = site + "/view/method/" + clazz + "/s/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find module's method
      url = site + "/view/method/" + clazz + "/m/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find special method
      url = site + "/view/method/" + clazz + "/v/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find const
      url = site + "/view/method/" + clazz + "/c/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      */
      // open clazz's 
      return site + "/view/class/" + clazz;
    }
    function isAvailable(url) {
      var http = new XMLHttpRequest();
      http.open("HEAD" , url , false);
      http.setRequestHeader("accept-language" , "ja");
      http.setRequestHeader("Cache-Control"   , "no-cache");
      http.setRequestHeader("content-type"    , "application/x-www-form-urlencoded");
      http.send();
      return http.status == 200;
    }
    function encode_method(method) {
      return encodeURIComponent(method).replace("%","=");
    }
    // open tab
    let url = generate_url(extra.left)
    gBrowser.loadOneTab(url, null, null, null, extra.bang);
  },
  {
    bang      : true,
    literal   : 0,
    completer : function (args, extra) {
    function get_completes() {
      var http = new XMLHttpRequest();
      http.open("GET" , "http://basyura.org/ruby_completes/1.8.8.txt" , false);
      http.setRequestHeader("accept-language" , "ja");
      http.setRequestHeader("Cache-Control"   , "no-cache");
      http.setRequestHeader("content-type"    , "application/x-www-form-urlencoded");
      http.send();
      return http.responseText;
    }
    if (ruby_completes == null) {
      ruby_completes = eval("(" + get_completes() + ")");
    }
    if(extra.left.indexOf("#") != -1) {
      let clazz = extra.left.split("#")[0];
      let list  = ruby_completes[clazz];
      if(list != undefined) {
            return completer.matcher.substring(list)(extra.left || "");
      }
    }
      return completer.matcher.substring(ruby_completes["classes"])(extra.left || "");
    }
  },
  true
);

補完用ファイルはこんな感じ。

{
"classes":["Array" , "String" , ...],
"Array":["Array#find" , "Array#inspect" , ...],
"String":["String#upcase!" , "String#zip" , ...], 
・・・
}
トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100328

2010-03-26

Ruby API 検索 - その2

| 21:19 |  Ruby API 検索 - その2 - basyura snail を含むブックマーク はてなブックマーク -  Ruby API 検索 - その2 - basyura snail

メソッドも指定できるようにしたい。でも、補完用の設定をたくさん用意するのも嫌だ(めんどくさい)。てことで、可能な限り見つけられるようにしてみた。

refe String#to_s

と「#」で区切るとメソッドのリファレンスページを直接開くようにトライする。該当のページが存在するかは HTTP ヘッダのステータスを見る。200 で無い場合ば次をチェックする。

Clazz#method → Object#method → Kernel#method 
→ Module#method → Kernel#method(特殊メソッド) → Kernel#method(定数) 
→ Clazz

といった順番に検索される(はず)だけど、さすがに全部スルーして結局クラスのページを開く場合は遅い。Object#method までで十分じゃないかと思うのでコメントアウト

let ruby_completes = [
"ARGF","Array","Bignum","Binding","Class","Comparable","Continuation","Data","Dir",
"ENV","Enumerable","Enumerator","Errno","FalseClass",
"File","File::Constants","File::Stat","FileTest","Fixnum","Float","GC","Hash","IO","Integer",
"Kernel","Marshal","MatchData","Math","Method","Module","NilClass","Numeric","Object",
"ObjectSpace","Precision","Proc","Process","Process::GID","Process::Status",
"Process::Sys","Process::UID","Range","Regexp","Signal",
"String","Struct","Struct::Tms","Symbol","Thread","ThreadGroup","Time","TrueClass",
"UnboundMethod","ArgumentError","EOFError","Errno::E2BIG","Errno::EACCES","Errno::EADDRINUSE",
"Errno::EADDRNOTAVAIL","Errno::EADV","Errno::EAFNOSUPPORT","Errno::EAGAIN","Errno::EALREADY",
"Errno::EBADE","Errno::EBADF","Errno::EBADFD","Errno::EBADMSG","Errno::EBADR","Errno::EBADRQC",
"Errno::EBADSLT","Errno::EBFONT","Errno::EBUSY","Errno::ECHILD","Errno::ECHRNG","Errno::ECOMM",
"Errno::ECONNABORTED","Errno::ECONNREFUSED","Errno::ECONNRESET","Errno::EDEADLK","Errno::EDEADLOCK",
"Errno::EDESTADDRREQ","Errno::EDOM","Errno::EDOTDOT","Errno::EDQUOT","Errno::EEXIST","Errno::EFAULT",
"Errno::EFBIG","Errno::EHOSTDOWN","Errno::EHOSTUNREACH","Errno::EIDRM","Errno::EILSEQ",
"Errno::EINPROGRESS","Errno::EINTR","Errno::EINVAL","Errno::EIO","Errno::EISCONN","Errno::EISDIR",
"Errno::EISNAM","Errno::EL2HLT","Errno::EL2NSYNC","Errno::EL3HLT","Errno::EL3RST","Errno::ELIBACC",
"Errno::ELIBBAD","Errno::ELIBEXEC","Errno::ELIBMAX","Errno::ELIBSCN","Errno::ELNRNG","Errno::ELOOP",
"Errno::EMFILE","Errno::EMLINK","Errno::EMSGSIZE","Errno::EMULTIHOP","Errno::ENAMETOOLONG",
"Errno::ENAVAIL","Errno::ENETDOWN","Errno::ENETRESET","Errno::ENETUNREACH","Errno::ENFILE",
"Errno::ENOANO","Errno::ENOBUFS","Errno::ENOCSI","Errno::ENODATA","Errno::ENODEV","Errno::ENOENT",
"Errno::ENOEXEC","Errno::ENOLCK","Errno::ENOLINK","Errno::ENOMEM","Errno::ENOMSG","Errno::ENONET",
"Errno::ENOPKG","Errno::ENOPROTOOPT","Errno::ENOSPC","Errno::ENOSR","Errno::ENOSTR","Errno::ENOSYS",
"Errno::ENOTBLK","Errno::ENOTCONN","Errno::ENOTDIR","Errno::ENOTEMPTY","Errno::ENOTNAM","Errno::ENOTSOCK",
"Errno::ENOTTY","Errno::ENOTUNIQ","Errno::ENXIO","Errno::EOPNOTSUPP","Errno::EOVERFLOW","Errno::EPERM",
"Errno::EPFNOSUPPORT","Errno::EPIPE","Errno::EPROTO","Errno::EPROTONOSUPPORT","Errno::EPROTOTYPE",
"Errno::ERANGE","Errno::EREMCHG","Errno::EREMOTE","Errno::EREMOTEIO","Errno::ERESTART","Errno::EROFS",
"Errno::ERROR","Errno::ESHUTDOWN","Errno::ESOCKTNOSUPPORT","Errno::ESPIPE","Errno::ESRCH","Errno::ESRMNT",
"Errno::ESTALE","Errno::ESTRPIPE","Errno::ETIME","Errno::ETIMEDOUT","Errno::ETOOMANYREFS",
"Errno::ETXTBSY","Errno::EUCLEAN","Errno::EUNATCH","Errno::EUSERS","Errno::EWOULDBLOCK","Errno::EXDEV",
"Errno::EXFULL","Errno::EXXX","Exception","FloatDomainError","IOError","IndexError","Interrupt",
"LoadError","LocalJumpError","NameError","NoMemoryError","NoMethodError","NotImplementedError",
"RangeError","RegexpError","RuntimeError","ScriptError","SecurityError","SignalException",
"StandardError","StopIteration","SyntaxError","SystemCallError","SystemExit","SystemStackError",
"ThreadError","TypeError","ZeroDivisionError","fatal"];

shell.add("refe" , M({ja: "Ruby リファレンス検索", en: "ruby reference search"}) ,
  function (args, extra) {
    function generate_url(word) {
      let site   = "http://doc.okkez.net/188";
      let clazz  = word.split("#")[0];
      let method = word.split("#")[1];
      // not match. search by google with site: .
      if(ruby_completes.indexOf(clazz) == -1) {
        let w = encodeURIComponent(word + " site:" + site);
        return "http://www.google.co.jp/search?q=" + w + "&ie=utf-8&oe=utf-8";
      }
      // no method. open clazz's
      if(method == undefined) {
        return site + "/view/class/" + clazz;
      }
      // try to find clazz's method
      let url = site + "/view/method/" + clazz + "/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find object's method
      url = site + "/view/method/Object/i/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      /*
      // try to find singleton's method
      url = site + "/view/method/" + clazz + "/s/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find module's method
      url = site + "/view/method/" + clazz + "/m/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find special method
      url = site + "/view/method/" + clazz + "/v/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      // try to find const
      url = site + "/view/method/" + clazz + "/c/" + encode_method(method);
      if(isAvailable(url)) {
        return url;
      }
      */
      // open clazz's 
      return site + "/view/class/" + clazz;
    }
    function isAvailable(url) {
      var http = new XMLHttpRequest();
      http.open("HEAD" , url , false);
      http.setRequestHeader("accept-language" , "ja");
      http.setRequestHeader("Cache-Control"   , "no-cache");
      http.setRequestHeader("content-type"    , "application/x-www-form-urlencoded");
      http.send();
      return http.status == 200;
    }
    function encode_method(method) {
      return encodeURIComponent(method).replace("%","=");
    }
    // open tab
    let url = generate_url(extra.left)
    gBrowser.loadOneTab(url, null, null, null, extra.bang);
  },
  {
    bang      : true,
    literal   : 0,
    completer : function (args, extra) {
      return completer.matcher.substring(ruby_completes)(extra.left || "");
    }
  },
  true
);

追記

「#」だと打ちにくいから

let clazz  = word.split("\.")[0];
let method = word.split("\.")[1];

として「.」で判定した方がいいのかも。

トラックバック - http://keysnail.g.hatena.ne.jp/basyura/20100326
|