diff --git a/content/bookmarks.js b/content/bookmarks.js
index 378a05c9..7ba391eb 100644
--- a/content/bookmarks.js
+++ b/content/bookmarks.js
@@ -301,9 +301,7 @@ function Bookmarks() //{{{
if (bookmarks.add(false, title, url, keyword, tags, special))
{
- var extra = "";
- if (title != url)
- extra = " (" + title + ")";
+ let extra = (title == url) ? "" : " (" + title + ")";
liberator.echo("Added bookmark: " + url + extra, commandline.FORCE_SINGLELINE);
}
else
@@ -561,26 +559,21 @@ function Bookmarks() //{{{
// if openItems is true, open the matching bookmarks items in tabs rather than display
list: function (filter, tags, openItems)
{
- var items = this.get(filter, tags, false);
- if (items.length == 0)
- {
- if (filter.length > 0 && tags.length > 0)
- liberator.echoerr("E283: No bookmarks matching tags: \"" + tags + "\" and string: \"" + filter + "\"");
- else if (filter.length > 0)
- liberator.echoerr("E283: No bookmarks matching string: \"" + filter + "\"");
- else if (tags.length > 0)
- liberator.echoerr("E283: No bookmarks matching tags: \"" + tags + "\"");
- else
- liberator.echoerr("No bookmarks set");
+ if (!openItems)
+ return template.listCompleter("bookmark", filter, tags);
- return;
- }
+ let items = this.get(filter, tags, false);
+ if (items.length)
+ return liberator.open(items.map(function (i) i.url), liberator.NEW_TAB);
- if (openItems)
- return liberator.open([i.url for each (i in items)], liberator.NEW_TAB);
-
- let list = template.genericTable(items, this.format);
- commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
+ if (filter.length > 0 && tags.length > 0)
+ liberator.echoerr("E283: No bookmarks matching tags: \"" + tags + "\" and string: \"" + filter + "\"");
+ else if (filter.length > 0)
+ liberator.echoerr("E283: No bookmarks matching string: \"" + filter + "\"");
+ else if (tags.length > 0)
+ liberator.echoerr("E283: No bookmarks matching tags: \"" + tags + "\"");
+ else
+ liberator.echoerr("No bookmarks set");
}
};
//}}}
@@ -808,22 +801,17 @@ function History() //{{{
// if openItems is true, open the matching history items in tabs rather than display
list: function (filter, openItems)
{
- var items = this.get(filter, 1000);
- if (items.length == 0)
- {
- if (filter.length > 0)
- liberator.echoerr("E283: No history matching \"" + filter + "\"");
- else
- liberator.echoerr("No history set");
+ if (!openItems)
+ return template.listCompleter("history", filter);
- return;
- }
-
- if (openItems)
+ var items = this.get({ searchTerms: filter }, 1000);
+ if (items.length)
return liberator.open([i[0] for each (i in items)], liberator.NEW_TAB);
- let list = template.genericTable(items, this.format);
- commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
+ if (filter.length > 0)
+ liberator.echoerr("E283: No history matching \"" + filter + "\"");
+ else
+ liberator.echoerr("No history set");
}
};
//}}}
@@ -942,6 +930,7 @@ function QuickMarks() //{{{
add: function (qmark, location)
{
qmarks.set(qmark, location);
+ liberator.echo("Added Quick Mark '" + qmark + "': " + location);
},
remove: function (filter)
@@ -997,9 +986,7 @@ function QuickMarks() //{{{
}
let items = [[mark, qmarks.get(mark)] for ([k, mark] in Iterator(marks))];
-
- let list = template.genericTable(items, { title: ["QuickMark", "URL"] });
- commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
+ template.genericTable(items, { title: ["QuickMark", "URL"] });
}
};
//}}}
diff --git a/content/commands.js b/content/commands.js
index aed1458e..e45ccc06 100644
--- a/content/commands.js
+++ b/content/commands.js
@@ -818,7 +818,8 @@ function Commands() //{{{
cmd.argCount,
cmd.count ? "0c" : "",
completerToString(cmd.completer),
- cmd.replacementText || "function () { ... }"] for each (cmd in cmds)));
+ cmd.replacementText || "function () { ... }"]
+ for each (cmd in cmds)));
commandline.echo(str, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
}
diff --git a/content/completion.js b/content/completion.js
index b10bf064..bc97cec1 100644
--- a/content/completion.js
+++ b/content/completion.js
@@ -149,7 +149,7 @@ CompletionContext.prototype = {
this.incomplete = true;
liberator.callFunctionInThread(null, function () {
let items = self.generate();
- if (self.backgroundLock != lock)
+ if (self.cache.backgroundLock != lock)
return;
self.incomplete = false;
self.completions = items;
@@ -244,12 +244,14 @@ CompletionContext.prototype = {
function (i) cache[i] = cache[i] || util.xmlToDom(self.createRow(items[i]), doc));
},
- fork: function fork(name, offset, completer, self)
+ fork: function fork(name, offset, self, completer)
{
+ if (typeof completer == "string")
+ completer = self[completer]
let context = new CompletionContext(this, name, offset);
this.contextList.push(context);
if (completer)
- return completer.apply(self, [context].concat(Array.slice(arguments, 4)));
+ return completer.apply(self || this, [context].concat(Array.slice(arguments, 4)));
return context;
},
@@ -683,13 +685,13 @@ function Completion() //{{{
for (let [,obj] in Iterator(objects))
{
obj[3] = compl || this.objectKeys(obj);
- this.context.fork(obj[1], top[OFFSET], this.filter, this,
+ this.context.fork(obj[1], top[OFFSET], this, "filter",
obj[3], obj[1], true, key + (string || ""), last, key.length);
}
for (let [,obj] in Iterator(objects))
{
obj[1] += " (substrings)";
- this.context.fork(obj[1], top[OFFSET], this.filter, this,
+ this.context.fork(obj[1], top[OFFSET], this, "filter",
obj[3], obj[1], false, key + (string || ""), last, key.length);
}
}
@@ -1063,15 +1065,19 @@ function Completion() //{{{
}
},
- buffer: function buffer(filter)
+ buffer: function buffer(context)
{
- // FIXME: liberator.has("tabs")
- let items = [];
- let xml =
- filter = (filter || "").toLowerCase();
+ filter = context.filter.toLowerCase();
+ context.title = ["Buffer", "URL"];
+ context.keys = { text: "text", description: "url", icon: "icon" };
+ let process = context.process[0];
+ context.process = [function ({ text: text, item: item }) <>
+ {item.i}
+ {item.indicator}
+ { process.call(this, { item: item, text: text }) }
+ >];
- for (let [i, browser] in tabs.browsers)
- {
+ context.completions = util.map(tabs.browsers, function ([i, browser]) {
if (i == tabs.index())
indicator = "%"
else if (i == tabs.index(tabs.alternate))
@@ -1079,43 +1085,18 @@ function Completion() //{{{
else
indicator = " ";
+ let tab = tabs.getTab(i);
i = i + 1;
- let title = "";
- try
- {
- title = browser.contentDocument.title;
- }
- catch (e) {}
-
let url = browser.contentDocument.location.href;
- if (title.indexOf(filter) != -1 || url.indexOf(filter) != -1 ||
- String.indexOf(i, filter) != -1)
- {
- if (title == "")
- title = "(Untitled)";
-
- items.push([[i + ": " + title, i + ": " + url], url]);
-
- let icon = "";
- if (liberator.has("bookmarks"))
- icon = bookmarks.getFavicon(url);
-
- xml.* +=
-
- - {i}
- - {indicator}
- - {icon ?
: <>>}
- - {title}
- - {url}
-
;
- }
- }
-
- if (!filter)
- return [0, items.map(function ([a, b]) [a[0], b]), xml];
-
- return [0, buildLongestCommonSubstring(items, filter), xml];
+ return {
+ text: [i + ": " + (tab.label || "(Untitled)"), i + ": " + url],
+ url: url,
+ indicator: indicator,
+ i: i,
+ icon: tab.image
+ };
+ });
},
colorScheme: function colorScheme(filter)
@@ -1174,7 +1155,7 @@ function Completion() //{{{
let [, prefix, junk] = context.filter.match(/^(:*\d*)\w*(.?)/) || [];
context.advance(prefix.length)
if (!junk)
- return context.fork("", 0, this.command);
+ return context.fork("", 0, this, "command");
// dynamically get completions as specified with the command's completer function
let command = commands.get(cmd);
@@ -1239,7 +1220,7 @@ function Completion() //{{{
function (file) [(tail ? file.leafName : dir + file.leafName).replace(" ", "\\ ", "g"),
file.isDirectory() ? "Directory" : "File",
file.isDirectory() ? "resource://gre/res/html/folder.png"
- : "moz-icon://" + makeFileURI(file).path]
+ : "moz-icon://" + file.leafName]
);
}
catch (e) {}
@@ -1337,12 +1318,12 @@ function Completion() //{{{
if (!space)
return;
- context.fork("suggest", keyword.length + space.length, this.searchEngineSuggest, this,
+ context.fork("suggest", keyword.length + space.length, this, "searchEngineSuggest",
keyword, true);
let item = keywords.filter(function (k) k.keyword == keyword)[0];
if (item && item.url.indexOf("%s") > -1)
- context.fork("keyword/" + keyword, keyword.length + space.length, function (context) {
+ context.fork("keyword/" + keyword, keyword.length + space.length, null, function (context) {
context.format = history.format;
context.title = [keyword + " Quick Search"];
context.background = true;
@@ -1458,7 +1439,7 @@ function Completion() //{{{
// Will, and should, throw an error if !(c in opts)
Array.forEach(complete || options["complete"],
- function (c) context.fork(c, 0, completion.urlCompleters[c].completer, completion));
+ function (c) context.fork(c, 0, completion, completion.urlCompleters[c].completer));
},
urlCompleters: {},
diff --git a/content/editor.js b/content/editor.js
index 6b310bd9..3947f226 100644
--- a/content/editor.js
+++ b/content/editor.js
@@ -928,22 +928,12 @@ function Editor() //{{{
var searchFilter = (filter == "!") ? "!ci"
: filter + "!"; // ! -> list all, on c or i ! matches too)
- let list =
-
- {
- template.map(abbrevs(), function ([lhs, rhs])
- searchFilter.indexOf(rhs[0]) < 0 ? undefined :
-
- | {rhs[0]} |
- {lhs} |
- {rhs[1]} |
-
)
- }
-
;
- if (list.*.length())
- commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
- else
- liberator.echoerr("No abbreviations found");
+ let list = [[rhs[0], lhs, rhs[1]] for ([lhs, rhs] in abbrevs()) if (searchFilter.indexOf(rhs[0]) > -1)];
+
+ if (!list.length)
+ return liberator.echoerr("No abbreviations found");
+ list = template.tabular(["", "LHS", "RHS"], [], list);
+ commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
}
},
diff --git a/content/liberator.js b/content/liberator.js
index 9a418dc9..e59bb8ba 100644
--- a/content/liberator.js
+++ b/content/liberator.js
@@ -1249,12 +1249,12 @@ const liberator = (function () //{{{
autocommands.trigger(config.name + "Leave", {});
},
- sleep: function (ms)
+ sleep: function (delay)
{
- var mainThread = threadManager.mainThread;
+ let mainThread = threadManager.mainThread;
- var then = new Date().getTime(), now = then;
- for (; now - then < ms; now = new Date().getTime())
+ let end = Date.now() + delay;
+ while (Date.now() < end)
mainThread.processNextEvent(true);
return true;
},
@@ -1268,11 +1268,16 @@ const liberator = (function () //{{{
callback();
},
- threadYield: function (flush)
+ threadYield: function (flush, interruptable)
{
let mainThread = threadManager.mainThread;
+ liberator.interrupted = false;
do
+ {
mainThread.processNextEvent(true);
+ if (liberator.interrupted)
+ throw new Error("Interrupted");
+ }
while (flush && mainThread.hasPendingEvents());
},
diff --git a/content/options.js b/content/options.js
index 369fb9d7..6e1720b6 100644
--- a/content/options.js
+++ b/content/options.js
@@ -965,13 +965,11 @@ function Options() //{{{
continue;
value = options.getPref(pref);
- if (typeof value == "string")
- value = value.substr(0, 100).replace(/\n/g, " ");
let option = {
isDefault: !userValue,
default: loadPreference(pref, null, true),
- value: <>={template.highlight(value)}>,
+ value: <>={template.highlight(value, true, 100)}>,
name: pref,
pre: "\u00a0\u00a0" /* Unicode nonbreaking space. */
};
diff --git a/content/tabs.js b/content/tabs.js
index 131acc25..0bafeafb 100644
--- a/content/tabs.js
+++ b/content/tabs.js
@@ -354,7 +354,7 @@ function Tabs() //{{{
{
bang: true,
count: true,
- completer: function (context) completion.buffer(context.filter),
+ completer: function (context) completion.buffer(context),
literal: true
});
@@ -480,7 +480,7 @@ function Tabs() //{{{
{
bang: true,
count: true,
- completer: function (context) completion.buffer(context.filter),
+ completer: function (context) completion.buffer(context),
literal: true
});
@@ -748,8 +748,7 @@ function Tabs() //{{{
list: function (filter)
{
- let list = template.generic(completion.buffer(filter)[2]);
- commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
+ template.listCompleter("buffer", filter);
},
// wrap causes the movement to wrap around the start and end of the tab list
diff --git a/content/template.js b/content/template.js
index 09d3effc..222fa113 100644
--- a/content/template.js
+++ b/content/template.js
@@ -32,6 +32,23 @@ const template = {
return <>{xml}>;
},
+ listCompleter: function (name, filter)
+ {
+ let context = new CompletionContext(filter || "");
+ context.fork.apply(context, ["list", 0, completion, name].concat(Array.slice(arguments, 2)));
+ context = context.contexts["/list"];
+
+ while (context.incomplete)
+ liberator.threadYield(true, true);
+
+ let list = this.generic(
+
+ { this.completionRow(context.title, "hl-CompTitle") }
+ { template.map(context.items, function (item) context.createRow(item)) }
+
);
+ commandline.echo(list, commandline.HL_NORMAL, commandline.FORCE_MULTILINE);
+ },
+
completionRow: function completionRow(item, class)
{
if (typeof icon == "function")
@@ -93,7 +110,7 @@ const template = {
return {str};
case "string":
if (processStrings)
- str = <>{util.escapeString(str)}>;
+ str = str.quote();
return {str};
case "boolean":
return {str};
@@ -188,18 +205,12 @@ const template = {
// @param headers is an array of strings, the text for the header columns
genericTable: function genericTable(items, format)
{
- // FIXME: Kludge.
- let context = new CompletionContext("");
- context.filterFunc = function (items) items;
- if (format)
- context.format = format;
- return this.generic(
-
- { this.completionRow(context.title, "hl-CompTitle") }
- {
- this.map(items, function (item) template.completionRow.call(context, { text: context.getKey({item: item}, "text"), item: item }))
- }
-
);
+ this.listCompleter(function (context) {
+ context.filterFunc = null;
+ if (format)
+ context.format = format;
+ context.completions = items;
+ });
},
// returns a single row for a bookmark or history item
diff --git a/content/ui.js b/content/ui.js
index 7db9d2fe..5d67953e 100644
--- a/content/ui.js
+++ b/content/ui.js
@@ -117,7 +117,7 @@ function CommandLine() //{{{
if (events.feedingKeys)
return;
completionContext.reset();
- completionContext.fork("ex", 0, completion.ex, completion);
+ completionContext.fork("ex", 0, completion, "ex");
commandline.setCompletions(completionContext.allItems);
});
@@ -261,7 +261,7 @@ function CommandLine() //{{{
liberator.registerCallback("complete", modes.EX, function (str) {
completionContext.reset();
completionContext.tabPressed = true;
- completionContext.fork("ex", 0, completion.ex, completion);
+ completionContext.fork("ex", 0, completion, "ex");
return completionContext.allItems;
});
liberator.registerCallback("change", modes.EX, function (command) {
diff --git a/content/util.js b/content/util.js
index f0b66b7a..eeef060a 100644
--- a/content/util.js
+++ b/content/util.js
@@ -394,10 +394,7 @@ const util = { //{{{
{
if (Date.now() > endTime)
{
- liberator.interrupted = false;
- liberator.threadYield();
- if (liberator.interrupted)
- throw new Error("Interrupted");
+ liberator.threadYield(false, true);
endTime = Date.now() + time;
}
yield start++;