mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 11:58:00 +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:
@@ -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
10
content/eval.js
Normal 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:
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user