diff --git a/common/content/completion.js b/common/content/completion.js
index c27734fc..21cce3d3 100644
--- a/common/content/completion.js
+++ b/common/content/completion.js
@@ -155,7 +155,9 @@ function CompletionContext(editor, name, offset) //{{{
/**
* @property {Object} A map of all contexts, keyed on their names.
* Names are assigned when a context is forked, with its specified
- * name appended, after a '/', to its parent's name.
+ * name appended, after a '/', to its parent's name. May
+ * contain inactive contexts. For active contexts, see
+ * {@link #contextList}.
*/
this.contexts = { "/": this };
/**
@@ -638,6 +640,11 @@ CompletionContext.prototype = {
for (let type in this.selectionTypes)
this.highlight(0, 0, type);
+ /**
+ * @property {[CompletionContext]} A list of active
+ * completion contexts, in the order in which they were
+ * instantiated.
+ */
this.contextList = [];
this.offset = 0;
this.process = [];
diff --git a/common/content/events.js b/common/content/events.js
index 8d132e56..0408e157 100644
--- a/common/content/events.js
+++ b/common/content/events.js
@@ -1014,7 +1014,7 @@ function Events() //{{{
if (event.metaKey)
modifier += "M-";
- if (event.type == "keypress")
+ if (/^key/.test(event.type))
{
if (event.charCode == 0)
{
diff --git a/common/content/liberator.xul b/common/content/liberator.xul
index b8003cfd..3f6ae0ca 100644
--- a/common/content/liberator.xul
+++ b/common/content/liberator.xul
@@ -85,6 +85,7 @@ the terms of any one of the MPL, the GPL or the LGPL.
diff --git a/common/content/ui.js b/common/content/ui.js
index 728c4897..8b74db3e 100644
--- a/common/content/ui.js
+++ b/common/content/ui.js
@@ -352,7 +352,7 @@ function CommandLine() //{{{
{
case this.UP:
if (this.selected == null)
- idx = this.items.length - 1;
+ idx = -2
else
idx = this.selected - 1;
break;
@@ -369,8 +369,8 @@ function CommandLine() //{{{
idx = Math.max(0, Math.min(this.items.length - 1, idx));
break;
}
- this.itemList.selectItem(idx);
- if (idx < 0 || idx >= this.items.length || idx == null)
+
+ if (idx == -1 || this.items.length && idx >= this.items.length || idx == null)
{
// Wrapped. Start again.
this.selected = null;
@@ -378,9 +378,32 @@ function CommandLine() //{{{
}
else
{
+ // Wait for contexts to complete if necessary.
+ // FIXME: Need to make idx relative to individual contexts.
+ let list = this.context.contextList.reverse();
+ if (idx == -2)
+ list = list.slice().reverse();
+ let n = 0;
+ for (let [,context] in Iterator(list))
+ {
+ function done() !(idx >= n + context.items.length || idx == -2 && !context.items.length);
+ while (context.incomplete && !done())
+ liberator.threadYield(true, true);
+ if (done())
+ break;
+ n += context.items.length;
+ }
+
+ // See previous FIXME. This will break if new items in
+ // a previous context come in.
+ if (idx < 0)
+ idx = this.items.length - 1;
+
this.selected = idx;
this.completion = this.items[idx].text;
}
+
+ this.itemList.selectItem(idx);
},
tab: function tab(reverse)
@@ -390,19 +413,6 @@ function CommandLine() //{{{
if (this.context.waitingForTab || this.wildIndex == -1)
this.complete(true, true);
- // Would prefer to only do this check when no completion
- // is available, but there are complications.
- if (this.items.length == 0 || this.context.incomplete)
- {
- // No items. Wait for any unfinished completers.
- let end = Date.now() + 5000;
- while (this.context.incomplete && /* this.items.length == 0 && */ Date.now() < end)
- liberator.threadYield(true, true);
-
- if (this.items.length == 0)
- return liberator.beep();
- }
-
switch (this.wildtype.replace(/.*:/, ""))
{
case "":
@@ -421,6 +431,9 @@ function CommandLine() //{{{
break;
}
+ if (this.items.length == 0)
+ return void liberator.beep();
+
if (this.type.list)
completionList.show();
@@ -1276,6 +1289,7 @@ function CommandLine() //{{{
}
else if (event.type == "keyup")
{
+ let key = events.toString(event);
if (key == "" || key == "")
tabTimer.flush();
}
@@ -1608,7 +1622,6 @@ function CommandLine() //{{{
if (completions)
{
completions.context.cancelAll();
-
completions.wildIndex = -1;
completions.previewClear();
}