1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-23 18:02:27 +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.
}}} ***** 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)
{
if (!(this instanceof arguments.callee))
@@ -359,6 +353,13 @@ CompletionContext.prototype = {
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)
{
let self = this;
@@ -493,8 +494,6 @@ function Completion() //{{{
catch (e) {}
const EVAL_TMP = "__liberator_eval_tmp";
Javascript.cleanEval = _cleanEval;
delete modules._cleanEval;
function Javascript()
{
@@ -571,11 +570,19 @@ function Completion() //{{{
// the wrappedJSObject instead, and return any keys
// available in the object itself.
let orig = obj;
if (obj.wrappedJSObject)
obj = obj.wrappedJSObject;
// v[0] in orig and orig[v[0]] catch different cases. XPCOM
// 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,
// return that, too.
if (orig.wrappedJSObject)
@@ -599,19 +606,27 @@ function Completion() //{{{
this.eval = function eval(arg, key, tmp)
{
let cache = this.context.cache.eval;
let context = this.context.cache.evalContext;
if (!key)
key = arg;
if (key in cache)
return cache[key];
context[EVAL_TMP] = tmp;
try
{
return cache[key] = Javascript.cleanEval(arg, tmp);
let res = liberator.eval(arg, context);
return res;
}
catch (e)
{
return null;
}
finally
{
delete context[EVAL_TMP];
}
}
/* Get an element from the stack. If @n is negative,
@@ -773,8 +788,9 @@ function Completion() //{{{
return;
}
if (!this.context.cache.eval)
this.context.cache.eval = {};
let cache = this.context.cache;
this.context.getCache("eval", Object);
this.context.getCache("evalContext", function () ({ __proto__: modules }));
/* Okay, have parse stack. Figure out what we're completing. */
@@ -794,7 +810,7 @@ function Completion() //{{{
function checkFunction(start, end, key)
{
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;
self.context.waitingForTab = true;
return true;
@@ -817,12 +833,13 @@ function Completion() //{{{
{
if (dot < statement)
continue;
if (dot > stop)
if (dot > stop || dot <= prev)
break;
let s = str.substring(prev, dot);
if (prev != statement)
s = EVAL_TMP + "." + s;
liberator.dump("s : " + s);
cacheKey = str.substring(statement, dot);
if (checkFunction(prev, dot, cacheKey))
@@ -841,7 +858,7 @@ function Completion() //{{{
let end = (frame == -1 ? lastIdx : get(frame + 1)[OFFSET]);
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? */
if (dot < statement) // No.
dot = statement - 1;
@@ -1022,7 +1039,7 @@ function Completion() //{{{
let [offset, obj, key] = getObjKey(-1);
// 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.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
if (/\.js$/.test(filename))
{
let loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
try
{
loader.loadSubScript(uri.spec, new Script(file.path));
liberator.loadScript(uri.spec, new Script(file.path));
}
catch (e)
{

View File

@@ -31,6 +31,13 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const plugins = {};
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 () //{{{
{
////////////////////////////////////////////////////////////////////////////////
@@ -705,29 +712,32 @@ const liberator = (function () //{{{
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
{
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)
{
e.source = str;
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;
delete context[EVAL_ERROR];
delete context[EVAL_RESULT];
delete context[EVAL_STRING];
}
},

View File

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