summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/content/commandline.js2
-rw-r--r--common/content/dactyl.js13
-rw-r--r--common/modules/addons.jsm20
-rw-r--r--common/modules/completion.jsm14
-rw-r--r--common/modules/util.jsm15
-rw-r--r--common/tests/functional/testCommands.js177
-rw-r--r--pentadactyl/content/config.js40
7 files changed, 174 insertions, 107 deletions
diff --git a/common/content/commandline.js b/common/content/commandline.js
index 6c889eeb..fb585e9c 100644
--- a/common/content/commandline.js
+++ b/common/content/commandline.js
@@ -1418,7 +1418,7 @@ var CommandLine = Module("commandline", {
let command = commandline.command;
self.accepted = true;
- modes.pop();
+ return function () modes.pop();
});
[
diff --git a/common/content/dactyl.js b/common/content/dactyl.js
index eca46353..c273ca1f 100644
--- a/common/content/dactyl.js
+++ b/common/content/dactyl.js
@@ -1989,19 +1989,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
context.completions = [[k, v[0], v[2]] for ([k, v] in Iterator(config.dialogs))];
};
- completion.extension = function extension(context) {
- context.title = ["Extension"];
- context.anchored = false;
- context.keys = { text: "name", description: "description", icon: "iconURL" },
- context.generate = function () {
- context.incomplete = true;
- AddonManager.getAddonsByTypes(["extension"], function (addons) {
- context.incomplete = false;
- context.completions = addons;
- });
- };
- };
-
completion.help = function help(context, unchunked) {
dactyl.initHelp();
context.title = ["Help"];
diff --git a/common/modules/addons.jsm b/common/modules/addons.jsm
index 3d5fe593..9e0d04fb 100644
--- a/common/modules/addons.jsm
+++ b/common/modules/addons.jsm
@@ -437,18 +437,32 @@ var Addons = Module("addons", {
context.completions = types.map(function (t) [t, util.capitalize(t)]);
}
+ if (AddonManager.getAllAddons)
+ context.incomplete = true;
+
context.generate = function generate() {
update(base);
- if (AddonManager.getAllAddons) {
- context.incomplete = true;
+ if (AddonManager.getAllAddons)
AddonManager.getAllAddons(function (addons) {
context.incomplete = false;
update(array.uniq(base.concat(addons.map(function (a) a.type)),
true));
});
- }
}
}
+
+ completion.extension = function extension(context, types) {
+ context.title = ["Extension"];
+ context.anchored = false;
+ context.keys = { text: "name", description: "description", icon: "iconURL" },
+ context.incomplete = true;
+ context.generate = function () {
+ AddonManager.getAddonsByTypes(types || ["extension"], function (addons) {
+ context.incomplete = false;
+ context.completions = addons;
+ });
+ };
+ };
}
});
diff --git a/common/modules/completion.jsm b/common/modules/completion.jsm
index b2f038b5..e029e1b7 100644
--- a/common/modules/completion.jsm
+++ b/common/modules/completion.jsm
@@ -798,14 +798,14 @@ var CompletionContext = Class("CompletionContext", {
/**
* Wait for all subcontexts to complete.
*
- * @param {boolean} interruptible When true, the call may be interrupted
- * via <C-c>, in which case, "Interrupted" may be thrown.
* @param {number} timeout The maximum time, in milliseconds, to wait.
* If 0 or null, wait indefinitely.
+ * @param {boolean} interruptible When true, the call may be interrupted
+ * via <C-c>, in which case, "Interrupted" may be thrown.
*/
- wait: function wait(interruptable, timeout) {
- util.waitFor(function () !this.incomplete, this, timeout);
- return this.incomplete;
+ wait: function wait(timeout, interruptable) {
+ this.allItems;
+ return util.waitFor(function () !this.incomplete, this, timeout, interruptable);
}
}, {
Sort: {
@@ -852,7 +852,7 @@ var Completion = Module("completion", {
return { items: res.map(function (i) ({ item: i })) };
context.contexts["/run"].completions = res;
}
- context.wait(true);
+ context.wait(null, true);
return context.allItems;
},
@@ -866,7 +866,7 @@ var Completion = Module("completion", {
context.maxItems = maxItems;
context.fork.apply(context, ["list", 0, this, name].concat(Array.slice(arguments, 3)));
context = context.contexts["/list"];
- context.wait();
+ context.wait(null, true);
let contexts = context.contextList.filter(function (c) c.hasItems && c.items.length);
if (!contexts.length)
diff --git a/common/modules/util.jsm b/common/modules/util.jsm
index 73b53e19..3fc01164 100644
--- a/common/modules/util.jsm
+++ b/common/modules/util.jsm
@@ -1536,10 +1536,19 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
this.yielders--;
}
},
+
waitFor: function waitFor(test, self, timeout, interruptable) {
- let end = timeout && Date.now() + timeout;
- while ((!end || Date.now() < end) && !test.call(self))
- this.threadYield(false, interruptable);
+ let end = timeout && Date.now() + timeout, result;
+
+ let timer = services.Timer(function () {}, 10, services.Timer.TYPE_REPEATING_SLACK);
+ try {
+ while (!(result = test.call(self)) && (!end || Date.now() < end))
+ this.threadYield(false, interruptable);
+ }
+ finally {
+ timer.cancel();
+ }
+ return result;
},
yieldable: function yieldable(func)
diff --git a/common/tests/functional/testCommands.js b/common/tests/functional/testCommands.js
index 44e98a89..6b53e97f 100644
--- a/common/tests/functional/testCommands.js
+++ b/common/tests/functional/testCommands.js
@@ -19,6 +19,10 @@ var teardownModule = function (module) {
dactyl.teardown();
}
+function hasItems(context) context.allItems.items.length;
+function hasntNullItems(context) hasItems(context) &&
+ !context.allItems.items.some(function ({ text, description }) [text, description].some(function (text) /^\[object/.test(text)));
+
var tests = {
"!": {
multiOutput: ["echo foo"]
@@ -32,18 +36,27 @@ var tests = {
noOutput: [""]
},
addons: {
- multiOutput: ["", "dactyl", "-type=extension", "-type=extension dactyl"]
+ multiOutput: ["", "dactyl", "-type=extension", "-type=extension dactyl"],
+ completions: [
+ "",
+ ["-types=", hasItems]
+ ]
},
autocmd: {
multiOutput: ["", "DOMLoad", "DOMLoad foo"],
noOutput: ["DOMLoad foo bar", "-js DOMLoad foo bar"],
- completions: ["", "DOMLoad foo ", "-js DOMLoad foo "]
+ completions: [
+ ["", hasntNullItems],
+ "DOMLoad foo ",
+ "-js DOMLoad foo "
+ ]
},
back: { noOutput: [""] },
bdelete: {
init: ["tabopen about:pentadactyl", "tabopen about:pentadactyl"],
noOutput: [""],
- anyOutput: ["about:pentadactyl"]
+ anyOutput: ["about:pentadactyl"],
+ completions: [["", hasItems]]
},
bmark: {
someOutput: ["bmark", "bmark -tags=foo -titlt=bar -keyword=baz -charset=UTF-8 -post=quux about:pentadactyl"],
@@ -52,7 +65,7 @@ var tests = {
"-max=1 -keyword=",
"-max=1 -keyword=foo -tags=",
"-max=1 -keyword=foo -tags=bar -title=",
- "-max=1 -keyword=foo -tags=bar -title=baz -charset=",
+ ["-max=1 -keyword=foo -tags=bar -title=baz -charset=", hasItems],
"-max=1 -keyword=foo -tags=bar -title=baz -charset= about:"
]
},
@@ -68,7 +81,10 @@ var tests = {
buffer: {
anyOutput: ["", "1"],
noOutput: ["!", "! 1"],
- completions: ["", "1"]
+ completions: [
+ ["", hasItems],
+ ["1", hasItems]
+ ]
},
buffers: {
multiOutput: ["", "1"],
@@ -95,7 +111,10 @@ var tests = {
cookies: {
anyOutput: ["dactyl.sf.net", "dactyl.sf.net list"],
error: [""],
- completions: ["", "dactyl.sf.net "]
+ completions: [
+ "",
+ ["dactyl.sf.net ", hasItems]
+ ]
},
delbmarks: { anyOutput: ["", "about:pentadactyl"] },
delcommand: {
@@ -114,7 +133,9 @@ var tests = {
},
dialog: {
// Skip implementation for now
- completions: ["", "pre"]
+ completions: [
+ ["", hasntNullItems]
+ ]
},
doautoall: {}, // Skip for now
doautocmd: {}, // Skip for now
@@ -147,24 +168,34 @@ var tests = {
emenu: {
noOutput: ["View.Zoom.Zoom In", "View.Zoom.Zoom Out"],
error: [""],
- completions: ["", "View."]
+ completions: [
+ ["", hasItems],
+ ["View.", hasItems]
+ ]
},
endif: {}, // Skip for now
execute: {
noOutput: ["", "'js " + "".quote() + "'"],
- someOutput: ["'ls'"]
+ someOutput: ["'ls'"],
+ completions: [["", hasItems]]
},
extadd: {
- completions: [""],
+ completions: [["", hasItems]],
error: [""]
},
extdelete: {
- completions: [""],
+ completions: [["", hasItems]],
error: [""]
},
get extdisable() this.extdelete,
- get extenable() this.extdelete,
- get extoptions() this.extdelete,
+ extenable: {
+ completions: [""],
+ error: [""]
+ },
+ extoptions: {
+ completions: [""],
+ error: [""]
+ },
get extrehash() this.extdelete,
get exttoggle() this.extdelete,
get extupdate() this.extdelete,
@@ -179,7 +210,10 @@ var tests = {
help: {
noOutput: ["", "intro"],
cleanup: ["tabdelete", "tabdelete"],
- completions: ["", "'wild"]
+ completions: [
+ ["", hasItems],
+ ["'wild", hasItems]
+ ]
},
get helpall() this.help,
highlight: {
@@ -190,34 +224,35 @@ var tests = {
"Help -group=FontCode foo: bar;"
],
completions: [
- "",
- "Help",
- "Help ",
- "Help -group=",
- "Help -group=FontCode ",
- "Help foo: bar; -moz"
+ ["", hasItems],
+ ["Help", hasItems],
+ ["Help ", hasItems],
+ ["Help -group=", hasItems],
+ ["Help -group=FontCode ", hasItems],
+ ["Help foo: bar; -moz", hasItems]
]
},
history: {
+ init: ["open about:pentadactyl"],
anyOutput: ["-max=1", "-max=1 -sort=+date", "-max=1 dactyl"],
completions: [
- "",
- "dactyl",
- "-sort=+",
- "-sort=-",
- "-sort=+date ",
- "-sort=+date dactyl"
+ ["", hasItems],
+ "about:",
+ ["-sort=+", hasItems],
+ ["-sort=-", hasItems],
+ ["-sort=+date ", hasItems],
+ "-sort=+date about:"
]
},
if: {}, // Skip for now
javascript: {
noOutput: ["''", "'\\n'", "<pre>foo bar</pre>", "window"],
completions: [
- "",
- "window",
- "window.",
- "window['",
- "commands.get('"
+ ["", hasItems],
+ ["window", hasItems],
+ ["window.", hasItems],
+ ["window['", hasItems],
+ ["commands.get('", hasItems]
]
},
jumps: {
@@ -231,7 +266,10 @@ var tests = {
let: {}, // Deprecated. Fuck it.
listcommands: {
anyOutput: ["", "in"],
- completions: ["", "in "]
+ completions: [
+ ["", hasItems],
+ "in "
+ ]
},
get listkeys() this.listcommands,
get listoptions() this.listcommands,
@@ -256,14 +294,14 @@ var tests = {
"-gtroup=some-nonexistent-group <C-a> <C-a>"
],
completeions: [
- "",
- "-",
- "-mode=ex ",
- "-mode=",
- "-group=",
- "-builtin i ",
- "-ex i ",
- "-javascript i ",
+ ["", hasItems],
+ ["-", hasItems],
+ ["-mode=ex ", hasItems],
+ ["-mode=", hasItems],
+ ["-group=", hasItems],
+ ["-builtin i ", hasItems],
+ ["-ex i ", hasItems],
+ ["-javascript i ", hasItems]
]
},
mapclear: {
@@ -326,7 +364,9 @@ var tests = {
"some-nonexistent-pentadactyl-dir/",
"some-nonexistent-pentadactyl-dir/foo.vim"
],
- completeions: [""],
+ completeions: [
+ ["", hasItems]
+ ],
cleanup: ["silent !rm -r some-nonexistent-pentadactyl-dir/"]
},
normal: {
@@ -337,20 +377,20 @@ var tests = {
open: {
noOutput: ["about:blank | about:home"],
completions: [
- "",
- "./",
- "./ | ",
- "chrome://",
- "chrome://browser/",
- "chrome://browser/content/",
- "about:",
- "resource://",
- "resource://dactyl/"
+ ["", hasItems],
+ ["./", hasItems],
+ ["./ | ", hasItems],
+ ["chrome://", hasItems],
+ ["chrome://browser/", hasItems],
+ ["chrome://browser/content/", hasItems],
+ ["about:", hasItems],
+ ["resource://", hasItems],
+ ["resource://dactyl/", hasItems]
]
},
pageinfo: {
multiOutput: ["", "fgm"],
- completions: [""],
+ completions: [["", hasItems]],
error: ["abcdefghijklmnopqrstuvwxyz", "f g m"]
},
pagestyle: {
@@ -366,7 +406,10 @@ var tests = {
"m foo bar"
],
error: ["", "#"],
- completions: ["", "m "]
+ completions: [
+ ["", hasItems], // Fails. Why?
+ ["m ", hasItems]
+ ]
},
qmarks: [
{
@@ -376,7 +419,7 @@ var tests = {
{
init: ["qmark x"],
multiOutput: ["", "m", "x"],
- completions: [""]
+ completions: [["", hasItems]]
}
],
quit: {}, // Skip for now
@@ -446,7 +489,10 @@ var tests = {
// "!" Previous sidebar isn't saved until the window loads.
// We don't give it enough time.
],
- completions: ["", "! "]
+ completions: [
+ ["", hasntNullItems],
+ "! "
+ ]
},
silent: {
noOutput: [
@@ -455,7 +501,7 @@ var tests = {
"echoerr 'foo'",
"echoerr " + "foo\nbar".quote()
],
- completions: [""]
+ completions: [["", hasItems]]
},
source: {},
stop: {},
@@ -508,7 +554,7 @@ function runCommands(cmdName, testName, commands, test, forbidErrors) {
commands.forEach(function (val) {
var [cmd, testVal] = Array.concat(val);
- // dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
+ dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
dactyl.clearMessage();
dactyl.closeMessageWindow();
@@ -529,7 +575,7 @@ function _runCommands(cmdName, testName, commands) {
commands.forEach(function (value) {
var [cmd, test] = Array.concat(value);
- // dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
+ dump("CMD: " + testName + " " + cmdName + " " + cmd + "\n");
var res = dactyl.runExCommand(cmd);
controller.waitForPageLoad(controller.tabs.activeTab);
if (test)
@@ -602,12 +648,21 @@ for (var val in Iterator(tests)) (function ([command, paramsList]) {
addTest(command, testName, function () {
commands.forEach(function (val) {
var [cmd, test] = Array.concat(val);
+ cmd = command + cmd.replace(/^(!?) ?/, "$1 ");
dactyl.assertNoErrorMessages(function () {
- dactyl.runExCompletion(command + cmd.replace(/^(!?) ?/, "$1 "));
- if (test)
- jumlib.assert(test(dactyl.modules.commandline.commandSession.completions.context),
- "Initializing for " + cmdName + " tests failed: " + cmd.quote() + " " + test);
+ dump("COMPL: " + cmd + "\n");
+ dactyl.runExCompletion(cmd);
+ if (test) {
+ /* Freezes. :(
+ var context = dactyl.modules.commandline.commandSession.completions.context;
+ */
+ var context = dactyl.modules.CompletionContext(cmd);
+ context.tabPressed = true;
+ context.fork("ex", 0, dactyl.modules.completion, "ex");
+ jumlib.assert(context.wait(5000), "Completion failed: " + cmd.quote());
+ jumlib.assert(test(context), "Completion tests failed: " + cmd.quote() + " " + test);
+ }
});
});
});
diff --git a/pentadactyl/content/config.js b/pentadactyl/content/config.js
index 89ace4cf..75e13d4c 100644
--- a/pentadactyl/content/config.js
+++ b/pentadactyl/content/config.js
@@ -281,11 +281,16 @@ var Config = Module("config", ConfigBase, {
const { CompletionContext, bookmarkcache, bookmarks, completion } = modules;
const { document } = window;
- var searchRunning = false; // only until Firefox fixes https://bugzilla.mozilla.org/show_bug.cgi?id=510589
+ var searchRunning = null; // only until Firefox fixes https://bugzilla.mozilla.org/show_bug.cgi?id=510589
completion.location = function location(context) {
if (!services.autoCompleteSearch)
return;
+ if (searchRunning) {
+ searchRunning.completions = searchRunning.completions;
+ searchRunning.cancel();
+ }
+
context.anchored = false;
context.compare = CompletionContext.Sort.unsorted;
context.filterFunc = null;
@@ -297,30 +302,27 @@ var Config = Module("config", ConfigBase, {
context.title = ["Smart Completions"];
context.cancel = function () {
- if (searchRunning) {
+ this.incomplete = false;
+ if (searchRunning === this) {
services.autoCompleteSearch.stopSearch();
- searchRunning = false;
+ searchRunning = null;
}
};
- if (searchRunning)
- services.autoCompleteSearch.stopSearch();
- let timer = new Timer(50, 100, function (result) {
- context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
- context.completions = [
- { url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
- for (i in util.range(0, result.matchCount))
- ];
- });
+
services.autoCompleteSearch.startSearch(context.filter, "", context.result, {
onSearchResult: function onSearchResult(search, result) {
- timer.tell(result);
- if (result.searchResult <= result.RESULT_SUCCESS) {
- searchRunning = false;
- timer.flush();
- }
- }
+ if (result.searchResult <= result.RESULT_SUCCESS)
+ searchRunning = null;
+
+ context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING;
+ context.completions = [
+ { url: result.getValueAt(i), title: result.getCommentAt(i), icon: result.getImageAt(i) }
+ for (i in util.range(0, result.matchCount))
+ ];
+ },
+ get onUpdateSearchResult() this.onSearchResult
});
- searchRunning = true;
+ searchRunning = context;
};
completion.sidebar = function sidebar(context) {