1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 13:52:26 +01:00

liberator.eval (:js/:echo/...) now uses a separate context. JS completion uses disposable contexts that last one session.

This commit is contained in:
Kris Maglione
2008-11-29 16:22:35 +00:00
parent 3f6f53580f
commit f068dc57ca
5 changed files with 80 additions and 39 deletions

View File

@@ -26,12 +26,6 @@ the provisions above, a recipient may use your version of this file under
the terms of any one of the MPL, the GPL or the LGPL. the terms of any one of the MPL, the GPL or the LGPL.
}}} ***** END LICENSE BLOCK *****/ }}} ***** END LICENSE BLOCK *****/
// An eval with a cleaner lexical scope.
modules._cleanEval = function _cleanEval(__liberator_eval_arg, __liberator_eval_tmp)
{
return window.eval(__liberator_eval_arg);
}
function CompletionContext(editor, name, offset) function CompletionContext(editor, name, offset)
{ {
if (!(this instanceof arguments.callee)) if (!(this instanceof arguments.callee))
@@ -359,6 +353,13 @@ CompletionContext.prototype = {
this._filter = this._filter.substr(count); this._filter = this._filter.substr(count);
}, },
getCache: function (key, defVal)
{
if (!(key in this.cache))
this.cache[key] = defVal();
return this.cache[key];
},
getItems: function getItems(start, end) getItems: function getItems(start, end)
{ {
let self = this; let self = this;
@@ -493,8 +494,6 @@ function Completion() //{{{
catch (e) {} catch (e) {}
const EVAL_TMP = "__liberator_eval_tmp"; const EVAL_TMP = "__liberator_eval_tmp";
Javascript.cleanEval = _cleanEval;
delete modules._cleanEval;
function Javascript() function Javascript()
{ {
@@ -571,11 +570,19 @@ function Completion() //{{{
// the wrappedJSObject instead, and return any keys // the wrappedJSObject instead, and return any keys
// available in the object itself. // available in the object itself.
let orig = obj; let orig = obj;
if (obj.wrappedJSObject)
obj = obj.wrappedJSObject;
// v[0] in orig and orig[v[0]] catch different cases. XPCOM // v[0] in orig and orig[v[0]] catch different cases. XPCOM
// objects are problematic, to say the least. // objects are problematic, to say the least.
compl = [v for (v in this.iter(obj)) if (v[0] in orig || orig[v[0]] !== undefined)]; if (obj.__proto__ == modules || obj.__proto__ == plugins) // Special case.
compl = [v for (v in Iterator(obj))];
else
{
if (obj.wrappedJSObject)
obj = obj.wrappedJSObject;
compl = [v for (v in this.iter(obj))
if ((typeof orig == "object" && v[0] in orig) || orig[v[0]] !== undefined)];
}
// And if wrappedJSObject happens to be available, // And if wrappedJSObject happens to be available,
// return that, too. // return that, too.
if (orig.wrappedJSObject) if (orig.wrappedJSObject)
@@ -599,19 +606,27 @@ function Completion() //{{{
this.eval = function eval(arg, key, tmp) this.eval = function eval(arg, key, tmp)
{ {
let cache = this.context.cache.eval; let cache = this.context.cache.eval;
let context = this.context.cache.evalContext;
if (!key) if (!key)
key = arg; key = arg;
if (key in cache) if (key in cache)
return cache[key]; return cache[key];
context[EVAL_TMP] = tmp;
try try
{ {
return cache[key] = Javascript.cleanEval(arg, tmp); let res = liberator.eval(arg, context);
return res;
} }
catch (e) catch (e)
{ {
return null; return null;
} }
finally
{
delete context[EVAL_TMP];
}
} }
/* Get an element from the stack. If @n is negative, /* Get an element from the stack. If @n is negative,
@@ -773,8 +788,9 @@ function Completion() //{{{
return; return;
} }
if (!this.context.cache.eval) let cache = this.context.cache;
this.context.cache.eval = {}; this.context.getCache("eval", Object);
this.context.getCache("evalContext", function () ({ __proto__: modules }));
/* Okay, have parse stack. Figure out what we're completing. */ /* Okay, have parse stack. Figure out what we're completing. */
@@ -794,7 +810,7 @@ function Completion() //{{{
function checkFunction(start, end, key) function checkFunction(start, end, key)
{ {
let res = functions.some(function (idx) idx >= start && idx < end); let res = functions.some(function (idx) idx >= start && idx < end);
if (!res || self.context.tabPressed || key in self.context.cache.eval) if (!res || self.context.tabPressed || key in cache.eval)
return false; return false;
self.context.waitingForTab = true; self.context.waitingForTab = true;
return true; return true;
@@ -817,12 +833,13 @@ function Completion() //{{{
{ {
if (dot < statement) if (dot < statement)
continue; continue;
if (dot > stop) if (dot > stop || dot <= prev)
break; break;
let s = str.substring(prev, dot); let s = str.substring(prev, dot);
if (prev != statement) if (prev != statement)
s = EVAL_TMP + "." + s; s = EVAL_TMP + "." + s;
liberator.dump("s : " + s);
cacheKey = str.substring(statement, dot); cacheKey = str.substring(statement, dot);
if (checkFunction(prev, dot, cacheKey)) if (checkFunction(prev, dot, cacheKey))
@@ -841,7 +858,7 @@ function Completion() //{{{
let end = (frame == -1 ? lastIdx : get(frame + 1)[OFFSET]); let end = (frame == -1 ? lastIdx : get(frame + 1)[OFFSET]);
cacheKey = null; cacheKey = null;
let obj = [[modules, "modules"], [window, "window"]]; // Default objects; let obj = [[cache.evalContext, "Local Variables"], [modules, "modules"], [window, "window"]]; // Default objects;
/* Is this an object dereference? */ /* Is this an object dereference? */
if (dot < statement) // No. if (dot < statement) // No.
dot = statement - 1; dot = statement - 1;
@@ -1022,7 +1039,7 @@ function Completion() //{{{
let [offset, obj, key] = getObjKey(-1); let [offset, obj, key] = getObjKey(-1);
// Wait for a keypress before completing the default objects. // Wait for a keypress before completing the default objects.
if (!this.context.tabPressed && key == "" && obj.length == 2) if (!this.context.tabPressed && key == "" && obj.length > 1)
{ {
this.context.waitingForTab = true; this.context.waitingForTab = true;
this.context.message = "Waiting for key press"; this.context.message = "Waiting for key press";

10
content/eval.js Normal file
View File

@@ -0,0 +1,10 @@
try { __liberator_eval_result = eval(__liberator_eval_string)
}
catch (e)
{
__liberator_eval_error = e;
}
// Important: The eval statement *must* remain on the first line
// in order for line numbering in any errors to remain correct.
//
// vim: set fdm=marker sw=4 ts=4 et:

View File

@@ -822,11 +822,9 @@ lookup:
// handle pure javascript files specially // handle pure javascript files specially
if (/\.js$/.test(filename)) if (/\.js$/.test(filename))
{ {
let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
try try
{ {
loader.loadSubScript(uri.spec, new Script(file.path)); liberator.loadScript(uri.spec, new Script(file.path));
} }
catch (e) catch (e)
{ {

View File

@@ -31,6 +31,13 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const plugins = {}; const plugins = {};
plugins.__proto__ = modules; plugins.__proto__ = modules;
const EVAL_ERROR = "__liberator_eval_error";
const EVAL_RESULT = "__liberator_eval_result";
const EVAL_STRING = "__liberator_eval_string";
const userContext = {
__proto__: modules
};
const liberator = (function () //{{{ const liberator = (function () //{{{
{ {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -705,29 +712,32 @@ const liberator = (function () //{{{
commandline.echo(str, commandline.HL_INFOMSG, flags); commandline.echo(str, commandline.HL_INFOMSG, flags);
}, },
eval: function (str) loadScript: function (uri, context)
{
let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript(uri, context);
},
eval: function (str, context)
{ {
const fileName = "chrome://liberator/content/liberator.js";
const line = new Error().lineNumber + 3;
try try
{ {
return window.eval(str); if (!context)
context = userContext;
context[EVAL_ERROR] = null;
context[EVAL_STRING] = str;
context[EVAL_RESULT] = null;
this.loadScript("chrome://liberator/content/eval.js", context);
if (context[EVAL_ERROR])
throw context[EVAL_ERROR];
return context[EVAL_RESULT];
} }
catch (e) finally
{ {
if (e.fileName == fileName && e.lineNumber >= line) delete context[EVAL_ERROR];
{ delete context[EVAL_RESULT];
e.source = str; delete context[EVAL_STRING];
e.fileName = "<Evaled string>";
e.lineNumber -= line;
if (modules.io && io.sourcing)
{
liberator.dump(io.sourcing);
e.fileName = io.sourcing.file;
e.lineNumber += io.sourcing.line;
}
}
throw e;
} }
}, },

View File

@@ -350,6 +350,11 @@ const util = { //{{{
try // window.content often does not want to be queried with "var i in object" try // window.content often does not want to be queried with "var i in object"
{ {
let hasValue = !("__iterator__" in object); let hasValue = !("__iterator__" in object);
if (object.__proto__ == modules || object.__proto__ == plugins)
{
object = Iterator(object);
hasValue = false;
}
for (let i in object) for (let i in object)
{ {
let value = <![CDATA[<no value>]]>; let value = <![CDATA[<no value>]]>;
@@ -365,6 +370,7 @@ const util = { //{{{
else else
var noVal = true; var noVal = true;
} }
value = template.highlight(value, true, 150); value = template.highlight(value, true, 150);
// FIXME: Inline style. // FIXME: Inline style.
key = <span style="font-weight: bold;">{i}</span>; key = <span style="font-weight: bold;">{i}</span>;