diff --git a/TODO b/TODO
index 8dd54326..d79e120d 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,5 @@
-
Priority list:
-1-9 as in Vim (9=required for next release, 5=would be nice, 1=probably not)
+1-9 as in Vim (9 = required for next release, 5 = would be nice, 1 = probably not)
BUGS:
- add window resize support to hints
@@ -23,6 +22,7 @@ BUGS:
- :set! browser.urlbar.clickSelectsAll=true -> clicking in the location bar unfocuses it immediately
- http://apcmag.com/why_os_x_106_snow_leopard_should_leave_powerpc_in_the_cold.htm - scrolls the wrong
window with j/k (the green slashdot thing for me).
+- http://cgiirc.blitzed.org?chan=%23debug is unusable after login in
(recent CVS regressions):
- A cached "awesomebar completion" result is still displayed, after the user removes "l" from the 'cpt' and
@@ -34,6 +34,7 @@ BUGS:
:b a changes the (Untitled) title to "about:blank"
- visual caret mode is broken
- Tabbing between form elems triggers NORMAL mode
+- :bmarks, :hs output and 'cpt'=bh completions are broken
FEATURES:
9 adaptive timeout for auto-completions, :set completions can be updated more often than
@@ -87,4 +88,3 @@ FEATURES:
RANDOM IDEAS:
* hide scrollbars: (window.content.document.body.style.overflow = "hidden" has problems with the mouse wheel)
-
diff --git a/content/completion.js b/content/completion.js
index 95512bed..7c40c5e8 100644
--- a/content/completion.js
+++ b/content/completion.js
@@ -58,6 +58,11 @@ function Completion() //{{{
var completionCache = [];
var historyTimer = new util.Timer(50, 100, function histTimer() {
+ // don't set all completions again every time the timer fires, even
+ // though items might not have changed
+ if (historyCache.length == historyResult.matchCount)
+ return;
+
let comp = [];
for (let i in util.range(0, historyResult.matchCount))
comp.push([historyResult.getValueAt(i),
@@ -66,8 +71,9 @@ function Completion() //{{{
//let foo = ["", "IGNORED", "FAILURE", "NOMATCH", "SUCCESS", "NOMATCH_ONGOING", "SUCCESS_ONGOING"];
+ // TODO: we need to have a "completionCacheAfter" to allow cpt=slf
historyCache = comp;
- commandline.setCompletions({ get completions() { return completionCache.concat(historyCache); } });
+ commandline.setCompletions({ get items() { return completionCache.concat(historyCache); } });
});
function Javascript()
@@ -807,7 +813,7 @@ function Completion() //{{{
{
return {
start: 0,
- get completions() { return bookmarks.get(filter) },
+ get items() { return bookmarks.get(filter) },
createRow: function (item)

@@ -943,7 +949,7 @@ function Completion() //{{{
var [count, cmd, special, args] = commands.parseCommand(str);
var matches = str.match(/^(:*\d*)\w*$/);
if (matches)
- return { start: matches[1].length, completions: this.command(cmd)[1] };
+ return { start: matches[1].length, items: this.command(cmd)[1] };
// dynamically get completions as specified with the command's completer function
var compObject = { start: 0, completions: [] };
@@ -955,7 +961,7 @@ function Completion() //{{{
exLength = matches ? matches[0].length : 0;
compObject = command.completer.call(this, args, special);
if (compObject instanceof Array) // for now at least, let completion functions return arrays instead of objects
- compObject = { start: compObject[0], completions: compObject[1] };
+ compObject = { start: compObject[0], items: compObject[1] };
}
compObject.start += exLength;
return compObject;
@@ -1198,8 +1204,41 @@ function Completion() //{{{
// if the 'complete' argument is passed like "h", it temporarily overrides the complete option
url: function url(filter, complete)
{
+ function getMoreItems(count, maxTime)
+ {
+ maxTime = maxTime || 5000; // maximum time to wait, default 5 sec
+ count = count || 10;
+
+ var completions = [];
+ historyResult = null;
+ let then = new Date().getTime();
+ for (let now = then; now - then < maxTime; now = new Date().getTime())
+ {
+ liberator.threadYield();
+ if (!historyResult)
+ continue;
+
+ if (historyResult.searchResult == historyResult.RESULT_SUCCESS ||
+ historyResult.searchResult == historyResult.RESULT_NOMATCH ||
+ (historyResult.searchResult == historyResult.RESULT_SUCCESS_ONGOING &&
+ historyResult.matchCount >= count + numLocationCompletions))
+ {
+ //liberator.dump("Got " + historyResult.matchCount + " more results after " + (now - then) + " ms with result: " + historyResult.searchResult);
+ //completionService.stopSearch();
+ for (let i in util.range(numLocationCompletions, historyResult.matchCount))
+ completions.push([historyResult.getValueAt(i),
+ historyResult.getCommentAt(i),
+ historyResult.getImageAt(i)]);
+ numLocationCompletions = historyResult.matchCount;
+ break;
+ }
+ }
+ return completions;
+ }
+
this.filterString = filter;
var completions = [];
+ var numLocationCompletions = 0; // how many async completions did we already return to the caller?
var start = 0;
var skip = filter.match("^(.*" + options["urlseparator"] + ")(.*)"); // start after the last 'urlseparator'
if (skip)
@@ -1214,32 +1253,34 @@ function Completion() //{{{
for (let c in util.Array.iterator(cpt))
{
if (c == "s")
- completions.push(this.search(filter)[1]);
+ completions = completions.concat(this.search(filter)[1]);
else if (c == "f")
- completions.push(this.file(filter, false)[1]);
+ completions = completions.concat(this.file(filter, false)[1]);
else if (c == "S")
- completions.push(this.searchEngineSuggest(filter, suggestEngineAlias)[1]);
+ completions = completions.concat(this.searchEngineSuggest(filter, suggestEngineAlias)[1]);
else if (c == "b")
- completions.push(bookmarks.get(filter));
+ completions = completions.concat(bookmarks.get(filter));
else if (c == "h")
- completions.push(history.get(filter));
+ completions = completions.concat(history.get(filter));
else if (c == "l" && completionService) // add completions like Firefox's smart location bar
{
+ historyCache = [];
+ completionCache = completions.slice(); // make copy of current results
completionService.stopSearch();
- //dump("searching for " + filter + "\n");
completionService.startSearch(filter, "", historyResult, {
onSearchResult: function onSearchResult(search, result) {
historyResult = result;
+ //liberator.dump("Search result in " + historyResult.matchCount + " results with retval: " + historyResult.searchResult);
historyTimer.tell();
if (result.searchResult <= result.RESULT_SUCCESS)
historyTimer.flush();
}
});
+
}
}
- completionCache = util.Array.flatten(completions);
- return [start, completionCache.concat(historyCache)];
+ return { start: start, items: completions, getMoreItems: getMoreItems };
},
userCommand: function userCommand(filter)
diff --git a/content/ui.js b/content/ui.js
index 00c79822..c755865a 100644
--- a/content/ui.js
+++ b/content/ui.js
@@ -97,9 +97,8 @@ function CommandLine() //{{{
var silent = false;
var completionList = new ItemList("liberator-completions");
- var completions = [];
+ var completions = { start: 0, items: [] };
// for the example command "open sometext| othertext" (| is the cursor pos):
- var completionStartIndex = 0; // will be 5 because we want to complete arguments for the :open command
var completionPrefix = ""; // will be: "open sometext"
var completionPostfix = ""; // will be: " othertext"
var completionIndex = UNINITIALIZED;
@@ -108,10 +107,10 @@ function CommandLine() //{{{
var startHints = false; // whether we're waiting to start hints mode
var statusTimer = new util.Timer(5, 100, function () {
- if (completionIndex >= completions.length)
+ if (completionIndex >= completions.items.length)
statusline.updateProgress("");
else
- statusline.updateProgress("match " + (completionIndex + 1) + " of " + completions.length);
+ statusline.updateProgress("match " + (completionIndex + 1) + " of " + completions.items.length);
});
var autocompleteTimer = new util.Timer(201, 300, function (command) {
if (events.feedingKeys)
@@ -543,8 +542,6 @@ function CommandLine() //{{{
// FORCE_MULTILINE is given, FORCE_MULTILINE takes precedence
APPEND_TO_MESSAGES : 1 << 3, // add the string to the message history
- get autocompleteTimer() autocompleteTimer,
-
get mode() (modes.extended == modes.EX) ? "cmd" : "search",
get silent() silent,
@@ -581,9 +578,9 @@ function CommandLine() //{{{
// open the completion list automatically if wanted
if (/\s/.test(cmd) &&
- options.get("wildoptions").has("auto") >= 0 &&
+ options.get("wildoptions").has("auto") &&
extendedMode == modes.EX)
- autocompleteTimer.tell(cmd);
+ autocompleteTimer.tell(cmd);
},
// normally used when pressing esc, does not execute a command
@@ -599,9 +596,7 @@ function CommandLine() //{{{
{
multilineInputWidget.collapsed = true;
outputContainer.collapsed = true;
- autocompleteTimer.reset();
completionList.hide();
- completions = [];
this.resetCompletions();
setLine("", this.HL_NORMAL);
@@ -731,7 +726,7 @@ function CommandLine() //{{{
currentExtendedMode = null; /* Don't let modes.pop trigger "cancel" */
inputHistory.add(command);
modes.pop(!commandline.silent);
- autocompleteTimer.reset();
+ this.resetCompletions();
completionList.hide();
liberator.focusContent(false);
statusline.updateProgress(""); // we may have a "match x of y" visible
@@ -827,31 +822,37 @@ function CommandLine() //{{{
// we need to build our completion list first
if (completionIndex == UNINITIALIZED)
{
- completionStartIndex = 0;
completionIndex = -1;
completionPrefix = command.substring(0, commandWidget.selectionStart);
completionPostfix = command.substring(commandWidget.selectionStart);
- var compObject = liberator.triggerCallback("complete", currentExtendedMode, completionPrefix);
- if (compObject)
- {
- completionStartIndex = compObject.start;
- completions = compObject.completions;
- }
+ completions = liberator.triggerCallback("complete", currentExtendedMode, completionPrefix);
// sort the completion list
+ // TODO: might not make sense anymore with our advanced completions, we should just sort when necessary
if (options.get("wildoptions").has("sort"))
- compObject.completions.sort(function (a, b) String.localeCompare(a[0], b[0]));
+ completions.items.sort(function (a, b) String.localeCompare(a[0], b[0]));
- completionList.setItems(compObject);
+ completionList.setItems(completions.items);
}
- if (completions.length == 0)
+ if (completions.items.length == 0)
{
- liberator.beep();
- // prevent tab from moving to the next field:
- event.preventDefault();
- event.stopPropagation();
- return false;
+ // try to fetch more items, if possible
+ // TODO: also use that code when we DO have completions but too few
+ if (completions.getMoreItems)
+ {
+ completions.items = completions.items.concat(completions.getMoreItems(1));
+ completionList.setItems(completions.items);
+ }
+
+ if (completions.items.length == 0) // still not more matches
+ {
+ liberator.beep();
+ // prevent tab from moving to the next field:
+ event.preventDefault();
+ event.stopPropagation();
+ return false;
+ }
}
if (full)
@@ -860,12 +861,12 @@ function CommandLine() //{{{
{
completionIndex--;
if (completionIndex < -1)
- completionIndex = completions.length - 1;
+ completionIndex = completions.items.length - 1;
}
else
{
completionIndex++;
- if (completionIndex > completions.length)
+ if (completionIndex > completions.items.length)
completionIndex = 0;
}
@@ -877,30 +878,31 @@ function CommandLine() //{{{
if (hasList)
completionList.show();
- if ((completionIndex == -1 || completionIndex >= completions.length) && !longest) // wrapped around matches, reset command line
+ if ((completionIndex == -1 || completionIndex >= completions.items.length) && !longest) // wrapped around matches, reset command line
{
- if (full && completions.length > 1)
+ if (full)
setCommand(completionPrefix + completionPostfix);
}
else
{
var compl = null;
- if (longest && completions.length > 1)
+ if (longest && completions.items.length > 1)
compl = completion.getLongestSubstring();
else if (full)
- compl = completions[completionIndex][0];
- else if (completions.length == 1)
- compl = completions[0][0];
+ compl = completions.items[completionIndex][0];
+ else if (completions.items.length == 1)
+ compl = completion.items[0][0];
if (compl)
{
- setCommand(command.substring(0, completionStartIndex) + compl + completionPostfix);
- commandWidget.selectionStart = commandWidget.selectionEnd = completionStartIndex + compl.length;
+ setCommand(command.substring(0, completions.start) + compl + completionPostfix);
+ commandWidget.selectionStart = commandWidget.selectionEnd = completions.start + compl.length;
if (longest)
liberator.triggerCallback("change", currentExtendedMode, this.getCommand());
// Start a new completion in the next iteration. Useful for commands like :source
// RFC: perhaps the command can indicate whether the completion should be restarted
+ // -> should be doable now, since the completion items are objects
// Needed for :source to grab another set of completions after a file/directory has been filled out
// if (completions.length == 1 && !full)
// completionIndex = UNINITIALIZED;
@@ -1220,7 +1222,7 @@ function CommandLine() //{{{
},
// to allow asynchronous adding of completions
- setCompletions: function (completionObject)
+ setCompletions: function (newCompletions)
{
if (liberator.mode != modes.COMMAND_LINE)
return;
@@ -1230,32 +1232,41 @@ function CommandLine() //{{{
return completionList.hide();
*/
- let newCompletions = completionObject.completions;
- completionList.setItems(completionObject);
+ completionList.setItems(newCompletions.items);
- if (completionIndex >= 0 && completionIndex < newCompletions.length && completionIndex < completions.length)
+ // try to keep the old item selected
+ if (completionIndex >= 0 && completionIndex < newCompletions.items.length && completionIndex < completions.items.length)
{
- if (newCompletions[completionIndex][0] != completions[completionIndex][0])
+ if (newCompletions.items[completionIndex][0] != completions.items[completionIndex][0])
completionIndex = -1;
}
else
completionIndex = -1;
+ let oldStart = completions.start;
completions = newCompletions;
+ if (typeof completions.start != "number")
+ completions.start = oldStart;
+
completionList.selectItem(completionIndex);
if (options.get("wildoptions").has("auto"))
completionList.show();
+ // why do we have to set that here? Without that, we lose the
+ // prefix when wrapping around searches
+ // with that, we SOMETIMES have problems with followed by in :open completions
var command = this.getCommand();
completionPrefix = command.substring(0, commandWidget.selectionStart);
completionPostfix = command.substring(commandWidget.selectionStart);
- if (typeof completionObject.start == "number")
- completionStartIndex = completionObject.start;
},
+ // TODO: does that function need to be public?
resetCompletions: function ()
{
+ autocompleteTimer.reset();
+ completion.cancel();
+ completions = { start: 0, items: [] };
completionIndex = historyIndex = UNINITIALIZED;
wildIndex = 0;
}
@@ -1269,8 +1280,6 @@ function CommandLine() //{{{
* @param id: the id of the the XUL