From 473c461d3fc950bb793739c7834c31139bf1bdc2 Mon Sep 17 00:00:00 2001 From: Martin Stubenschrott Date: Wed, 7 Jan 2009 03:04:42 +0100 Subject: [PATCH] fixed :open completions for slow computers. We now yield incremental results, and the user gets more completion, the more often he presses tab. Need to find out, how to change the "Waiting..." message to "More results...". Also reminds me, how ugly the completion context code is partly. We should try to clean it up and remove/merge useless function to make it's interface smaller and more side-effect free. --- common/content/completion.js | 37 ++++++++++++++++++++++--------- common/content/liberator.js | 1 + common/content/ui.js | 43 +++++++++++++++++++++++------------- 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/common/content/completion.js b/common/content/completion.js index c27734fc..058ef027 100644 --- a/common/content/completion.js +++ b/common/content/completion.js @@ -528,7 +528,9 @@ CompletionContext.prototype = { cancelAll: function () { - for (let [,context] in Iterator(this.contextList)) + // Kris: contextList gives undefined. And why do we have contexts and contextList? + // I am not too much of a fan of a huge API for classes + for (let [,context] in Iterator(this.top.contexts)) { if (context.cancel) context.cancel(); @@ -1576,6 +1578,7 @@ function Completion() //{{{ context.filterFunc = null; context.cancel = function () services.get("autoCompleteSearch").stopSearch(); context.compare = null; + // TODO: shouldn't this timer be deleted by context.cancel? let timer = new Timer(50, 100, function (result) { context.incomplete = result.searchResult >= result.RESULT_NOMATCH_ONGOING; context.completions = [ @@ -1583,16 +1586,28 @@ function Completion() //{{{ for (i in util.range(0, result.matchCount)) ]; }); - services.get("autoCompleteSearch").stopSearch(); - services.get("autoCompleteSearch").startSearch(context.filter, "", context.result, { - onSearchResult: function onSearchResult(search, result) - { - context.result = result; - timer.tell(result); - if (result.searchResult <= result.RESULT_SUCCESS) - timer.flush(); - } - }); + context.generate = function () { + let minItems = context.minItems || 1; + services.get("autoCompleteSearch").stopSearch(); + services.get("autoCompleteSearch").startSearch(context.filter, "", context.result, { + onSearchResult: function (search, result) + { + context.result = result; + timer.tell(result); + if (result.searchResult <= result.RESULT_SUCCESS) + timer.flush(); + } + }); + + let end = Date.now() + 5000; + while (context.incomplete && context.completions.length < minItems && Date.now() < end) + liberator.threadYield(false, true); + + // context.message = "More results..."; // very very strange, if I enable this line, completions don't work; + services.get("autoCompleteSearch").stopSearch(); + + return context.completions; + } }, macro: function macro(context) diff --git a/common/content/liberator.js b/common/content/liberator.js index dd5d396c..e7085102 100644 --- a/common/content/liberator.js +++ b/common/content/liberator.js @@ -1362,6 +1362,7 @@ const liberator = (function () //{{{ callback.call(self); }, + // TODO: interruptable not used? threadYield: function (flush, interruptable) { let mainThread = services.get("threadManager").mainThread; diff --git a/common/content/ui.js b/common/content/ui.js index 0943f691..f45f5cfb 100644 --- a/common/content/ui.js +++ b/common/content/ui.js @@ -336,7 +336,7 @@ function CommandLine() //{{{ else idx = this.selected + 1; break; - case this.RESET: + case this.RESET: // TODO: never used for now idx = null; break; default: @@ -360,22 +360,37 @@ function CommandLine() //{{{ tab: function tab(reverse) { autocompleteTimer.flush(); + // Check if we need to run the completer. + let numElementsNeeded; + if (this.selected == null) + numElementsNeeded = reverse ? 100000 : 1; // better way to specify give me all items than setting to a very large number? + else + numElementsNeeded = reverse ? this.selected : this.selected + 2; // this.selected is zero-based + 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(); + this.complete(true, true); } + else if (this.context.incomplete && numElementsNeeded > this.items.length) + { + for (let [, context] in Iterator(this.context.contexts)) + { + if (context.incomplete && context.generate) + { + // regenerate twice as many items as needed, as regenerating + // to often looks visually bad + context.minItems = numElementsNeeded * 2; // TODO: document minItems, or find a better way + context.regenerate = true; + context._generate(); // HACK + } + if (this.items.length >= numElementsNeeded) + break; + } + } + + if (this.items.length == 0) + return liberator.beep(); switch (this.wildtype.replace(/.*:/, "")) { @@ -1435,11 +1450,9 @@ function CommandLine() //{{{ { autocompleteTimer.reset(); - // liberator.dump("Resetting completions..."); if (completions) { completions.context.cancelAll(); - completions.wildIndex = -1; completions.previewClear(); }