Ubiquity用evalを作ってみる

プレビューに式の結果を表示するコマンドeval

*1


範囲選択で実行とかもできますね。副作用も残るので、たとえば、

CmdUtils.getWindow().document.body.contentEditable = true

を範囲選択してCtrl+Spaceで窓を開いてevalを選ぶと面白いことがおきるかも
(戻すときは)

CmdUtils.getWindow().document.body.contentEditable = false

ソース

CmdUtils.CreateCommand({
  name: "eval",
  icon: "chrome://ubiquity/skin/icons/favicon.ico",
  homepage: "http://d.hatena.ne.jp/bellbind/",
  author: {name: "bellbind", email: "bellbind@gmail.com"},
  license: "GPL",
  description: "evaluate script",
  help: "evaluate script",
  takes: {"input": noun_arb_text},
  preview: function (pblock, input) {
    var code = input.text;
    var pnode = jQuery(pblock);
    var pre = jQuery("<pre></pre>");
    pre.css({overflow: "scroll"});
    pre.width(450);
    pre.height(450);
    pre.text(this._eval(code));
    pnode.empty().append(pre);
  },
  execute: function (input) {
    var code = input.text;
    CmdUtils.getWindow().alert(this._eval(code));
  },
  _eval: function (code) {
    try {
      return this._pp(eval(code));
    } catch (ex) {
      return this._pp(ex);
    }
  },
  _pp: function (obj) {
    return this._pplevel(obj, "", false, false, 2);
  },
  _pplevel: function (obj, indent, cont, flat, level) {
    var itop = cont ? "" : indent;
    switch (obj) {
      case undefined: return itop + "undefined";
      case null: return itop + "null";
      case true: return itop + "true";
      case false: return itop + "false";
    }
    if (level === 0) return itop + "...";
    switch (typeof obj) {
      case "number": return itop + obj.toString();
      case "string": return itop +
        (level < 2 ? "'...'" : this._ppstr(obj));
      case "function": return itop +
        (level < 2 ? "function ..." : obj.toSource().split("\n").join(indent + "\n"));
    }
    try {
      var nlevel = level - 1;
      var nflat = nlevel < 2;
      var nindent = this._nest(indent);
      var mindent = flat ? "": nindent;
      var mcont = flat ? true : false;
      var mjoin = flat ? ", " : ",\n";
      var sjoin = flat ? "" : "\n";
      switch (obj.constructor) {
        case Array: return [
          itop + "[",
          [this._pplevel(item, nindent, mcont, nflat, nlevel)
           for each (item in obj)].join(mjoin),
          indent + "]"].join(sjoin);
      }
      var keys = [k for (k in obj)].sort();
      var name = "";
      try {
        name = "/* " + obj.constructor.name + " */ ";
      } catch (ex) {
        ;
      }
      return [
        itop + "{" + name,
        [mindent + this._ppstr(k) + ": " +
         this._pplevel(obj[k], nindent, true, nflat, nlevel)
         for each (k in keys)].join(mjoin),
        indent + "}"].join(sjoin);
    } catch (ex) {
      return itop + obj.toSource();
    }
  },
  _ppstr: function (obj) {
    return "'" + obj.split("'").join("\\'") +"'";
  },
  _nest: function (indent) {return indent + " ";}
});

JavaScript-1.8のlist comprehensionとか使って書きました。
結構いいかげんなコードだけど、システム内の機能を試す分には十分だろうか。

*1:Ubiquityが入った状態でgistのページに行くと、上に登録ボタンがでるんですね。