diff --git a/common/content/commands.js b/common/content/commands.js index 173b59e3..44164529 100644 --- a/common/content/commands.js +++ b/common/content/commands.js @@ -916,7 +916,7 @@ var Commands = Module("commands", { } } - if (arg != null || opt.type == CommandOption.NOARG) + if (arg != null || opt.type == CommandOption.NOARG) { // option allowed multiple times if (opt.multiple) args[opt.names[0]] = (args[opt.names[0]] || []).concat(arg); @@ -924,6 +924,7 @@ var Commands = Module("commands", { Class.replaceProperty(args, opt.names[0], opt.type == CommandOption.NOARG || arg); args.explicitOpts[opt.names[0]] = args[opt.names[0]]; + } i += optname.length + count; if (i == str.length) @@ -989,14 +990,17 @@ var Commands = Module("commands", { if (args.completeOpt) { let opt = args.completeOpt; let context = complete.fork(opt.names[0], args.completeStart); - let arg = args[opt.names[0]]; + let arg = args.explicitOpts[opt.names[0]]; context.filter = args.completeFilter; + if (isArray(arg)) context.filters.push(function (item) arg.indexOf(item.text) === -1); + if (typeof opt.completer == "function") var compl = opt.completer(context, args); else compl = opt.completer || []; + context.title = [opt.names[0]]; context.quote = args.quote; if (compl) diff --git a/common/modules/addons.jsm b/common/modules/addons.jsm index 4964d938..a1bd8272 100644 --- a/common/modules/addons.jsm +++ b/common/modules/addons.jsm @@ -10,7 +10,7 @@ Components.utils.import("resource://dactyl/bootstrap.jsm"); defineModule("addons", { exports: ["AddonManager", "Addons", "Addon", "addons"], require: ["services"], - use: ["config", "io", "prefs", "template", "util"] + use: ["completion", "config", "io", "prefs", "template", "util"] }, this); var callResult = function callResult(method) { @@ -235,8 +235,9 @@ var Addon = Class("Addon", { }); var AddonList = Class("AddonList", { - init: function init(modules, types) { + init: function init(modules, types, filter) { this.modules = modules; + this.filter = filter && filter.toLowerCase(); this.nodes = {}; this.addons = []; this.ready = false; @@ -271,6 +272,9 @@ var AddonList = Class("AddonList", { if (addon.id in this.addons) this.update(addon); else { + if (this.filter && addon.name.toLowerCase().indexOf(this.filter) === -1) + return; + addon = Addon(addon, this); this.addons[addon.id] = addon; @@ -318,7 +322,7 @@ var Addons = Module("addons", { }, { }, { commands: function (dactyl, modules, window) { - const { commands, completion } = modules; + const { CommandOption, commands, completion } = modules; let addonListener = AddonListener(modules); @@ -414,12 +418,44 @@ var Addons = Module("addons", { commands.add(["addo[ns]", "ao"], "List installed extensions", function (args) { - let addons = AddonList(modules, ["extension"]); + let addons = AddonList(modules, args["-types"], args[0]); modules.commandline.echo(addons); if (modules.commandline.savingOutput) util.waitFor(function () addons.ready); + }, + { + argCount: "?", + options: [ + { + names: ["-types", "-type", "-t"], + description: "The add-on types to list", + default: ["extension"], + completer: function (context, args) completion.addonType(context), + type: CommandOption.LIST + } + ] }); + }, + completion: function (dactyl, modules, window) { + completion.addonType = function addonType(context) { + let base = ["extension", "theme"]; + function update(types) { + context.completions = types.map(function (t) [t, util.capitalize(t)]); + } + + context.generate = function generate() { + update(base); + if (AddonManager.getAllAddons) { + context.incomplete = true; + AddonManager.getAllAddons(function (addons) { + context.incomplete = false; + update(array.uniq(base.concat(addons.map(function (a) a.type)), + true)); + }); + } + } + } } }); diff --git a/common/modules/base.jsm b/common/modules/base.jsm index caaab70b..6e1a4138 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -297,11 +297,11 @@ function deprecated(alternative, fn) { * @param {object} obj The object to inspect. * @returns {Generator} */ -function keys(obj) { +function keys(obj) iter(function keys() { for (var k in obj) if (hasOwnProperty.call(obj, k)) yield k; -} +}()); /** * Iterates over all of the top-level, iterable property values of an * object. diff --git a/common/modules/completion.jsm b/common/modules/completion.jsm index 7c352d1b..8594deeb 100644 --- a/common/modules/completion.jsm +++ b/common/modules/completion.jsm @@ -481,6 +481,13 @@ var CompletionContext = Class("CompletionContext", { let filtered = this.filterFunc(this._cache.constructed); if (this.maxItems) filtered = filtered.slice(0, this.maxItems); + if (/types/.test(this.name)) { + let self = this; + util.dump(this.filters[1]); + util.dump("FILTERED", this._cache.constructed.map(function (item) [item.text.quote(), self.filters[0].call(self, item.text)])); + util.dump("FILTERED", this._cache.constructed.map(function (item) + self.filters.map(function (filter) filter.call(self, item)))); + } // Sorting if (this.sortResults && this.compare) diff --git a/common/modules/config.jsm b/common/modules/config.jsm index 9b13b7d7..42434f5f 100644 --- a/common/modules/config.jsm +++ b/common/modules/config.jsm @@ -424,6 +424,7 @@ var ConfigBase = Class("ConfigBase", { Link position: relative; padding-right: 2em; Link:not(:hover)>LinkInfo opacity: 0; left: 0; width: 1px; height: 1px; overflow: hidden; LinkInfo { + color: black; position: absolute; left: 100%; padding: 1ex; @@ -518,6 +519,7 @@ var ConfigBase = Class("ConfigBase", { DownloadState;;;DownloadCell DownloadTime;;;DownloadCell DownloadTitle;;;DownloadCell,URL + DownloadTitle>Link>a max-width: 48ex; overflow: hidden; display: inline-block; AddonCell display: table-cell; padding: 0 1ex; @@ -530,7 +532,7 @@ var ConfigBase = Class("ConfigBase", { Addon>*;;;AddonCell AddonButtons AddonDescription - AddonName + AddonName max-width: 48ex; overflow: hidden; AddonStatus AddonVersion diff --git a/common/modules/downloads.jsm b/common/modules/downloads.jsm index 138efaac..33fcb2cc 100644 --- a/common/modules/downloads.jsm +++ b/common/modules/downloads.jsm @@ -178,9 +178,10 @@ var DownloadList = Class("DownloadList", XPCOM([Ci.nsIDownloadProgressListener, Ci.nsIObserver, Ci.nsISupportsWeakReference]), { - init: function init(modules) { + init: function init(modules, filter) { this.modules = modules; this.nodes = {}; + this.filter = filter && filter.toLowerCase(); this.downloads = {}; }, cleanup: function cleanup() { @@ -213,12 +214,15 @@ var DownloadList = Class("DownloadList", addDownload: function addDownload(id) { if (!(id in this.downloads)) { - this.downloads[id] = Download(id, this); + let download = Download(id, this); + if (this.filter && download.displayName.indexOf(this.filter) === -1) + return; + this.downloads[id] = download; let index = values(this.downloads).sort(function (a, b) a.compare(b)) - .indexOf(this.downloads[id]); + .indexOf(download); - this.nodes.list.insertBefore(this.downloads[id].nodes.row, + this.nodes.list.insertBefore(download.nodes.row, this.nodes.list.childNodes[index + 1]); } }, @@ -283,8 +287,11 @@ var Downloads = Module("downloads", { commands.add(["downl[oads]", "dl"], "Display the downloads list", function (args) { - let downloads = DownloadList(modules); + let downloads = DownloadList(modules, args[0]); modules.commandline.echo(downloads); + }, + { + argCount: "?" }); }, dactyl: function (dactyl, modules, window) {