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.* += - ; - } - } - - 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++;