mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 21:52:27 +01:00
Better JS completion cacheing
This commit is contained in:
@@ -72,7 +72,6 @@ function Completion() //{{{
|
|||||||
let last = ""; /* The last opening char pushed onto the stack. */
|
let last = ""; /* The last opening char pushed onto the stack. */
|
||||||
let lastNonwhite = ""; /* Last non-whitespace character we saw. */
|
let lastNonwhite = ""; /* Last non-whitespace character we saw. */
|
||||||
let lastChar = ""; /* Last character we saw, used for \ escaping quotes. */
|
let lastChar = ""; /* Last character we saw, used for \ escaping quotes. */
|
||||||
let lastObjs = [];
|
|
||||||
let lastKey = null;
|
let lastKey = null;
|
||||||
let compl = [];
|
let compl = [];
|
||||||
let str = "";
|
let str = "";
|
||||||
@@ -129,23 +128,10 @@ function Completion() //{{{
|
|||||||
if (!(objects instanceof Array))
|
if (!(objects instanceof Array))
|
||||||
objects = [objects];
|
objects = [objects];
|
||||||
|
|
||||||
// See if we can use the cached member list from a previous call.
|
|
||||||
if (continuing && objects != lastObjs)
|
|
||||||
{
|
|
||||||
let k = 0;
|
|
||||||
continuing = objects.every(function (obj) obj == lastObjs[k++]);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastObjs = objects;
|
|
||||||
if (continuing)
|
|
||||||
return compl;
|
|
||||||
|
|
||||||
// Can't use the cache. Build a member list.
|
// Can't use the cache. Build a member list.
|
||||||
compl = [];
|
compl = [];
|
||||||
for (let [,obj] in Iterator(objects))
|
for (let [,obj] in Iterator(objects))
|
||||||
{
|
{
|
||||||
if (typeof obj == "string")
|
|
||||||
obj = eval("with (liberator) {" + obj + "}");
|
|
||||||
// Things we can dereference
|
// Things we can dereference
|
||||||
if (["object", "string", "function"].indexOf(typeof obj) == -1)
|
if (["object", "string", "function"].indexOf(typeof obj) == -1)
|
||||||
continue;
|
continue;
|
||||||
@@ -186,12 +172,19 @@ function Completion() //{{{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function eval(arg)
|
this.eval = function eval(arg, key)
|
||||||
{
|
{
|
||||||
|
if (!("eval" in cacheResults))
|
||||||
|
cacheResults.eval = {};
|
||||||
|
let cache = cacheResults.eval;
|
||||||
|
if (!key)
|
||||||
|
key = arg;
|
||||||
|
|
||||||
|
if (key in cache)
|
||||||
|
return cache[key];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// liberator.dump("eval(" + util.escapeString(arg) + ")\n");
|
return cache[key] = window.eval(arg);
|
||||||
return liberator.eval(arg);
|
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
@@ -331,6 +324,7 @@ function Completion() //{{{
|
|||||||
|
|
||||||
this.complete = function complete(string)
|
this.complete = function complete(string)
|
||||||
{
|
{
|
||||||
|
let self = this;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
continuing = lastIdx && string.indexOf(str) == 0;
|
continuing = lastIdx && string.indexOf(str) == 0;
|
||||||
@@ -348,22 +342,53 @@ function Completion() //{{{
|
|||||||
|
|
||||||
// Find any complete statements that we can eval before we eval our object.
|
// Find any complete statements that we can eval before we eval our object.
|
||||||
// This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab>
|
// This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab>
|
||||||
let end = get(0, 0, FULL_STATEMENTS) || 0;
|
let prev = 0;
|
||||||
let preEval = str.substring(0, end) + ";";
|
for (let [,v] in Iterator(get(0)[FULL_STATEMENTS]))
|
||||||
|
{
|
||||||
|
this.eval(str.substring(prev, v + 1));
|
||||||
|
prev = v + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each DOT in a statement, prefix it with TMP, eval it,
|
||||||
|
// and save the result back to TMP. The point of this is to
|
||||||
|
// cache the entire path through an object chain, mainly in
|
||||||
|
// the presence of function calls. There are drawbacks. For
|
||||||
|
// instance, if the value of a variable changes in the course
|
||||||
|
// of inputting a command (let foo=bar; frob(foo); foo=foo.bar; ...),
|
||||||
|
// we'll still use the old value. But, it's worth it.
|
||||||
|
let getObj = function (frame, stop)
|
||||||
|
{
|
||||||
|
const TMP = "__liberator_eval_tmp";
|
||||||
|
let statement = get(frame, 0, STATEMENTS) || 0; // Current statement.
|
||||||
|
let prev = statement;
|
||||||
|
window[TMP] = null;
|
||||||
|
for (let [i, dot] in Iterator(get(frame)[DOTS]))
|
||||||
|
{
|
||||||
|
if (dot < statement)
|
||||||
|
continue;
|
||||||
|
if (dot > stop)
|
||||||
|
break;
|
||||||
|
let s = str.substring(prev, dot);
|
||||||
|
if (prev != statement)
|
||||||
|
s = TMP + "." + s;
|
||||||
|
prev = dot + 1;
|
||||||
|
window[TMP] = self.eval(s, str.substring(statement, dot));
|
||||||
|
}
|
||||||
|
return window[TMP];
|
||||||
|
}
|
||||||
|
|
||||||
let getObjKey = function (frame)
|
let getObjKey = function (frame)
|
||||||
{
|
{
|
||||||
let obj = [liberator, window]; // Default objects;
|
|
||||||
|
|
||||||
let dot = get(frame, 0, DOTS) || -1; // Last dot in frame.
|
let dot = get(frame, 0, DOTS) || -1; // Last dot in frame.
|
||||||
let statement = get(frame, 0, STATEMENTS) || 0; // Current statement.
|
let statement = get(frame, 0, STATEMENTS) || 0; // Current statement.
|
||||||
let end = (frame == -1 ? lastIdx : get(frame + 1)[OFFSET]);
|
let end = (frame == -1 ? lastIdx : get(frame + 1)[OFFSET]);
|
||||||
|
|
||||||
|
let obj = [liberator, 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;
|
||||||
else // Yes. Set the object to the string before the dot.
|
else // Yes. Set the object to the string before the dot.
|
||||||
obj = preEval + str.substring(statement, dot);
|
obj = getObj(frame, dot);
|
||||||
|
|
||||||
let [, space, key] = str.substring(dot + 1, end).match(/^(\s*)(.*)/);
|
let [, space, key] = str.substring(dot + 1, end).match(/^(\s*)(.*)/);
|
||||||
return [dot + 1 + space.length, obj, key];
|
return [dot + 1 + space.length, obj, key];
|
||||||
@@ -400,11 +425,11 @@ function Completion() //{{{
|
|||||||
return [0, []];
|
return [0, []];
|
||||||
|
|
||||||
// Begining of the statement upto the opening [
|
// Begining of the statement upto the opening [
|
||||||
let obj = preEval + str.substring(get(-3, 0, STATEMENTS), get(-2)[OFFSET]);
|
let obj = getObj(-3, get(-2)[OFFSET]);
|
||||||
// After the opening [ upto the opening ", plus '' to take care of any operators before it
|
// After the opening [ upto the opening ", plus '' to take care of any operators before it
|
||||||
let key = preEval + str.substring(get(-2)[OFFSET] + 1, top[OFFSET]) + "''";
|
let key = str.substring(get(-2)[OFFSET] + 1, top[OFFSET]) + "''";
|
||||||
// Now eval the key, to process any referenced variables.
|
// Now eval the key, to process any referenced variables.
|
||||||
key = eval(key);
|
key = this.eval(key);
|
||||||
|
|
||||||
let compl = this.objectKeys(obj);
|
let compl = this.objectKeys(obj);
|
||||||
return [top[OFFSET], this.filter(compl, key + string, last, key.length)];
|
return [top[OFFSET], this.filter(compl, key + string, last, key.length)];
|
||||||
@@ -430,9 +455,10 @@ function Completion() //{{{
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!completer)
|
if (!completer)
|
||||||
completer = eval(obj)[func].liberatorCompleter;
|
completer = obj[func].liberatorCompleter;
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
|
liberator.dump({call: completer, func: func, obj: obj, string: string, args: "args"});
|
||||||
if (!completer)
|
if (!completer)
|
||||||
return [0, []];
|
return [0, []];
|
||||||
|
|
||||||
@@ -446,8 +472,8 @@ function Completion() //{{{
|
|||||||
});
|
});
|
||||||
args.push(key);
|
args.push(key);
|
||||||
|
|
||||||
let compl = completer.call(this, func, preEval, obj, string, args);
|
let compl = completer.call(this, func, obj, string, args);
|
||||||
key = eval(preEval + key);
|
key = this.eval(key);
|
||||||
return [top[OFFSET], this.filter(compl, key + string, last, key.length)];
|
return [top[OFFSET], this.filter(compl, key + string, last, key.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -640,14 +640,13 @@ const liberator = (function () //{{{
|
|||||||
liberator.dump((msg || "") + (new Error()).stack.replace(/.*\n/, ""));
|
liberator.dump((msg || "") + (new Error()).stack.replace(/.*\n/, ""));
|
||||||
},
|
},
|
||||||
|
|
||||||
// with (liberator) means, liberator is the default namespace "inside" eval
|
|
||||||
eval: function (str)
|
eval: function (str)
|
||||||
{
|
{
|
||||||
const fileName = "chrome://liberator/content/liberator.js";
|
const fileName = "chrome://liberator/content/liberator.js";
|
||||||
const line = new Error().lineNumber + 3;
|
const line = new Error().lineNumber + 3;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return eval("with (liberator) {" + str + "}");
|
return window.eval(str);
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user