mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 18:12: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:
@@ -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
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
|
// 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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
Reference in New Issue
Block a user