mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-02-26 11:15:46 +01:00
Poke :downloads a bit. Add -sort flag, downloadsort option, :dlclear command. Closes issue #386.
--HG-- extra : rebase_source : 1ce7621d39e91f2779d1827975b44f00c7a1d00b
This commit is contained in:
@@ -983,6 +983,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
}
|
}
|
||||||
else if (obj instanceof Option) {
|
else if (obj instanceof Option) {
|
||||||
link = function (opt, name) <o>{name}</o>;
|
link = function (opt, name) <o>{name}</o>;
|
||||||
|
args = { value: "", values: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
XML.prettyPrinting = false;
|
XML.prettyPrinting = false;
|
||||||
@@ -1027,7 +1028,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (obj.completer)
|
if (obj.completer)
|
||||||
add(completion._runCompleter(obj.completer, "", null, args).items
|
add(completion._runCompleter(obj.closure.completer, "", null, args).items
|
||||||
.map(function (i) [i.text, i.description]));
|
.map(function (i) [i.text, i.description]));
|
||||||
|
|
||||||
if (obj.options && obj.options.some(function (o) o.description))
|
if (obj.options && obj.options.some(function (o) o.description))
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ var MOW = Module("mow", {
|
|||||||
catch (e) {
|
catch (e) {
|
||||||
util.reportError(e);
|
util.reportError(e);
|
||||||
util.dump(data);
|
util.dump(data);
|
||||||
this.messages.push(data);
|
|
||||||
}
|
}
|
||||||
|
this.messages.push(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let style = isString(data) ? "pre" : "nowrap";
|
let style = isString(data) ? "pre" : "nowrap";
|
||||||
|
|||||||
@@ -68,6 +68,21 @@
|
|||||||
Show progress of current downloads. Here, downloads can
|
Show progress of current downloads. Here, downloads can
|
||||||
be paused, resumed, and canceled.
|
be paused, resumed, and canceled.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>Available options include:</p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>-sort</dt> <dd>Sort order (see <o>downloadsort</o>) (short name: <em>-s</em>)</dd>
|
||||||
|
</dl>
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<tags>:dlc :dlclear</tags>
|
||||||
|
<strut/>
|
||||||
|
<spec>:dlc<oa>lear</oa></spec>
|
||||||
|
<description>
|
||||||
|
<p>Clear completed downloads.</p>
|
||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|||||||
@@ -257,6 +257,9 @@ quickmark.added-2 = Added Quick Mark '%S': %S
|
|||||||
|
|
||||||
save.invalidDestination-1 = Invalid destination: %S
|
save.invalidDestination-1 = Invalid destination: %S
|
||||||
|
|
||||||
|
sort.ascending = ascending
|
||||||
|
sort.descending = descending
|
||||||
|
|
||||||
status.link-1 = Link: %S
|
status.link-1 = Link: %S
|
||||||
|
|
||||||
style.none = No style found
|
style.none = No style found
|
||||||
|
|||||||
@@ -519,6 +519,32 @@
|
|||||||
</description>
|
</description>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<tags>'dls' 'dlsort' 'downloadsort'</tags>
|
||||||
|
<spec>'downloadsort'</spec>
|
||||||
|
<type>stringlist</type>
|
||||||
|
<default>-active,+filename</default>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
<ex>:downloads</ex> sort order, in order of precedence.
|
||||||
|
Each element must be preceded by a <tt>+</tt> or
|
||||||
|
<tt>-</tt>, indicating ascending or descending sorting,
|
||||||
|
respectively. Valid sort orders are:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>active</dt> <dd>Whether download is active</dd>
|
||||||
|
<dt>complete</dt> <dd>Percent complete</dd>
|
||||||
|
<dt>filename</dt> <dd>Target filename</dd>
|
||||||
|
<dt>size</dt> <dd>File size</dd>
|
||||||
|
<dt>speed</dt> <dd>Download speed</dd>
|
||||||
|
<dt>time</dt> <dd>Time remaining</dd>
|
||||||
|
<dt>url</dt> <dd>Source URL</dd>
|
||||||
|
</dl>
|
||||||
|
</description>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>'ds' 'defsearch'</tags>
|
<tags>'ds' 'defsearch'</tags>
|
||||||
<spec>'defsearch' 'ds'</spec>
|
<spec>'defsearch' 'ds'</spec>
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ var ConfigBase = Class("ConfigBase", {
|
|||||||
|
|
||||||
Dense margin-top: 0; margin-bottom: 0;
|
Dense margin-top: 0; margin-bottom: 0;
|
||||||
|
|
||||||
EditorEditing;;* background: #bbb !important; -moz-user-input: none !important; -moz-user-modify: read-only !important;
|
EditorEditing;;* background-color: #bbb !important; -moz-user-input: none !important; -moz-user-modify: read-only !important;
|
||||||
EditorError;;* background: red !important;
|
EditorError;;* background: red !important;
|
||||||
EditorBlink1;;* background: yellow !important;
|
EditorBlink1;;* background: yellow !important;
|
||||||
EditorBlink2;;*
|
EditorBlink2;;*
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ var Download = Class("Download", {
|
|||||||
/>/<span highlight="DownloadProgressTotal" key="progressTotal"/>
|
/>/<span highlight="DownloadProgressTotal" key="progressTotal"/>
|
||||||
</td>
|
</td>
|
||||||
<td highlight="DownloadPercent" key="percent"/>
|
<td highlight="DownloadPercent" key="percent"/>
|
||||||
|
<td highlight="DownloadSpeed" key="speed"/>
|
||||||
<td highlight="DownloadTime" key="time"/>
|
<td highlight="DownloadTime" key="time"/>
|
||||||
<td><a highlight="DownloadSource" key="source" href={self.source.spec}>{self.source.spec}</a></td>
|
<td><a highlight="DownloadSource" key="source" href={self.source.spec}>{self.source.spec}</a></td>
|
||||||
</tr>,
|
</tr>,
|
||||||
@@ -120,25 +121,46 @@ var Download = Class("Download", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
compare: function compare(other) String.localeCompare(this.displayName, other.displayName),
|
_compare: {
|
||||||
|
active: function (a, b) a.alive - b.alive,
|
||||||
|
complete: function (a, b) a.percentComplete - b.percentComplete,
|
||||||
|
filename: function (a, b) String.localeCompare(a.targetFile.leafName, b.targetFile.leafName),
|
||||||
|
size: function (a, b) a.size - b.size,
|
||||||
|
speed: function (a, b) a.speed - b.speed,
|
||||||
|
time: function (a, b) a.timeRemaining - b.timeRemaining,
|
||||||
|
url: function (a, b) String.localeCompare(a.source.spec, b.source.spec)
|
||||||
|
},
|
||||||
|
|
||||||
|
compare: function compare(other) values(this.list.sortOrder).map(function (order) {
|
||||||
|
let val = this._compare[order.substr(1)](this, other);
|
||||||
|
|
||||||
|
return (order[0] == "-") ? -val : val;
|
||||||
|
}, this).nth(util.identity, 0) || 0,
|
||||||
|
|
||||||
timeRemaining: Infinity,
|
timeRemaining: Infinity,
|
||||||
|
|
||||||
updateProgress: function updateProgress() {
|
updateProgress: function updateProgress() {
|
||||||
let self = this.__proto__;
|
let self = this.__proto__;
|
||||||
|
|
||||||
if (this.amountTransferred === this.size)
|
if (this.amountTransferred === this.size) {
|
||||||
|
this.nodes.speed.textContent = "";
|
||||||
this.nodes.time.textContent = "";
|
this.nodes.time.textContent = "";
|
||||||
else if (this.speed == 0 || this.size == 0)
|
|
||||||
this.nodes.time.textContent = "Unknown";
|
|
||||||
else {
|
|
||||||
let seconds = (this.size - this.amountTransferred) / this.speed;
|
|
||||||
[, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining);
|
|
||||||
if (this.timeRemaining)
|
|
||||||
this.nodes.time.textContent = util.formatSeconds(this.timeRemaining);
|
|
||||||
else
|
|
||||||
this.nodes.time.textContent = /*L*/"~1 second";
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
this.nodes.speed.textContent = util.formatBytes(this.speed, 1, true) + "/s";
|
||||||
|
|
||||||
|
if (this.speed == 0 || this.size == 0)
|
||||||
|
this.nodes.time.textContent = "Unknown";
|
||||||
|
else {
|
||||||
|
let seconds = (this.size - this.amountTransferred) / this.speed;
|
||||||
|
[, self.timeRemaining] = DownloadUtils.getTimeLeft(seconds, this.timeRemaining);
|
||||||
|
if (this.timeRemaining)
|
||||||
|
this.nodes.time.textContent = util.formatSeconds(this.timeRemaining);
|
||||||
|
else
|
||||||
|
this.nodes.time.textContent = /*L*/"~1 second";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let total = this.nodes.progressTotal.textContent = this.size ? util.formatBytes(this.size, 1, true) : "Unknown";
|
let total = this.nodes.progressTotal.textContent = this.size ? util.formatBytes(this.size, 1, true) : "Unknown";
|
||||||
let suffix = RegExp(/( [a-z]+)?$/i.exec(total)[0] + "$");
|
let suffix = RegExp(/( [a-z]+)?$/i.exec(total)[0] + "$");
|
||||||
this.nodes.progressHave.textContent = util.formatBytes(this.amountTransferred, 1, true).replace(suffix, "");
|
this.nodes.progressHave.textContent = util.formatBytes(this.amountTransferred, 1, true).replace(suffix, "");
|
||||||
@@ -165,7 +187,8 @@ var DownloadList = Class("DownloadList",
|
|||||||
XPCOM([Ci.nsIDownloadProgressListener,
|
XPCOM([Ci.nsIDownloadProgressListener,
|
||||||
Ci.nsIObserver,
|
Ci.nsIObserver,
|
||||||
Ci.nsISupportsWeakReference]), {
|
Ci.nsISupportsWeakReference]), {
|
||||||
init: function init(modules, filter) {
|
init: function init(modules, filter, sort) {
|
||||||
|
this.sortOrder = sort;
|
||||||
this.modules = modules;
|
this.modules = modules;
|
||||||
this.filter = filter && filter.toLowerCase();
|
this.filter = filter && filter.toLowerCase();
|
||||||
this.nodes = {
|
this.nodes = {
|
||||||
@@ -173,6 +196,7 @@ var DownloadList = Class("DownloadList",
|
|||||||
};
|
};
|
||||||
this.downloads = {};
|
this.downloads = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
cleanup: function cleanup() {
|
cleanup: function cleanup() {
|
||||||
this.observe.unregister();
|
this.observe.unregister();
|
||||||
services.downloadManager.removeListener(this);
|
services.downloadManager.removeListener(this);
|
||||||
@@ -187,6 +211,7 @@ var DownloadList = Class("DownloadList",
|
|||||||
<span/>
|
<span/>
|
||||||
<span><!--L-->Progress</span>
|
<span><!--L-->Progress</span>
|
||||||
<span/>
|
<span/>
|
||||||
|
<span><!--L-->Speed</span>
|
||||||
<span><!--L-->Time remaining</span>
|
<span><!--L-->Time remaining</span>
|
||||||
<span><!--L-->Source</span>
|
<span><!--L-->Source</span>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -202,6 +227,7 @@ var DownloadList = Class("DownloadList",
|
|||||||
/>/<span highlight="DownloadProgressTotal" key="progressTotal"/>
|
/>/<span highlight="DownloadProgressTotal" key="progressTotal"/>
|
||||||
</td>
|
</td>
|
||||||
<td highlight="DownloadPercent" key="percent"/>
|
<td highlight="DownloadPercent" key="percent"/>
|
||||||
|
<td highlight="DownloadSpeed" key="speed"/>
|
||||||
<td highlight="DownloadTime" key="time"/>
|
<td highlight="DownloadTime" key="time"/>
|
||||||
<td/>
|
<td/>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -253,6 +279,17 @@ var DownloadList = Class("DownloadList",
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sort: function sort() {
|
||||||
|
let list = values(this.downloads).sort(function (a, b) a.compare(b));
|
||||||
|
|
||||||
|
for (let [i, download] in iter(list))
|
||||||
|
if (this.nodes.list.childNodes[i + 1] != download.nodes.row)
|
||||||
|
this.nodes.list.insertBefore(download.nodes.row,
|
||||||
|
this.nodes.list.childNodes[i + 1]);
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldSort: function shouldSort() Array.some(arguments, function (val) this.sortOrder.some(function (v) v.substr(1) == val), this),
|
||||||
|
|
||||||
update: function update() {
|
update: function update() {
|
||||||
for (let node in values(this.nodes))
|
for (let node in values(this.nodes))
|
||||||
if (node.update && node.update != update)
|
if (node.update && node.update != update)
|
||||||
@@ -278,8 +315,11 @@ var DownloadList = Class("DownloadList",
|
|||||||
let active = downloads.filter(function (dl) dl.alive).length;
|
let active = downloads.filter(function (dl) dl.alive).length;
|
||||||
if (active)
|
if (active)
|
||||||
this.nodes.total.textContent = /*L*/active + " active";
|
this.nodes.total.textContent = /*L*/active + " active";
|
||||||
else for (let key in values(["total", "percent", "time"]))
|
else for (let key in values(["total", "percent", "speed", "time"]))
|
||||||
this.nodes[key].textContent = "";
|
this.nodes[key].textContent = "";
|
||||||
|
|
||||||
|
if (this.shouldSort("complete", "size", "speed", "time"))
|
||||||
|
this.sort();
|
||||||
},
|
},
|
||||||
|
|
||||||
observers: {
|
observers: {
|
||||||
@@ -305,11 +345,15 @@ var DownloadList = Class("DownloadList",
|
|||||||
this.nodes.list.scrollIntoView(false);
|
this.nodes.list.scrollIntoView(false);
|
||||||
}
|
}
|
||||||
this.update();
|
this.update();
|
||||||
|
|
||||||
|
if (this.shouldSort("active"))
|
||||||
|
this.sort();
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
util.reportError(e);
|
util.reportError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onProgressChange: function (webProgress, request,
|
onProgressChange: function (webProgress, request,
|
||||||
curProgress, maxProgress,
|
curProgress, maxProgress,
|
||||||
curTotalProgress, maxTotalProgress,
|
curTotalProgress, maxTotalProgress,
|
||||||
@@ -328,17 +372,84 @@ var DownloadList = Class("DownloadList",
|
|||||||
var Downloads = Module("downloads", {
|
var Downloads = Module("downloads", {
|
||||||
}, {
|
}, {
|
||||||
}, {
|
}, {
|
||||||
commands: function (dactyl, modules, window) {
|
commands: function initCommands(dactyl, modules, window) {
|
||||||
const { commands } = modules;
|
const { commands, CommandOption } = modules;
|
||||||
|
|
||||||
commands.add(["downl[oads]", "dl"],
|
commands.add(["downl[oads]", "dl"],
|
||||||
"Display the downloads list",
|
"Display the downloads list",
|
||||||
function (args) {
|
function (args) {
|
||||||
let downloads = DownloadList(modules, args[0]);
|
let downloads = DownloadList(modules, args[0], args["-sort"]);
|
||||||
modules.commandline.echo(downloads);
|
modules.commandline.echo(downloads);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
argCount: "?"
|
argCount: "?",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
names: ["-sort", "-s"],
|
||||||
|
description: "Sort order (see 'downloadsort')",
|
||||||
|
type: CommandOption.LIST,
|
||||||
|
get default() modules.options["downloadsort"],
|
||||||
|
completer: function (context, args) modules.options.get("downloadsort").completer(context, { values: args["-sort"] }),
|
||||||
|
validator: function (value) modules.options.get("downloadsort").validator(value)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
commands.add(["dlc[lear]"],
|
||||||
|
"Clear completed downloads",
|
||||||
|
function (args) { services.downloadManager.cleanUp(); });
|
||||||
|
},
|
||||||
|
options: function initOptions(dactyl, modules, window) {
|
||||||
|
const { options } = modules;
|
||||||
|
|
||||||
|
if (false)
|
||||||
|
options.add(["downloadcolumns", "dlc"],
|
||||||
|
"The columns to show in the download manager",
|
||||||
|
"stringlist", "filename,state,buttons,progress,percent,time,url",
|
||||||
|
{
|
||||||
|
values: {
|
||||||
|
buttons: "Control buttons",
|
||||||
|
filename: "Target filename",
|
||||||
|
percent: "Percent complete",
|
||||||
|
size: "File size",
|
||||||
|
speed: "Download speed",
|
||||||
|
state: "The download's state",
|
||||||
|
time: "Time remaining",
|
||||||
|
url: "Source URL"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.add(["downloadsort", "dlsort", "dls"],
|
||||||
|
":downloads sort order",
|
||||||
|
"stringlist", "-active,+filename",
|
||||||
|
{
|
||||||
|
values: {
|
||||||
|
active: "Whether download is active",
|
||||||
|
complete: "Percent complete",
|
||||||
|
filename: "Target filename",
|
||||||
|
size: "File size",
|
||||||
|
speed: "Download speed",
|
||||||
|
time: "Time remaining",
|
||||||
|
url: "Source URL"
|
||||||
|
},
|
||||||
|
|
||||||
|
completer: function (context, extra) {
|
||||||
|
let seen = set.has(set(extra.values.map(function (val) val.substr(1))));
|
||||||
|
|
||||||
|
context.completions = iter(this.values).filter(function ([k, v]) !seen(k))
|
||||||
|
.map(function ([k, v]) [["+" + k, [v, " (", _("sort.ascending"), ")"].join("")],
|
||||||
|
["-" + k, [v, " (", _("sort.descending"), ")"].join("")]])
|
||||||
|
.flatten().array;
|
||||||
|
},
|
||||||
|
|
||||||
|
has: function () Array.some(arguments, function (val) this.value.some(function (v) v.substr(1) == val)),
|
||||||
|
|
||||||
|
validator: function (value) {
|
||||||
|
let seen = {};
|
||||||
|
return value.every(function (val) /^[+-]/.test(val) && set.has(this.values, val.substr(1))
|
||||||
|
&& !set.add(seen, val.substr(1)),
|
||||||
|
this) && value.length;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1439,6 +1439,14 @@ var Options = Module("options", {
|
|||||||
context.filters.push(function (i) curValues.indexOf(i.text) == -1);
|
context.filters.push(function (i) curValues.indexOf(i.text) == -1);
|
||||||
if (op == "-")
|
if (op == "-")
|
||||||
context.filters.push(function (i) curValues.indexOf(i.text) > -1);
|
context.filters.push(function (i) curValues.indexOf(i.text) > -1);
|
||||||
|
|
||||||
|
memoize(extra, "values", function () {
|
||||||
|
if (op == "+")
|
||||||
|
return curValues.concat(newValues);
|
||||||
|
if (op == "-")
|
||||||
|
return curValues.filter(function (v) newValues.indexOf(val) == -1);
|
||||||
|
return newValues;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = completer.call(opt, context, extra);
|
let res = completer.call(opt, context, extra);
|
||||||
|
|||||||
@@ -89,7 +89,8 @@
|
|||||||
listing keys for modes other than Normal, filtering the output,
|
listing keys for modes other than Normal, filtering the output,
|
||||||
and linking to source code locations). [b4]
|
and linking to source code locations). [b4]
|
||||||
- :downloads now opens a download list in the multi-line output
|
- :downloads now opens a download list in the multi-line output
|
||||||
buffer. [b6]
|
buffer. Added -sort flag. [b6][b7]
|
||||||
|
- Added :dlclear command. [b7]
|
||||||
- :extensions has been replaced with a more powerful :addons. [b6]
|
- :extensions has been replaced with a more powerful :addons. [b6]
|
||||||
- :javascript! now opens a Read Eval Print Loop. [b6]
|
- :javascript! now opens a Read Eval Print Loop. [b6]
|
||||||
- Added -arg flag to :map. [b6]
|
- Added -arg flag to :map. [b6]
|
||||||
@@ -177,6 +178,7 @@
|
|||||||
- Added 'autocomplete' option for specifying which completion
|
- Added 'autocomplete' option for specifying which completion
|
||||||
groups should be auto-completed. [b2]
|
groups should be auto-completed. [b2]
|
||||||
- Added 'banghist' option. [b1]
|
- Added 'banghist' option. [b1]
|
||||||
|
- Added 'downloadsort' option. [b7]
|
||||||
- Replaced 'focuscontent' with 'strictfocus'. [b1]
|
- Replaced 'focuscontent' with 'strictfocus'. [b1]
|
||||||
- 'complete' now defaults to "slf" but file completion only
|
- 'complete' now defaults to "slf" but file completion only
|
||||||
triggers when the URL begins as above. [b1]
|
triggers when the URL begins as above. [b1]
|
||||||
|
|||||||
Reference in New Issue
Block a user