diff --git a/common/content/autocommands.js b/common/content/autocommands.js
index fd9f4e0f..899019f7 100755
--- a/common/content/autocommands.js
+++ b/common/content/autocommands.js
@@ -83,7 +83,7 @@ const AutoCommands = Module("autocommands", {
}
});
- let list = template.commandOutput(
+ let list = template.commandOutput(commandline.command,
----- Auto Commands -----
@@ -257,8 +257,6 @@ const AutoCommands = Module("autocommands", {
});
},
completion: function () {
- JavaScript.setCompleter(this.get, [function () Iterator(config.autocommands)]);
-
completion.autocmdEvent = function autocmdEvent(context) {
context.completions = Iterator(config.autocommands);
};
@@ -268,6 +266,9 @@ const AutoCommands = Module("autocommands", {
context.completions = [item for (item in events.getMacros())];
};
},
+ javascript: function () {
+ JavaScript.setCompleter(this.get, [function () Iterator(config.autocommands)]);
+ },
options: function () {
options.add(["eventignore", "ei"],
"List of autocommand event names which should be ignored",
diff --git a/common/content/base.js b/common/content/base.js
index 848f22d6..e4a58bbb 100644
--- a/common/content/base.js
+++ b/common/content/base.js
@@ -9,14 +9,6 @@ const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
-function array(obj) {
- if (isgenerator(obj))
- obj = [k for (k in obj)];
- else if (obj.length)
- obj = Array.slice(obj);
- return util.Array(obj);
-}
-
function allkeys(obj) {
let ret = {};
try {
@@ -45,7 +37,7 @@ function allkeys(obj) {
}
function debuggerProperties(obj) {
- if (modules.services && options["jsdebugger"]) {
+ if (modules.services && services.get("debugger").isOn) {
let ret = {};
services.get("debugger").wrapValue(obj).getProperties(ret, {});
return ret.value;
@@ -125,9 +117,9 @@ function iter(obj) {
}
catch (e) {}
})();
- if (isinstance(obj, [HTMLCollection, NodeList]))
- return util.Array.iteritems(obj);
- if (obj instanceof NamedNodeMap)
+ if (isinstance(obj, [Ci.nsIDOMHTMLCollection, Ci.nsIDOMNodeList]))
+ return array.iteritems(obj);
+ if (obj instanceof Ci.nsIDOMNamedNodeMap)
return (function () {
for (let i = 0; i < obj.length; i++)
yield [obj.name, obj];
@@ -208,6 +200,13 @@ function call(fn) {
return fn;
}
+function memoize(obj, key, getter) {
+ obj.__defineGetter__(key, function () {
+ delete obj[key];
+ return obj[key] = getter(obj, key);
+ });
+}
+
/**
* Curries a function to the given number of arguments. Each
* call of the resulting function returns a new function. When
@@ -312,13 +311,8 @@ function update(target) {
* @param {Object} overrides @optional
*/
function extend(subclass, superclass, overrides) {
- subclass.prototype = {};
+ subclass.prototype = { __proto__: superclass.prototype };
update(subclass.prototype, overrides);
- // This is unduly expensive. Unfortunately necessary since
- // we apparently can't rely on the presence of the
- // debugger to enumerate properties when we have
- // __iterators__ attached to prototypes.
- subclass.prototype.__proto__ = superclass.prototype;
subclass.superclass = superclass.prototype;
subclass.prototype.constructor = subclass;
@@ -421,8 +415,10 @@ Class.prototype = {
*/
setTimeout: function (callback, timeout) {
const self = this;
- function target() callback.call(self);
- return window.setTimeout(target, timeout);
+ let notify = { notify: function notify(timer) { callback.call(self) } };
+ let timer = services.create("timer");
+ timer.initWithCallback(notify, timeout, timer.TYPE_ONE_SHOT);
+ return timer;
}
};
@@ -493,4 +489,136 @@ for (let k in values(["concat", "every", "filter", "forEach", "indexOf", "join",
"map", "reduce", "reduceRight", "reverse", "slice", "some", "sort"]))
StructBase.prototype[k] = Array.prototype[k];
+/**
+ * Array utility methods.
+ */
+const array = Class("util.Array", Array, {
+ init: function (ary) {
+ if (isgenerator(ary))
+ ary = [k for (k in ary)];
+ else if (ary.length)
+ ary = Array.slice(ary);
+
+ return {
+ __proto__: ary,
+ __iterator__: function () this.iteritems(),
+ __noSuchMethod__: function (meth, args) {
+ var res = array[meth].apply(null, [this.__proto__].concat(args));
+
+ if (array.isinstance(res))
+ return array(res);
+ return res;
+ },
+ toString: function () this.__proto__.toString(),
+ concat: function () this.__proto__.concat.apply(this.__proto__, arguments),
+ map: function () this.__noSuchMethod__("map", Array.slice(arguments))
+ };
+ }
+}, {
+ isinstance: function isinstance(obj) {
+ return Object.prototype.toString.call(obj) == "[object Array]";
+ },
+
+ /**
+ * Converts an array to an object. As in lisp, an assoc is an
+ * array of key-value pairs, which maps directly to an object,
+ * as such:
+ * [["a", "b"], ["c", "d"]] -> { a: "b", c: "d" }
+ *
+ * @param {Array[]} assoc
+ * @... {string} 0 - Key
+ * @... 1 - Value
+ */
+ toObject: function toObject(assoc) {
+ let obj = {};
+ assoc.forEach(function ([k, v]) { obj[k] = v; });
+ return obj;
+ },
+
+ /**
+ * Compacts an array, removing all elements that are null or undefined:
+ * ["foo", null, "bar", undefined] -> ["foo", "bar"]
+ *
+ * @param {Array} ary
+ * @returns {Array}
+ */
+ compact: function compact(ary) ary.filter(function (item) item != null),
+
+ /**
+ * Flattens an array, such that all elements of the array are
+ * joined into a single array:
+ * [["foo", ["bar"]], ["baz"], "quux"] -> ["foo", ["bar"], "baz", "quux"]
+ *
+ * @param {Array} ary
+ * @returns {Array}
+ */
+ flatten: function flatten(ary) ary.length ? Array.concat.apply([], ary) : [],
+
+ /**
+ * Returns an Iterator for an array's values.
+ *
+ * @param {Array} ary
+ * @returns {Iterator(Object)}
+ */
+ itervalues: function itervalues(ary) {
+ let length = ary.length;
+ for (let i = 0; i < length; i++)
+ yield ary[i];
+ },
+
+ /**
+ * Returns an Iterator for an array's indices and values.
+ *
+ * @param {Array} ary
+ * @returns {Iterator([{number}, {Object}])}
+ */
+ iteritems: function iteritems(ary) {
+ let length = ary.length;
+ for (let i = 0; i < length; i++)
+ yield [i, ary[i]];
+ },
+
+ /**
+ * Filters out all duplicates from an array. If
+ * unsorted is false, the array is sorted before
+ * duplicates are removed.
+ *
+ * @param {Array} ary
+ * @param {boolean} unsorted
+ * @returns {Array}
+ */
+ uniq: function uniq(ary, unsorted) {
+ let ret = [];
+ if (unsorted) {
+ for (let [, item] in Iterator(ary))
+ if (ret.indexOf(item) == -1)
+ ret.push(item);
+ }
+ else {
+ for (let [, item] in Iterator(ary.sort())) {
+ if (item != last || !ret.length)
+ ret.push(item);
+ var last = item;
+ }
+ }
+ return ret;
+ },
+
+ /**
+ * Zips the contents of two arrays. The resulting array is twice the
+ * length of ary1, with any shortcomings of ary2 replaced with null
+ * strings.
+ *
+ * @param {Array} ary1
+ * @param {Array} ary2
+ * @returns {Array}
+ */
+ zip: function zip(ary1, ary2) {
+ let res = []
+ for(let [i, item] in Iterator(ary1))
+ res.push(item, i in ary2 ? ary2[i] : "");
+ return res;
+ }
+});
+
// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/content/bookmarks.js b/common/content/bookmarks.js
index 7f7f546b..fff84480 100644
--- a/common/content/bookmarks.js
+++ b/common/content/bookmarks.js
@@ -464,7 +464,7 @@ const Bookmarks = Module("bookmarks", {
args.completeFilter = have.pop();
let prefix = filter.substr(0, filter.length - args.completeFilter.length);
- let tags = util.Array.uniq(util.Array.flatten([b.tags for ([k, b] in Iterator(this._cache.bookmarks))]));
+ let tags = array.uniq(util.Array.flatten([b.tags for ([k, b] in Iterator(this._cache.bookmarks))]));
return [[prefix + tag, tag] for ([i, tag] in Iterator(tags)) if (have.indexOf(tag) < 0)];
}
diff --git a/common/content/buffer.js b/common/content/buffer.js
index bedfb4d7..cb50f16f 100644
--- a/common/content/buffer.js
+++ b/common/content/buffer.js
@@ -1003,7 +1003,7 @@ const Buffer = Module("buffer", {
let values = ZoomManager.zoomValues;
let cur = values.indexOf(ZoomManager.snap(ZoomManager.zoom));
- let i = util.Math.constrain(cur + steps, 0, values.length - 1);
+ let i = Math.constrain(cur + steps, 0, values.length - 1);
if (i == cur && fullZoom == ZoomManager.useFullZoom)
dactyl.beep();
@@ -1286,7 +1286,7 @@ const Buffer = Module("buffer", {
level = buffer.textZoom + parseInt(arg, 10);
// relative args shouldn't take us out of range
- level = util.Math.constrain(level, Buffer.ZOOM_MIN, Buffer.ZOOM_MAX);
+ level = Math.constrain(level, Buffer.ZOOM_MIN, Buffer.ZOOM_MAX);
}
else
dactyl.assert(false, "E488: Trailing characters");
@@ -1519,14 +1519,14 @@ const Buffer = Module("buffer", {
let xpath = ["input", "textarea[not(@disabled) and not(@readonly)]"];
let elements = [m for (m in util.evaluateXPath(xpath))].filter(function (elem) {
- if (elem.readOnly || elem instanceof HTMLInputElement && set.has(Events.editableInputs, elem.type))
+ if (elem.readOnly || elem instanceof HTMLInputElement && !set.has(Events.editableInputs, elem.type))
return false;
let computedStyle = util.computedStyle(elem);
return computedStyle.visibility != "hidden" && computedStyle.display != "none";
});
dactyl.assert(elements.length > 0);
- let elem = elements[util.Math.constrain(count, 1, elements.length) - 1];
+ let elem = elements[Math.constrain(count, 1, elements.length) - 1];
buffer.focusElement(elem);
util.scrollIntoView(elem);
}
diff --git a/common/content/commandline.js b/common/content/commandline.js
index f3088985..974d7446 100644
--- a/common/content/commandline.js
+++ b/common/content/commandline.js
@@ -131,26 +131,24 @@ const CommandLine = Module("commandline", {
this._startHints = false; // whether we're waiting to start hints mode
this._lastSubstring = "";
- // the containing box for the this._promptWidget and this._commandWidget
- this._commandlineWidget = document.getElementById("dactyl-commandline");
- // the prompt for the current command, for example : or /. Can be blank
- this._promptWidget = document.getElementById("dactyl-commandline-prompt");
- // the command bar which contains the current command
- this._commandWidget = document.getElementById("dactyl-commandline-command");
+ this.widgets = {
+ commandline: document.getElementById("dactyl-commandline"),
+ prompt: document.getElementById("dactyl-commandline-prompt"),
+ command: document.getElementById("dactyl-commandline-command"),
- this._messageBox = document.getElementById("dactyl-message");
+ message: document.getElementById("dactyl-message"),
- this._commandWidget.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
- this._messageBox.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
+ multilineOutput: document.getElementById("dactyl-multiline-output"),
+ multilineInput: document.getElementById("dactyl-multiline-input"),
+ };
+
+ this.widgets.command.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
+ this.widgets.message.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
// the widget used for multiline output
- this._multilineOutputWidget = document.getElementById("dactyl-multiline-output");
- this._outputContainer = this._multilineOutputWidget.parentNode;
+ this._outputContainer = this.widgets.multilineOutput.parentNode;
- this._multilineOutputWidget.contentDocument.body.id = "dactyl-multiline-output-content";
-
- // the widget used for multiline intput
- this._multilineInputWidget = document.getElementById("dactyl-multiline-input");
+ this.widgets.multilineOutput.contentDocument.body.id = "dactyl-multiline-output-content";
// we need to save the mode which were in before opening the command line
// this is then used if we focus the command line again without the "official"
@@ -208,7 +206,7 @@ const CommandLine = Module("commandline", {
* Highlight the messageBox according to group.
*/
_setHighlightGroup: function (group) {
- this._messageBox.setAttributeNS(NS.uri, "highlight", group);
+ this.widgets.message.setAttributeNS(NS.uri, "highlight", group);
},
/**
@@ -226,10 +224,10 @@ const CommandLine = Module("commandline", {
* @param {string} highlightGroup
*/
_setPrompt: function (val, highlightGroup) {
- this._promptWidget.value = val;
- this._promptWidget.size = val.length;
- this._promptWidget.collapsed = (val == "");
- this._promptWidget.setAttributeNS(NS.uri, "highlight", highlightGroup || commandline.HL_NORMAL);
+ this.widgets.prompt.value = val;
+ this.widgets.prompt.size = val.length;
+ this.widgets.prompt.collapsed = (val == "");
+ this.widgets.prompt.setAttributeNS(NS.uri, "highlight", highlightGroup || commandline.HL_NORMAL);
},
/**
@@ -239,9 +237,9 @@ const CommandLine = Module("commandline", {
* @param {string} cmd
*/
_setCommand: function (cmd) {
- this._commandWidget.value = cmd;
- this._commandWidget.selectionStart = cmd.length;
- this._commandWidget.selectionEnd = cmd.length;
+ this.widgets.command.value = cmd;
+ this.widgets.command.selectionStart = cmd.length;
+ this.widgets.command.selectionEnd = cmd.length;
},
/**
@@ -254,14 +252,14 @@ const CommandLine = Module("commandline", {
*/
_echoLine: function (str, highlightGroup, forceSingle) {
this._setHighlightGroup(highlightGroup);
- this._messageBox.value = str;
+ this.widgets.message.value = str;
dactyl.triggerObserver("echoLine", str, highlightGroup, forceSingle);
if (!this._commandShown())
commandline.hide();
- let field = this._messageBox.inputField;
+ let field = this.widgets.message.inputField;
if (!forceSingle && field.editor.rootElement.scrollWidth > field.scrollWidth)
this._echoMultiline({str}, highlightGroup);
},
@@ -274,8 +272,8 @@ const CommandLine = Module("commandline", {
*/
// TODO: resize upon a window resize
_echoMultiline: function (str, highlightGroup) {
- let doc = this._multilineOutputWidget.contentDocument;
- let win = this._multilineOutputWidget.contentWindow;
+ let doc = this.widgets.multilineOutput.contentDocument;
+ let win = this.widgets.multilineOutput.contentWindow;
dactyl.triggerObserver("echoMultiline", str, highlightGroup);
@@ -316,9 +314,9 @@ const CommandLine = Module("commandline", {
* Ensure that the multiline input widget is the correct size.
*/
_autosizeMultilineInputWidget: function () {
- let lines = this._multilineInputWidget.value.split("\n").length - 1;
+ let lines = this.widgets.multilineInput.value.split("\n").length - 1;
- this._multilineInputWidget.setAttribute("rows", Math.max(lines, 1));
+ this.widgets.multilineInput.setAttribute("rows", Math.max(lines, 1));
},
HL_NORMAL: "Normal",
@@ -386,15 +384,15 @@ const CommandLine = Module("commandline", {
try {
// The long path is because of complications with the
// completion preview.
- return this._commandWidget.inputField.editor.rootElement.firstChild.textContent;
+ return this.widgets.command.inputField.editor.rootElement.firstChild.textContent;
}
catch (e) {
- return this._commandWidget.value;
+ return this.widgets.command.value;
}
},
- set command(cmd) this._commandWidget.value = cmd,
+ set command(cmd) this.widgets.command.value = cmd,
- get message() this._messageBox.value,
+ get message() this.widgets.message.value,
/**
* Open the command line. The main mode is set to
@@ -416,14 +414,14 @@ const CommandLine = Module("commandline", {
this._setPrompt(this._currentPrompt);
this._setCommand(this._currentCommand);
- this._commandlineWidget.collapsed = false;
+ this.widgets.commandline.collapsed = false;
modes.set(modes.COMMAND_LINE, this._currentExtendedMode);
- this._commandWidget.focus();
+ this.widgets.command.focus();
- this._history = CommandLine.History(this._commandWidget.inputField, (modes.extended == modes.EX) ? "command" : "search");
- this._completions = CommandLine.Completions(this._commandWidget.inputField);
+ this._history = CommandLine.History(this.widgets.command.inputField, (modes.extended == modes.EX) ? "command" : "search");
+ this._completions = CommandLine.Completions(this.widgets.command.inputField);
// open the completion list automatically if wanted
if (cmd.length)
@@ -450,7 +448,7 @@ const CommandLine = Module("commandline", {
statusline.updateProgress(""); // we may have a "match x of y" visible
dactyl.focusContent(false);
- this._multilineInputWidget.collapsed = true;
+ this.widgets.multilineInput.collapsed = true;
this._completionList.hide();
if (!this._keepCommand || this._silent || this._quiet) {
@@ -470,7 +468,7 @@ const CommandLine = Module("commandline", {
* are under it.
*/
hide: function hide() {
- this._commandlineWidget.collapsed = true;
+ this.widgets.commandline.collapsed = true;
},
/**
@@ -509,7 +507,7 @@ const CommandLine = Module("commandline", {
return;
// The DOM isn't threadsafe. It must only be accessed from the main thread.
- dactyl.callInMainThread(function () {
+ util.callInMainThread(function () {
if ((flags & this.DISALLOW_MULTILINE) && !this._outputContainer.collapsed)
return;
@@ -518,7 +516,7 @@ const CommandLine = Module("commandline", {
// TODO: this is all a bit convoluted - clean up.
// assume that FORCE_MULTILINE output is fully styled
- if (!(flags & this.FORCE_MULTILINE) && !single && (!this._outputContainer.collapsed || this._messageBox.value == this._lastEcho)) {
+ if (!(flags & this.FORCE_MULTILINE) && !single && (!this._outputContainer.collapsed || this.widgets.message.value == this._lastEcho)) {
highlightGroup += " Message";
action = this._echoMultiline;
}
@@ -529,9 +527,9 @@ const CommandLine = Module("commandline", {
if (single)
this._lastEcho = null;
else {
- if (this._messageBox.value == this._lastEcho)
+ if (this.widgets.message.value == this._lastEcho)
this._echoMultiline({this._lastEcho},
- this._messageBox.getAttributeNS(NS.uri, "highlight"));
+ this.widgets.message.getAttributeNS(NS.uri, "highlight"));
this._lastEcho = (action == this._echoLine) && str;
}
@@ -571,10 +569,10 @@ const CommandLine = Module("commandline", {
this._setPrompt(prompt, extra.promptHighlight || this.HL_QUESTION);
this._setCommand(extra.default || "");
- this._commandlineWidget.collapsed = false;
- this._commandWidget.focus();
+ this.widgets.commandline.collapsed = false;
+ this.widgets.command.focus();
- this._completions = CommandLine.Completions(this._commandWidget.inputField);
+ this._completions = CommandLine.Completions(this.widgets.command.inputField);
},
/**
@@ -588,7 +586,7 @@ const CommandLine = Module("commandline", {
// FIXME: Buggy, especially when pasting. Shouldn't use a RegExp.
inputMultiline: function inputMultiline(untilRegexp, callbackFunc) {
// Kludge.
- let cmd = !this._commandWidget.collapsed && this.command;
+ let cmd = !this.widgets.command.collapsed && this.command;
modes.push(modes.COMMAND_LINE, modes.INPUT_MULTILINE);
if (cmd != false)
this._echoLine(cmd, this.HL_NORMAL);
@@ -597,11 +595,11 @@ const CommandLine = Module("commandline", {
this._multilineRegexp = untilRegexp;
this._multilineCallback = callbackFunc;
- this._multilineInputWidget.collapsed = false;
- this._multilineInputWidget.value = "";
+ this.widgets.multilineInput.collapsed = false;
+ this.widgets.multilineInput.value = "";
this._autosizeMultilineInputWidget();
- this.setTimeout(function () { this._multilineInputWidget.focus(); }, 10);
+ this.setTimeout(function () { this.widgets.multilineInput.focus(); }, 10);
},
/**
@@ -619,12 +617,12 @@ const CommandLine = Module("commandline", {
if (event.type == "blur") {
// prevent losing focus, there should be a better way, but it just didn't work otherwise
this.setTimeout(function () {
- if (this._commandShown() && event.originalTarget == this._commandWidget.inputField)
- this._commandWidget.inputField.focus();
+ if (this._commandShown() && event.originalTarget == this.widgets.command.inputField)
+ this.widgets.command.inputField.focus();
}, 0);
}
else if (event.type == "focus") {
- if (!this._commandShown() && event.target == this._commandWidget.inputField) {
+ if (!this._commandShown() && event.target == this.widgets.command.inputField) {
event.target.blur();
dactyl.beep();
}
@@ -703,22 +701,22 @@ const CommandLine = Module("commandline", {
if (event.type == "keypress") {
let key = events.toString(event);
if (events.isAcceptKey(key)) {
- let text = this._multilineInputWidget.value.substr(0, this._multilineInputWidget.selectionStart);
+ let text = this.widgets.multilineInput.value.substr(0, this.widgets.multilineInput.selectionStart);
if (text.match(this._multilineRegexp)) {
text = text.replace(this._multilineRegexp, "");
modes.pop();
- this._multilineInputWidget.collapsed = true;
+ this.widgets.multilineInput.collapsed = true;
this._multilineCallback.call(this, text);
}
}
else if (events.isCancelKey(key)) {
modes.pop();
- this._multilineInputWidget.collapsed = true;
+ this.widgets.multilineInput.collapsed = true;
}
}
else if (event.type == "blur") {
if (modes.extended & modes.INPUT_MULTILINE)
- this.setTimeout(function () { this._multilineInputWidget.inputField.focus(); }, 0);
+ this.setTimeout(function () { this.widgets.multilineInput.inputField.focus(); }, 0);
}
else if (event.type == "input")
this._autosizeMultilineInputWidget();
@@ -735,7 +733,7 @@ const CommandLine = Module("commandline", {
// FIXME: if 'more' is set and the MOW is not scrollable we should still
// allow a down motion after an up rather than closing
onMultilineOutputEvent: function onMultilineOutputEvent(event) {
- let win = this._multilineOutputWidget.contentWindow;
+ let win = this.widgets.multilineOutput.contentWindow;
let showMoreHelpPrompt = false;
let showMorePrompt = false;
@@ -934,7 +932,7 @@ const CommandLine = Module("commandline", {
},
getSpaceNeeded: function getSpaceNeeded() {
- let rect = this._commandlineWidget.getBoundingClientRect();
+ let rect = this.widgets.commandline.getBoundingClientRect();
let offset = rect.bottom - window.innerHeight;
return Math.max(0, offset);
},
@@ -953,7 +951,7 @@ const CommandLine = Module("commandline", {
return;
}
- let win = this._multilineOutputWidget.contentWindow;
+ let win = this.widgets.multilineOutput.contentWindow;
function isScrollable() !win.scrollMaxY == 0;
function atEnd() win.scrollY / win.scrollMaxY >= 1;
@@ -975,12 +973,12 @@ const CommandLine = Module("commandline", {
if (!open && this._outputContainer.collapsed)
return;
- let doc = this._multilineOutputWidget.contentDocument;
+ let doc = this.widgets.multilineOutput.contentDocument;
let availableHeight = config.outputHeight;
if (!this._outputContainer.collapsed)
availableHeight += parseFloat(this._outputContainer.height);
- doc.body.style.minWidth = this._commandlineWidget.scrollWidth + "px";
+ doc.body.style.minWidth = this.widgets.commandline.scrollWidth + "px";
this._outputContainer.height = Math.min(doc.height, availableHeight) + "px";
doc.body.style.minWidth = "";
this._outputContainer.collapsed = false;
@@ -1086,7 +1084,7 @@ const CommandLine = Module("commandline", {
while (true) {
this.index += diff;
if (this.index < 0 || this.index > this.store.length) {
- this.index = util.Math.constrain(this.index, 0, this.store.length);
+ this.index = Math.constrain(this.index, 0, this.store.length);
dactyl.beep();
// I don't know why this kludge is needed. It
// prevents the caret from moving to the end of
@@ -1146,8 +1144,8 @@ const CommandLine = Module("commandline", {
// Change the completion text.
// The second line is a hack to deal with some substring
// preview corner cases.
- commandline._commandWidget.value = this.prefix + completion + this.suffix;
- this.editor.selection.focusNode.textContent = commandline._commandWidget.value;
+ commandline.widgets.command.value = this.prefix + completion + this.suffix;
+ this.editor.selection.focusNode.textContent = commandline.widgets.command.value;
// Reset the caret to one position after the completion.
this.caret = this.prefix.length + completion.length;
@@ -1155,8 +1153,8 @@ const CommandLine = Module("commandline", {
get caret() this.editor.selection.focusOffset,
set caret(offset) {
- commandline._commandWidget.selectionStart = offset;
- commandline._commandWidget.selectionEnd = offset;
+ commandline.widgets.command.selectionStart = offset;
+ commandline.widgets.command.selectionEnd = offset;
},
get start() this.context.allItems.start,
@@ -1236,9 +1234,9 @@ const CommandLine = Module("commandline", {
}
else if (this.removeSubstring) {
let str = this.removeSubstring;
- let cmd = commandline._commandWidget.value;
+ let cmd = commandline.widgets.command.value;
if (cmd.substr(cmd.length - str.length) == str)
- commandline._commandWidget.value = cmd.substr(0, cmd.length - str.length);
+ commandline.widgets.command.value = cmd.substr(0, cmd.length - str.length);
}
delete this.removeSubstring;
},
@@ -1289,7 +1287,7 @@ const CommandLine = Module("commandline", {
idx = null;
break;
default:
- idx = util.Math.constrain(idx, 0, this.items.length - 1);
+ idx = Math.constrain(idx, 0, this.items.length - 1);
break;
}
@@ -1310,7 +1308,7 @@ const CommandLine = Module("commandline", {
for (let [, context] in Iterator(list)) {
function done() !(idx >= n + context.items.length || idx == -2 && !context.items.length);
while (context.incomplete && !done())
- dactyl.threadYield(false, true);
+ util.threadYield(false, true);
if (done())
break;
@@ -1369,7 +1367,7 @@ const CommandLine = Module("commandline", {
if (this.type.list)
this.itemList.show();
- this.wildIndex = util.Math.constrain(this.wildIndex + 1, 0, this.wildtypes.length - 1);
+ this.wildIndex = Math.constrain(this.wildIndex + 1, 0, this.wildtypes.length - 1);
this.preview();
commandline._statusTimer.tell();
@@ -1651,7 +1649,7 @@ const ItemList = Class("ItemList", {
let off = 0;
let end = this._startIndex + options["maxitems"];
function getRows(context) {
- function fix(n) util.Math.constrain(n, 0, len);
+ function fix(n) Math.constrain(n, 0, len);
let len = context.items.length;
let start = off;
end -= !!context.message + context.incomplete;
diff --git a/common/content/commands.js b/common/content/commands.js
index a3c81d97..1cda7784 100644
--- a/common/content/commands.js
+++ b/common/content/commands.js
@@ -315,7 +315,7 @@ const Commands = Module("commands", {
}
this._exCommands.push(command);
- for(let [,name] in Iterator(command.names))
+ for (let [,name] in Iterator(command.names))
this._exMap[name] = command;
return true;
@@ -765,9 +765,9 @@ const Commands = Module("commands", {
* any of the command's names.
*/
removeUserCommand: function (name) {
- for(let [,cmd] in Iterator(this._exCommands))
- if(cmd.user && cmd.hasName(name))
- for(let [,name] in Iterator(cmd.names))
+ for (let [,cmd] in Iterator(this._exCommands))
+ if (cmd.user && cmd.hasName(name))
+ for (let [,name] in Iterator(cmd.names))
delete this._exMap[name];
this._exCommands = this._exCommands.filter(function (cmd) !(cmd.user && cmd.hasName(name)));
},
@@ -858,23 +858,7 @@ const Commands = Module("commands", {
return [len - str.length, arg, quote];
}
}, {
- mappings: function () {
- mappings.add(config.browserModes,
- ["@:"], "Repeat the last Ex command",
- function (count) {
- if (commands.repeat) {
- for (let i in util.interruptibleRange(0, Math.max(count, 1), 100))
- dactyl.execute(commands.repeat);
- }
- else
- dactyl.echoerr("E30: No previous command line");
- },
- { count: true });
- },
-
completion: function () {
- JavaScript.setCompleter(this.get, [function () ([c.name, c.description] for (c in commands))]);
-
completion.command = function command(context) {
context.title = ["Command"];
context.keys = { text: "longNames", description: "description" };
@@ -1105,6 +1089,22 @@ const Commands = Module("commands", {
argCount: "1",
completer: function (context) completion.userCommand(context)
});
+ },
+ javascript: function () {
+ JavaScript.setCompleter(this.get, [function () ([c.name, c.description] for (c in commands))]);
+ },
+ mappings: function () {
+ mappings.add(config.browserModes,
+ ["@:"], "Repeat the last Ex command",
+ function (count) {
+ if (commands.repeat) {
+ for (let i in util.interruptibleRange(0, Math.max(count, 1), 100))
+ dactyl.execute(commands.repeat);
+ }
+ else
+ dactyl.echoerr("E30: No previous command line");
+ },
+ { count: true });
}
});
diff --git a/common/content/completion.js b/common/content/completion.js
index f902669b..9a9268a0 100755
--- a/common/content/completion.js
+++ b/common/content/completion.js
@@ -260,7 +260,7 @@ const CompletionContext = Class("CompletionContext", {
this._completions = items;
let self = this;
if (this.updateAsync && !this.noUpdate)
- dactyl.callInMainThread(function () { self.onUpdate.call(self); });
+ util.callInMainThread(function () { self.onUpdate.call(self); });
},
get createRow() this._createRow || template.completionRow, // XXX
@@ -326,7 +326,7 @@ const CompletionContext = Class("CompletionContext", {
this.cache.backgroundLock = lock;
this.incomplete = true;
let thread = this.getCache("backgroundThread", dactyl.newThread);
- dactyl.callAsync(thread, this, function () {
+ util.callAsync(thread, this, function () {
if (this.cache.backgroundLock != lock)
return;
let items = this.generate();
@@ -609,7 +609,7 @@ const CompletionContext = Class("CompletionContext", {
wait: function wait(interruptable, timeout) {
let end = Date.now() + timeout;
while (this.incomplete && (!timeout || Date.now() > end))
- dactyl.threadYield(false, interruptable);
+ util.threadYield(false, interruptable);
return this.incomplete;
}
}, {
@@ -668,7 +668,7 @@ const Completion = Module("completion", {
context = context.contexts["/list"];
context.wait();
- let list = template.commandOutput(
+ let list = template.commandOutput(commandline.command,
{ template.map(context.contextList.filter(function (c) c.hasItems),
function (context)
@@ -765,7 +765,7 @@ const Completion = Module("completion", {
commands.add(["contexts"],
"List the completion contexts used during completion of an ex command",
function (args) {
- commandline.echo(template.commandOutput(
+ commandline.echo(template.commandOutput(commandline.command,
{ template.completionRow(["Context", "Title"], "CompTitle") }
{ template.map(completion.contextList || [], function (item) template.completionRow(item, "CompItem")) }
diff --git a/common/content/configbase.js b/common/content/configbase.js
index e43033f9..9005f122 100644
--- a/common/content/configbase.js
+++ b/common/content/configbase.js
@@ -7,6 +7,15 @@
"use strict";
const ConfigBase = Class(ModuleBase, {
+ /**
+ * Called on dactyl startup to allow for any arbitrary application-specific
+ * initialization code. Must call superclass's init function.
+ */
+ init: function () {
+ highlight.styleableChrome = this.styleableChrome;
+ highlight.loadCSS(this.CSS);
+ },
+
/**
* @property {[["string", "string"]]} A sequence of names and descriptions
* of the autocommands available in this application. Primarily used
@@ -14,8 +23,8 @@ const ConfigBase = Class(ModuleBase, {
*/
autocommands: [],
- browser: window.gBrowser,
- tabbrowser: window.gBrowser,
+ get browser() window.gBrowser,
+ get tabbrowser() window.gBrowser,
get browserModes() [modes.NORMAL],
@@ -55,12 +64,6 @@ const ConfigBase = Class(ModuleBase, {
*/
hostApplication: null,
- /**
- * @property {function} Called on dactyl startup to allow for any
- * arbitrary application-specific initialization code.
- */
- init: function () {},
-
/**
* @property {Object} A map between key names for key events should be ignored,
* and a mask of the modes in which they should be ignored.
@@ -102,8 +105,229 @@ const ConfigBase = Class(ModuleBase, {
* @property {string} The leaf name of any temp files created by
* {@link io.createTempFile}.
*/
- get tempFile() this.name.toLowerCase() + ".tmp"
+ get tempFile() this.name.toLowerCase() + ".tmp",
+ /**
+ * @constant
+ * @property {string} The default highlighting rules. They have the
+ * form:
+ * rule ::= selector space space+ css
+ * selector ::= group
+ * | group "," css-selector
+ * | group "," css-selector "," scope
+ * group ::= groupname
+ * | groupname css-selector
+ */
+ //
+ CSS: * font-family: monospace; padding: 1px;
+ CmdOutput white-space: pre;
+
+ CompGroup
+ CompGroup:not(:first-of-type) margin-top: .5em;
+ CompTitle color: magenta; background: white; font-weight: bold;
+ CompTitle>* padding: 0 .5ex;
+ CompMsg font-style: italic; margin-left: 16px;
+ CompItem
+ CompItem[selected] background: yellow;
+ CompItem>* padding: 0 .5ex;
+ CompIcon width: 16px; min-width: 16px; display: inline-block; margin-right: .5ex;
+ CompIcon>img max-width: 16px; max-height: 16px; vertical-align: middle;
+ CompResult width: 45%; overflow: hidden;
+ CompDesc color: gray; width: 50%;
+ CompLess text-align: center; height: 0; line-height: .5ex; padding-top: 1ex;
+ CompLess::after content: "\2303" /* Unicode up arrowhead */
+ CompMore text-align: center; height: .5ex; line-height: .5ex; margin-bottom: -.5ex;
+ CompMore::after content: "\2304" /* Unicode down arrowhead */
+
+ Gradient height: 1px; margin-bottom: -1px; margin-top: -1px;
+ GradientLeft background-color: magenta;
+ GradientRight background-color: white;
+
+ Indicator color: blue;
+ Filter font-weight: bold;
+
+ Keyword color: red;
+ Tag color: blue;
+
+ LineNr color: orange; background: white;
+ Question color: green; background: white; font-weight: bold;
+
+ StatusLine color: white; background: black;
+ StatusLineBroken color: black; background: #FFa0a0 /* light-red */
+ StatusLineSecure color: black; background: #a0a0FF /* light-blue */
+ StatusLineExtended color: black; background: #a0FFa0 /* light-green */
+
+ TabClose,.tab-close-button
+ TabIcon,.tab-icon
+ TabText,.tab-text
+ TabNumber font-weight: bold; margin: 0px; padding-right: .3ex;
+ TabIconNumber {
+ font-weight: bold;
+ color: white;
+ text-align: center;
+ text-shadow: black -1px 0 1px, black 0 1px 1px, black 1px 0 1px, black 0 -1px 1px;
+ }
+
+ Title color: magenta; background: white; font-weight: bold;
+ URL text-decoration: none; color: green; background: inherit;
+ URL:hover text-decoration: underline; cursor: pointer;
+
+ FrameIndicator,,* {
+ background-color: red;
+ opacity: 0.5;
+ z-index: 999;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ }
+
+ Bell border: none; background-color: black;
+ Hint,,* {
+ font-family: monospace;
+ font-size: 10px;
+ font-weight: bold;
+ color: white;
+ background-color: red;
+ border-color: ButtonShadow;
+ border-width: 0px;
+ border-style: solid;
+ padding: 0px 1px 0px 1px;
+ }
+ Hint::after,,* content: attr(number);
+ HintElem,,* background-color: yellow; color: black;
+ HintActive,,* background-color: #88FF00; color: black;
+ HintImage,,* opacity: .5;
+
+ Help font-size: 8pt; line-height: 1.4em; font-family: -moz-fixed;
+
+ HelpArg color: #6A97D4;
+ HelpOptionalArg color: #6A97D4;
+
+ HelpBody display: block; margin: 1em auto; max-width: 100ex;
+ HelpBorder,*,dactyl://help/* border-color: silver; border-width: 0px; border-style: solid;
+ HelpCode display: block; white-space: pre; margin-left: 2em; font-family: Terminus, Fixed, monospace;
+
+ HelpDefault margin-right: 1ex; white-space: pre;
+
+ HelpDescription display: block;
+ HelpEm,html|em,dactyl://help/* font-weight: bold; font-style: normal;
+
+ HelpEx display: inline-block; color: #527BBD; font-weight: bold;
+
+ HelpExample display: block; margin: 1em 0;
+ HelpExample::before content: "Example: "; font-weight: bold;
+
+ HelpInfo display: block; width: 20em; margin-left: auto;
+ HelpInfoLabel display: inline-block; width: 6em; color: magenta; font-weight: bold; vertical-align: text-top;
+ HelpInfoValue display: inline-block; width: 14em; text-decoration: none; vertical-align: text-top;
+
+ HelpItem display: block; margin: 1em 1em 1em 10em; clear: both;
+
+ HelpKey color: #102663;
+
+ HelpLink,html|a,dactyl://help/* text-decoration: none;
+ HelpLink[href]:hover text-decoration: underline;
+
+ HelpList,html|ul,dactyl://help/* display: block; list-style: outside disc;
+ HelpOrderedList,html|ol,dactyl://help/* display: block; list-style: outside decimal;
+ HelpListItem,html|li,dactyl://help/* display: list-item;
+
+ HelpNote color: red; font-weight: bold;
+
+ HelpOpt color: #106326;
+ HelpOptInfo display: inline-block; margin-bottom: 1ex;
+
+ HelpParagraph,html|p,dactyl://help/* display: block; margin: 1em 0em;
+ HelpParagraph:first-child margin-top: 0;
+ HelpSpec display: block; margin-left: -10em; float: left; clear: left; color: #527BBD;
+
+ HelpString display: inline-block; color: green; font-weight: normal; vertical-align: text-top;
+ HelpString::before content: '"';
+ HelpString::after content: '"';
+ HelpString[delim]::before content: attr(delim);
+ HelpString[delim]::after content: attr(delim);
+
+ HelpHead,html|h1,dactyl://help/* {
+ display: block;
+ margin: 1em 0;
+ padding-bottom: .2ex;
+ border-bottom-width: 1px;
+ font-size: 2em;
+ font-weight: bold;
+ color: #527BBD;
+ clear: both;
+ }
+ HelpSubhead,html|h2,dactyl://help/* {
+ display: block;
+ margin: 1em 0;
+ padding-bottom: .2ex;
+ border-bottom-width: 1px;
+ font-size: 1.2em;
+ font-weight: bold;
+ color: #527BBD;
+ clear: both;
+ }
+ HelpSubsubhead,html|h3,dactyl://help/* {
+ display: block;
+ margin: 1em 0;
+ padding-bottom: .2ex;
+ font-size: 1.1em;
+ font-weight: bold;
+ color: #527BBD;
+ clear: both;
+ }
+
+ HelpTOC
+ HelpTOC>ol ol margin-left: -1em;
+
+ HelpTab,html|dl,dactyl://help/* display: table; width: 100%; margin: 1em 0; border-bottom-width: 1px; border-top-width: 1px; padding: .5ex 0; table-layout: fixed;
+ HelpTabColumn,html|column,dactyl://help/* display: table-column;
+ HelpTabColumn:first-child width: 25%;
+ HelpTabTitle,html|dt,dactyl://help/* display: table-cell; padding: .1ex 1ex; font-weight: bold;
+ HelpTabDescription,html|dd,dactyl://help/* display: table-cell; padding: .1ex 1ex; border-width: 0px;
+ HelpTabRow,html|dl>html|tr,dactyl://help/* display: table-row;
+
+ HelpTag display: inline-block; color: #527BBD; margin-left: 1ex; font-size: 8pt; font-weight: bold;
+ HelpTags display: block; float: right; clear: right;
+ HelpTopic color: #102663;
+ HelpType margin-right: 2ex;
+
+ HelpWarning color: red; font-weight: bold;
+
+ Logo
+
+ Search,,* {
+ font-size: inherit;
+ padding: 0;
+ color: black;
+ background-color: yellow;
+ }
+ ]]>.toString()
});
// vim: set fdm=marker sw=4 ts=4 et:
diff --git a/common/content/dactyl.js b/common/content/dactyl.js
index 26bb2461..320d6304 100644
--- a/common/content/dactyl.js
+++ b/common/content/dactyl.js
@@ -38,13 +38,6 @@ const Storage = Module("storage", {
}
});
-function Runnable(self, func, args) {
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIRunnable]),
- run: function () { func.apply(self, args || []); }
- };
-}
-
const FailedAssertion = Class("FailedAssertion", Error, {
init: function (message) {
this.message = message;
@@ -92,40 +85,6 @@ const Dactyl = Module("dactyl", {
/** @property {Element} The currently focused element. */
get focus() document.commandDispatcher.focusedElement,
- get extensions() {
- const rdf = services.get("rdf");
- const extensionManager = services.get("extensionManager");
-
- let extensions = extensionManager.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
-
- function getRdfProperty(item, property) {
- let resource = rdf.GetResource("urn:mozilla:item:" + item.id);
- let value = "";
-
- if (resource) {
- let target = extensionManager.datasource.GetTarget(resource,
- rdf.GetResource("http://www.mozilla.org/2004/em-rdf#" + property), true);
- if (target && target instanceof Ci.nsIRDFLiteral)
- value = target.Value;
- }
-
- return value;
- }
-
- //const Extension = Struct("id", "name", "description", "icon", "enabled", "version");
- return extensions.map(function (e) ({
- id: e.id,
- name: e.name,
- description: getRdfProperty(e, "description"),
- enabled: getRdfProperty(e, "isDisabled") != "true",
- icon: e.iconURL,
- options: getRdfProperty(e, "optionsURL"),
- version: e.version
- }));
- },
-
- getExtension: function (name) this.extensions.filter(function (e) e.name == name)[0],
-
// Global constants
CURRENT_TAB: [],
NEW_TAB: [],
@@ -183,7 +142,7 @@ const Dactyl = Module("dactyl", {
beep: function () {
// FIXME: popups clear the command line
if (options["visualbell"]) {
- dactyl.callInMainThread(function () {
+ util.callInMainThread(function () {
// flash the visual bell
let popup = document.getElementById("dactyl-visualbell");
let win = config.visualbellWindow;
@@ -204,45 +163,6 @@ const Dactyl = Module("dactyl", {
return false; // so you can do: if (...) return dactyl.beep();
},
- /**
- * Creates a new thread.
- */
- newThread: function () services.get("threadManager").newThread(0),
-
- /**
- * Calls a function asynchronously on a new thread.
- *
- * @param {nsIThread} thread The thread to call the function on. If no
- * thread is specified a new one is created.
- * @optional
- * @param {Object} self The 'this' object used when executing the
- * function.
- * @param {function} func The function to execute.
- *
- */
- callAsync: function (thread, self, func) {
- thread = thread || services.get("threadManager").newThread(0);
- thread.dispatch(Runnable(self, func, Array.slice(arguments, 3)), thread.DISPATCH_NORMAL);
- },
-
- /**
- * Calls a function synchronously on a new thread.
- *
- * NOTE: Be sure to call GUI related methods like alert() or dump()
- * ONLY in the main thread.
- *
- * @param {nsIThread} thread The thread to call the function on. If no
- * thread is specified a new one is created.
- * @optional
- * @param {function} func The function to execute.
- */
- callFunctionInThread: function (thread, func) {
- thread = thread || services.get("threadManager").newThread(0);
-
- // DISPATCH_SYNC is necessary, otherwise strange things will happen
- thread.dispatch(Runnable(null, func, Array.slice(arguments, 2)), thread.DISPATCH_SYNC);
- },
-
/**
* Prints a message to the console. If msg is an object it is
* pretty printed.
@@ -488,18 +408,6 @@ const Dactyl = Module("dactyl", {
*/
has: function (feature) config.features.indexOf(feature) >= 0,
- /**
- * Returns whether the host application has the specified extension
- * installed.
- *
- * @param {string} name The extension name.
- * @returns {boolean}
- */
- hasExtension: function (name) {
- let extensions = services.get("extensionManager").getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
- return extensions.some(function (e) e.name == name);
- },
-
/**
* Returns the URL of the specified help topic if it exists.
*
@@ -622,6 +530,99 @@ const Dactyl = Module("dactyl", {
}
},
+ exportHelp: function (path) {
+ const FILE = io.File(path);
+ const PATH = FILE.leafName.replace(/\..*/, "") + "/";
+ const TIME = Date.now();
+
+ dactyl.initHelp();
+ let zip = services.create("zipWriter");
+ zip.open(FILE, File.MODE_CREATE | File.MODE_WRONLY | File.MODE_TRUNCATE);
+ function addURIEntry(file, uri)
+ zip.addEntryChannel(PATH + file, TIME, 9,
+ services.get("io").newChannel(uri, null, null), false);
+ function addDataEntry(file, data) // Inideal to an extreme.
+ addURIEntry(file, "data:text/plain;charset=UTF-8," + encodeURI(data));
+
+ let empty = util.Array.toObject(
+ "area base basefont br col frame hr img input isindex link meta param"
+ .split(" ").map(Array.concat));
+
+ let chrome = {};
+ for (let [file,] in Iterator(services.get("dactyl:").FILE_MAP)) {
+ dactyl.open("dactyl://help/" + file);
+ dactyl.modules.events.waitForPageLoad();
+ let data = [
+ '\n',
+ '\n'
+ ];
+ function fix(node) {
+ switch(node.nodeType) {
+ case Node.ELEMENT_NODE:
+ if (node instanceof HTMLScriptElement)
+ return;
+
+ data.push("<"); data.push(node.localName);
+ if (node instanceof HTMLHtmlElement)
+ data.push(" xmlns=" + XHTML.uri.quote());
+
+ for (let { name: name, value: value } in util.Array.itervalues(node.attributes)) {
+ if (name == "dactyl:highlight") {
+ name = "class";
+ value = "hl-" + value;
+ }
+ if (name == "href") {
+ if (value.indexOf("dactyl://help-tag/") == 0)
+ value = services.get("io").newChannel(value, null, null).originalURI.path.substr(1);
+ if (!/[#\/]/.test(value))
+ value += ".xhtml";
+ }
+ if (name == "src" && value.indexOf(":") > 0) {
+ chrome[value] = value.replace(/.*\//, "");;
+ value = value.replace(/.*\//, "");
+ }
+ data.push(" ");
+ data.push(name);
+ data.push('="');
+ data.push(<>{value}>.toXMLString());
+ data.push('"')
+ }
+ if (node.localName in empty)
+ data.push(" />");
+ else {
+ data.push(">");
+ if (node instanceof HTMLHeadElement)
+ data.push(.toXMLString());
+ Array.map(node.childNodes, arguments.callee);
+ data.push(""); data.push(node.localName); data.push(">");
+ }
+ break;
+ case Node.TEXT_NODE:
+ data.push(<>{node.textContent}>.toXMLString());
+ }
+ }
+ fix(content.document.documentElement);
+ addDataEntry(file + ".xhtml", data.join(""));
+ }
+
+ let data = [h.selector.replace(/^\[.*?=(.*?)\]/, ".hl-$1").replace(/html\|/, "") +
+ "\t{" + h.value + "}"
+ for (h in highlight) if (/^Help|^Logo/.test(h.class))];
+
+ data = data.join("\n");
+ addDataEntry("help.css", data.replace(/chrome:[^ ")]+\//g, ""));
+
+ let re = /(chrome:[^ ");]+\/)([^ ");]+)/g;
+ while ((m = re.exec(data)))
+ chrome[m[0]] = m[2];
+
+ for (let [uri, leaf] in Iterator(chrome))
+ addURIEntry(leaf, uri);
+
+ zip.close();
+ },
+
/**
* Opens the help page containing the specified topic if it
* exists.
@@ -1016,34 +1017,6 @@ const Dactyl = Module("dactyl", {
return commands.parseArgs(cmdline, options, "*");
},
- sleep: function (delay) {
- let mainThread = services.get("threadManager").mainThread;
-
- let end = Date.now() + delay;
- while (Date.now() < end)
- mainThread.processNextEvent(true);
- return true;
- },
-
- callInMainThread: function (callback, self) {
- let mainThread = services.get("threadManager").mainThread;
- if (!services.get("threadManager").isMainThread)
- mainThread.dispatch(Runnable(self, callback), mainThread.DISPATCH_NORMAL);
- else
- callback.call(self);
- },
-
- threadYield: function (flush, interruptable) {
- let mainThread = services.get("threadManager").mainThread;
- dactyl.interrupted = false;
- do {
- mainThread.processNextEvent(!flush);
- if (dactyl.interrupted)
- throw new Error("Interrupted");
- }
- while (flush === true && mainThread.hasPendingEvents());
- },
-
variableReference: function (string) {
if (!string)
return [null, null, null];
@@ -1097,7 +1070,7 @@ const Dactyl = Module("dactyl", {
// return the platform normalized to Vim values
getPlatformFeature: function () {
- let platform = navigator.platform;
+ let platform = services.get("runtime").OS;
return /^Mac/.test(platform) ? "MacUnix" : platform == "Win32" ? "Win32" : "Unix";
},
@@ -1521,7 +1494,6 @@ const Dactyl = Module("dactyl", {
literal: 0
});
- // TODO: maybe indicate pending status too?
commands.add(["extens[ions]", "exts"],
"List available extensions",
function (args) {
@@ -1558,8 +1530,6 @@ const Dactyl = Module("dactyl", {
},
{ argCount: "?" });
- ///////////////////////////////////////////////////////////////////////////
-
commands.add(["exu[sage]"],
"List all Ex commands with a short description",
function (args) { Dactyl.showHelpIndex("ex-cmd-index", commands, args.bang); }, {
@@ -1726,7 +1696,7 @@ const Dactyl = Module("dactyl", {
else
totalUnits = "msec";
- let str = template.commandOutput(
+ let str = template.commandOutput(commandline.command,