mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 04:07:58 +01:00
Wait for <Tab> before evaluating funcitons in JS completion.
This commit is contained in:
@@ -54,14 +54,14 @@ function CompletionContext(editor, name, offset)
|
|||||||
self.parent = parent;
|
self.parent = parent;
|
||||||
self.offset = parent.offset + (offset || 0);
|
self.offset = parent.offset + (offset || 0);
|
||||||
self.keys = util.cloneObject(parent.keys);
|
self.keys = util.cloneObject(parent.keys);
|
||||||
delete self._generate;
|
|
||||||
delete self._filter; // FIXME?
|
delete self._filter; // FIXME?
|
||||||
|
delete self._generate;
|
||||||
delete self._ignoreCase;
|
delete self._ignoreCase;
|
||||||
["anchored", "compare", "editor", "filterFunc", "keys", "_process", "quote", "title", "top"].forEach(function (key)
|
["anchored", "compare", "editor", "filterFunc", "keys", "_process", "quote", "title", "top"].forEach(function (key)
|
||||||
self[key] = parent[key]);
|
self[key] = parent[key]);
|
||||||
if (self != this)
|
if (self != this)
|
||||||
return self;
|
return self;
|
||||||
["_caret", "contextList", "onUpdate", "selectionTypes", "tabPressed", "updateAsync", "value"].forEach(function (key) {
|
["_caret", "contextList", "onUpdate", "selectionTypes", "tabPressed", "updateAsync", "value", "waitingForTab"].forEach(function (key) {
|
||||||
self.__defineGetter__(key, function () this.top[key]);
|
self.__defineGetter__(key, function () this.top[key]);
|
||||||
self.__defineSetter__(key, function (val) this.top[key] = val);
|
self.__defineSetter__(key, function (val) this.top[key] = val);
|
||||||
});
|
});
|
||||||
@@ -84,9 +84,9 @@ function CompletionContext(editor, name, offset)
|
|||||||
let text = Array.concat(this.getKey(item, "text"));
|
let text = Array.concat(this.getKey(item, "text"));
|
||||||
for (let [i, str] in Iterator(text))
|
for (let [i, str] in Iterator(text))
|
||||||
{
|
{
|
||||||
if (this.match(str))
|
if (this.match(String(str)))
|
||||||
{
|
{
|
||||||
item.text = text[i];
|
item.text = String(text[i]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,10 +100,11 @@ function CompletionContext(editor, name, offset)
|
|||||||
this.__defineGetter__("incomplete", function () this.contextList.some(function (c) c.parent && c.incomplete));
|
this.__defineGetter__("incomplete", function () this.contextList.some(function (c) c.parent && c.incomplete));
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
this.name = name || "";
|
|
||||||
this.cache = {};
|
this.cache = {};
|
||||||
this.key = "";
|
|
||||||
this.itemCache = {};
|
this.itemCache = {};
|
||||||
|
this.key = "";
|
||||||
|
this.message = null;
|
||||||
|
this.name = name || "";
|
||||||
this._completions = []; // FIXME
|
this._completions = []; // FIXME
|
||||||
this.getKey = function (item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item) : item.item[self.keys[key]];
|
this.getKey = function (item, key) (typeof self.keys[key] == "function") ? self.keys[key].call(this, item) : item.item[self.keys[key]];
|
||||||
}
|
}
|
||||||
@@ -111,15 +112,23 @@ CompletionContext.prototype = {
|
|||||||
// Temporary
|
// Temporary
|
||||||
get allItems()
|
get allItems()
|
||||||
{
|
{
|
||||||
let self = this;
|
try
|
||||||
let minStart = Math.min.apply(Math, [context.offset for ([k, context] in Iterator(this.contexts)) if (context.items.length && context.hasItems)]);
|
{
|
||||||
let items = this.contextList.map(function (context) {
|
let self = this;
|
||||||
if (!context.hasItems)
|
let minStart = Math.min.apply(Math, [context.offset for ([k, context] in Iterator(this.contexts)) if (context.items.length && context.hasItems)]);
|
||||||
return [];
|
let items = this.contextList.map(function (context) {
|
||||||
let prefix = self.value.substring(minStart, context.offset);
|
if (!context.hasItems)
|
||||||
return context.items.map(function makeItem(item) ({ text: prefix + item.text, item: item.item }));
|
return [];
|
||||||
});
|
let prefix = self.value.substring(minStart, context.offset);
|
||||||
return { start: minStart, items: util.Array.flatten(items), longestSubstring: this.longestAllSubstring }
|
return context.items.map(function makeItem(item) ({ text: prefix + item.text, item: item.item }));
|
||||||
|
});
|
||||||
|
return { start: minStart, items: util.Array.flatten(items), longestSubstring: this.longestAllSubstring }
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
liberator.reportError(e);
|
||||||
|
return { start: 0, items: [], longestAllSubstring: "" }
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Temporary
|
// Temporary
|
||||||
get allSubstrings()
|
get allSubstrings()
|
||||||
@@ -135,6 +144,8 @@ CompletionContext.prototype = {
|
|||||||
function (res, list) res.filter(
|
function (res, list) res.filter(
|
||||||
function (str) list.some(function (s) s.substr(0, str.length) == str)),
|
function (str) list.some(function (s) s.substr(0, str.length) == str)),
|
||||||
lists.pop());
|
lists.pop());
|
||||||
|
if (!substrings) // FIXME: How is this undefined?
|
||||||
|
return [];
|
||||||
return util.Array.uniq(substrings);
|
return util.Array.uniq(substrings);
|
||||||
},
|
},
|
||||||
// Temporary
|
// Temporary
|
||||||
@@ -429,6 +440,7 @@ CompletionContext.prototype = {
|
|||||||
this.selectionTypes = {};
|
this.selectionTypes = {};
|
||||||
this.tabPressed = false;
|
this.tabPressed = false;
|
||||||
this.title = ["Completions"];
|
this.title = ["Completions"];
|
||||||
|
this.waitingForTab = false;
|
||||||
this.updateAsync = false;
|
this.updateAsync = false;
|
||||||
if (this.editor)
|
if (this.editor)
|
||||||
{
|
{
|
||||||
@@ -473,6 +485,7 @@ function Completion() //{{{
|
|||||||
.createInstance(Components.interfaces.nsIJSON);
|
.createInstance(Components.interfaces.nsIJSON);
|
||||||
const OFFSET = 0, CHAR = 1, STATEMENTS = 2, DOTS = 3, FULL_STATEMENTS = 4, FUNCTIONS = 5;
|
const OFFSET = 0, CHAR = 1, STATEMENTS = 2, DOTS = 3, FULL_STATEMENTS = 4, FUNCTIONS = 5;
|
||||||
let stack = [];
|
let stack = [];
|
||||||
|
let functions = [];
|
||||||
let top = []; /* The element on the top of the stack. */
|
let top = []; /* The element on the top of the stack. */
|
||||||
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. */
|
||||||
@@ -564,8 +577,6 @@ function Completion() //{{{
|
|||||||
|
|
||||||
this.eval = function eval(arg, key, tmp)
|
this.eval = function eval(arg, key, tmp)
|
||||||
{
|
{
|
||||||
if (!this.context.cache.eval)
|
|
||||||
this.context.cache.eval = {};
|
|
||||||
let cache = this.context.cache.eval;
|
let cache = this.context.cache.eval;
|
||||||
if (!key)
|
if (!key)
|
||||||
key = arg;
|
key = arg;
|
||||||
@@ -629,6 +640,7 @@ function Completion() //{{{
|
|||||||
let i = 0, c = ""; /* Current index and character, respectively. */
|
let i = 0, c = ""; /* Current index and character, respectively. */
|
||||||
|
|
||||||
stack = [];
|
stack = [];
|
||||||
|
functions = [];
|
||||||
push("#root");
|
push("#root");
|
||||||
|
|
||||||
/* Build a parse stack, discarding entries as opening characters
|
/* Build a parse stack, discarding entries as opening characters
|
||||||
@@ -669,6 +681,7 @@ function Completion() //{{{
|
|||||||
/* Function call, or if/while/for/... */
|
/* Function call, or if/while/for/... */
|
||||||
if (/[\w\d$]/.test(lastNonwhite))
|
if (/[\w\d$]/.test(lastNonwhite))
|
||||||
{
|
{
|
||||||
|
functions.push(i);
|
||||||
top[FUNCTIONS].push(i);
|
top[FUNCTIONS].push(i);
|
||||||
top[STATEMENTS].pop();
|
top[STATEMENTS].pop();
|
||||||
}
|
}
|
||||||
@@ -723,6 +736,9 @@ function Completion() //{{{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.context.cache.eval)
|
||||||
|
this.context.cache.eval = {};
|
||||||
|
|
||||||
/* Okay, have parse stack. Figure out what we're completing. */
|
/* Okay, have parse stack. Figure out what we're completing. */
|
||||||
|
|
||||||
if (/[\])}"';]/.test(str[lastIdx - 1]) && last != '"' && last != '"')
|
if (/[\])}"';]/.test(str[lastIdx - 1]) && last != '"' && last != '"')
|
||||||
@@ -733,8 +749,21 @@ function Completion() //{{{
|
|||||||
let prev = 0;
|
let prev = 0;
|
||||||
for (let [,v] in Iterator(get(0)[FULL_STATEMENTS]))
|
for (let [,v] in Iterator(get(0)[FULL_STATEMENTS]))
|
||||||
{
|
{
|
||||||
this.eval(str.substring(prev, v + 1));
|
let key = str.substring(prev, v + 1);
|
||||||
prev = v + 1;
|
if (checkFunction(prev, v, key))
|
||||||
|
return;
|
||||||
|
this.eval(key);
|
||||||
|
prev = v + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
return false;
|
||||||
|
self.context.waitingForTab = true;
|
||||||
|
self.context.message = "Waiting for <Tab>";
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each DOT in a statement, prefix it with TMP, eval it,
|
// For each DOT in a statement, prefix it with TMP, eval it,
|
||||||
@@ -757,10 +786,15 @@ function Completion() //{{{
|
|||||||
if (dot > stop)
|
if (dot > stop)
|
||||||
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;
|
||||||
prev = dot + 1;
|
|
||||||
cacheKey = str.substring(statement, dot);
|
cacheKey = str.substring(statement, dot);
|
||||||
|
|
||||||
|
if (checkFunction(prev, dot, cacheKey))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
prev = dot + 1;
|
||||||
obj = self.eval(s, cacheKey, obj);
|
obj = self.eval(s, cacheKey, obj);
|
||||||
}
|
}
|
||||||
return [[obj, cacheKey]]
|
return [[obj, cacheKey]]
|
||||||
@@ -889,6 +923,8 @@ function Completion() //{{{
|
|||||||
|
|
||||||
let [offset, obj, func] = getObjKey(-3);
|
let [offset, obj, func] = getObjKey(-3);
|
||||||
let key = str.substring(get(-2, 0, STATEMENTS), top[OFFSET]) + "''";
|
let key = str.substring(get(-2, 0, STATEMENTS), top[OFFSET]) + "''";
|
||||||
|
if (!obj.length)
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ 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 *****/
|
||||||
|
|
||||||
|
plugins.contexts = {};
|
||||||
|
function Script(name)
|
||||||
|
{
|
||||||
|
if (plugins.contexts[name])
|
||||||
|
return plugins.contexts[name];
|
||||||
|
plugins.contexts[name] = this;
|
||||||
|
this.NAME = name;
|
||||||
|
}
|
||||||
|
Script.prototype = plugins;
|
||||||
|
|
||||||
// TODO: why are we passing around strings rather than file objects?
|
// TODO: why are we passing around strings rather than file objects?
|
||||||
function IO() //{{{
|
function IO() //{{{
|
||||||
{
|
{
|
||||||
@@ -815,7 +825,7 @@ lookup:
|
|||||||
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
.getService(Components.interfaces.mozIJSSubScriptLoader);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
loader.loadSubScript(uri.spec, {__proto__: plugins});
|
loader.loadSubScript(uri.spec, new Script(file.path));
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ function Highlights(name, store, serial)
|
|||||||
|
|
||||||
CompTitle color: magenta; background: white; font-weight: bold;
|
CompTitle color: magenta; background: white; font-weight: bold;
|
||||||
CompTitle>* border-bottom: 1px dashed magenta;
|
CompTitle>* border-bottom: 1px dashed magenta;
|
||||||
|
CompMsg font-style: italic; margin-left: 16px;
|
||||||
CompItem
|
CompItem
|
||||||
CompItem[selected] background: yellow;
|
CompItem[selected] background: yellow;
|
||||||
CompItem>* padding: 0 .5ex;
|
CompItem>* padding: 0 .5ex;
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ function CommandLine() //{{{
|
|||||||
let full = !longest && wildmode.checkHas(wildType, "full");
|
let full = !longest && wildmode.checkHas(wildType, "full");
|
||||||
|
|
||||||
// we need to build our completion list first
|
// we need to build our completion list first
|
||||||
if (completionIndex == UNINITIALIZED)
|
if (completionIndex == UNINITIALIZED || completionContext.waitingForTab)
|
||||||
{
|
{
|
||||||
completionIndex = -1;
|
completionIndex = -1;
|
||||||
completionPrefix = command.substring(0, commandWidget.selectionStart);
|
completionPrefix = command.substring(0, commandWidget.selectionStart);
|
||||||
@@ -1365,13 +1365,14 @@ function ItemList(id) //{{{
|
|||||||
|
|
||||||
items.contextList.forEach(function init_eachContext(context) {
|
items.contextList.forEach(function init_eachContext(context) {
|
||||||
delete context.cache.nodes;
|
delete context.cache.nodes;
|
||||||
if (!context.items.length)
|
if (!context.items.length && !context.message)
|
||||||
return;
|
return;
|
||||||
context.cache.nodes = [];
|
context.cache.nodes = [];
|
||||||
dom(<div key="root">
|
dom(<div key="root">
|
||||||
<div highlight="Completions">
|
<div highlight="Completions">
|
||||||
{context.createRow(context.title || [], "CompTitle")}
|
{context.createRow(context.title || [], "CompTitle")}
|
||||||
</div>
|
</div>
|
||||||
|
<div key="message" highlight="CompMsg" style="display: none"/>
|
||||||
<div key="up" highlight="CompLess"/>
|
<div key="up" highlight="CompLess"/>
|
||||||
<div key="items" highlight="Completions"/>
|
<div key="items" highlight="Completions"/>
|
||||||
<div key="down" highlight="CompMore"/>
|
<div key="down" highlight="CompMore"/>
|
||||||
@@ -1396,6 +1397,7 @@ function ItemList(id) //{{{
|
|||||||
startIndex = offset;
|
startIndex = offset;
|
||||||
endIndex = Math.min(startIndex + maxItems, items.allItems.items.length);
|
endIndex = Math.min(startIndex + maxItems, items.allItems.items.length);
|
||||||
|
|
||||||
|
let haveCompletions = false;
|
||||||
let off = 0;
|
let off = 0;
|
||||||
function getRows(context)
|
function getRows(context)
|
||||||
{
|
{
|
||||||
@@ -1410,9 +1412,20 @@ function ItemList(id) //{{{
|
|||||||
let nodes = context.cache.nodes;
|
let nodes = context.cache.nodes;
|
||||||
if (!nodes)
|
if (!nodes)
|
||||||
return;
|
return;
|
||||||
|
haveCompletions = true;
|
||||||
|
|
||||||
|
nodes.message.style.display = "none";
|
||||||
|
if (context.message)
|
||||||
|
{
|
||||||
|
nodes.message.textContent = context.message;
|
||||||
|
nodes.message.style.display = "block";
|
||||||
|
}
|
||||||
let root = nodes.root
|
let root = nodes.root
|
||||||
let items = nodes.items;
|
let items = nodes.items;
|
||||||
let [start, end] = getRows(context);
|
let [start, end] = getRows(context);
|
||||||
|
if (start == end)
|
||||||
|
return;
|
||||||
|
|
||||||
for (let [i, row] in Iterator(context.getRows(start, end, doc)))
|
for (let [i, row] in Iterator(context.getRows(start, end, doc)))
|
||||||
nodes[i] = row;
|
nodes[i] = row;
|
||||||
for (let [i, row] in util.Array.iterator2(nodes))
|
for (let [i, row] in util.Array.iterator2(nodes))
|
||||||
@@ -1434,7 +1447,7 @@ function ItemList(id) //{{{
|
|||||||
nodes.down.style.display = (end == context.items.length) ? "none" : "block";
|
nodes.down.style.display = (end == context.items.length) ? "none" : "block";
|
||||||
});
|
});
|
||||||
|
|
||||||
divNodes.noCompletions.style.display = (off > 0) ? "none" : "block";
|
divNodes.noCompletions.style.display = haveCompletions ? "none" : "block";
|
||||||
|
|
||||||
completionElements = buffer.evaluateXPath("//xhtml:div[@liberator:highlight='CompItem']", doc);
|
completionElements = buffer.evaluateXPath("//xhtml:div[@liberator:highlight='CompItem']", doc);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user