mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-03-31 12:33:33 +02:00
Merge key-processing.
This commit is contained in:
@@ -9,11 +9,16 @@
|
|||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
var CommandWidgets = Class("CommandWidgets", {
|
var CommandWidgets = Class("CommandWidgets", {
|
||||||
init: function () {
|
depends: ["statusline"],
|
||||||
let _status = "dactyl-statusline-field-";
|
|
||||||
|
init: function init() {
|
||||||
|
let s = "dactyl-statusline-field-";
|
||||||
|
|
||||||
XML.ignoreWhitespace = true;
|
XML.ignoreWhitespace = true;
|
||||||
util.overlayWindow(window, {
|
util.overlayWindow(window, {
|
||||||
|
objects: {
|
||||||
|
eventTarget: commandline
|
||||||
|
},
|
||||||
append: <e4x xmlns={XUL} xmlns:dactyl={NS}>
|
append: <e4x xmlns={XUL} xmlns:dactyl={NS}>
|
||||||
<window id={document.documentElement.id}>
|
<window id={document.documentElement.id}>
|
||||||
<popupset>
|
<popupset>
|
||||||
@@ -39,16 +44,15 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
|
|
||||||
<vbox class="dactyl-container" id="dactyl-multiline-output-container" hidden="false" collapsed="true">
|
<vbox class="dactyl-container" id="dactyl-multiline-output-container" hidden="false" collapsed="true">
|
||||||
<iframe id="dactyl-multiline-output" src="dactyl://content/buffer.xhtml"
|
<iframe id="dactyl-multiline-output" src="dactyl://content/buffer.xhtml"
|
||||||
flex="1" hidden="false" collapsed="false"
|
flex="1" hidden="false" collapsed="false" contextmenu="dactyl-contextmenu"
|
||||||
contextmenu="dactyl-contextmenu"
|
highlight="Events" events="multilineOutputEvents" />
|
||||||
onclick="dactyl.modules.commandline.onMultilineOutputEvent(event)"/>
|
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
<vbox class="dactyl-container" hidden="false" collapsed="true">
|
<vbox class="dactyl-container" hidden="false" collapsed="true">
|
||||||
<iframe class="dactyl-completions" id="dactyl-completions-dactyl-commandline" src="dactyl://content/buffer.xhtml"
|
<iframe class="dactyl-completions" id="dactyl-completions-dactyl-commandline" src="dactyl://content/buffer.xhtml"
|
||||||
contextmenu="dactyl-contextmenu"
|
contextmenu="dactyl-contextmenu"
|
||||||
flex="1" hidden="false" collapsed="false"
|
flex="1" hidden="false" collapsed="false"
|
||||||
onclick="dactyl.modules.commandline.onMultilineOutputEvent(event)"/>
|
highlight="Events" events="multilineOutputEvents" />
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
<stack orient="horizontal" align="stretch" class="dactyl-container" id="dactyl-container" highlight="CmdLine CmdCmdLine">
|
<stack orient="horizontal" align="stretch" class="dactyl-container" id="dactyl-container" highlight="CmdLine CmdCmdLine">
|
||||||
@@ -59,30 +63,31 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
<hbox id="dactyl-commandline" hidden="false" class="dactyl-container" highlight="Normal CmdNormal" collapsed="true">
|
<hbox id="dactyl-commandline" hidden="false" class="dactyl-container" highlight="Normal CmdNormal" collapsed="true">
|
||||||
<label id="dactyl-commandline-prompt" class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/>
|
<label id="dactyl-commandline-prompt" class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/>
|
||||||
<textbox id="dactyl-commandline-command" class="dactyl-commandline-command plain" flex="1" type="input" timeout="100"
|
<textbox id="dactyl-commandline-command" class="dactyl-commandline-command plain" flex="1" type="input" timeout="100"
|
||||||
oninput="dactyl.modules.commandline.onEvent(event);"
|
highlight="Events" />
|
||||||
onkeyup="dactyl.modules.commandline.onEvent(event);"
|
|
||||||
onfocus="dactyl.modules.commandline.onEvent(event);"
|
|
||||||
onblur="dactyl.modules.commandline.onEvent(event);"/>
|
|
||||||
</hbox>
|
</hbox>
|
||||||
</stack>
|
</stack>
|
||||||
|
|
||||||
<vbox class="dactyl-container" hidden="false" collapsed="false" highlight="CmdLine">
|
<vbox class="dactyl-container" hidden="false" collapsed="false" highlight="CmdLine">
|
||||||
<textbox id="dactyl-multiline-input" class="plain" flex="1" rows="1" hidden="false" collapsed="true" multiline="true"
|
<textbox id="dactyl-multiline-input" class="plain" flex="1" rows="1" hidden="false" collapsed="true" multiline="true"
|
||||||
highlight="Normal"
|
highlight="Normal Events" events="multilineInputEvents" />
|
||||||
onkeypress="dactyl.modules.commandline.onMultilineInputEvent(event);"
|
|
||||||
oninput="dactyl.modules.commandline.onMultilineInputEvent(event);"
|
|
||||||
onblur="dactyl.modules.commandline.onMultilineInputEvent(event);"/>
|
|
||||||
</vbox>
|
</vbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
|
<stack id="dactyl-statusline-stack">
|
||||||
|
<hbox id={s + "commandline"} hidden="false" class="dactyl-container" highlight="Normal StatusNormal" collapsed="true">
|
||||||
|
<label id={s + "commandline-prompt"} class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/>
|
||||||
|
<textbox id={s + "commandline-command"} class="dactyl-commandline-command plain" flex="1" type="text" timeout="100"
|
||||||
|
highlight="Events" />
|
||||||
|
</hbox>
|
||||||
|
</stack>
|
||||||
</e4x>.elements(),
|
</e4x>.elements(),
|
||||||
|
|
||||||
before: <e4x xmlns={XUL} xmlns:dactyl={NS}>
|
before: <e4x xmlns={XUL} xmlns:dactyl={NS}>
|
||||||
<toolbar id={statusline.statusBar.id}>
|
<toolbar id={statusline.statusBar.id}>
|
||||||
<vbox id={"dactyl-completions-" + _status + "commandline-container"} class="dactyl-container" hidden="false" collapsed="true">
|
<vbox id={"dactyl-completions-" + s + "commandline-container"} class="dactyl-container" hidden="false" collapsed="true">
|
||||||
<iframe class="dactyl-completions" id={"dactyl-completions-" + _status + "commandline"} src="dactyl://content/buffer.xhtml"
|
<iframe class="dactyl-completions" id={"dactyl-completions-" + s + "commandline"} src="dactyl://content/buffer.xhtml"
|
||||||
contextmenu="dactyl-contextmenu"
|
contextmenu="dactyl-contextmenu" flex="1" hidden="false" collapsed="false"
|
||||||
flex="1" hidden="false" collapsed="false"
|
highlight="Events" events="multilineOutputEvents" />
|
||||||
onclick="dactyl.modules.commandline.onMultilineOutputEvent(event)"/>
|
|
||||||
</vbox>
|
</vbox>
|
||||||
</toolbar>
|
</toolbar>
|
||||||
</e4x>.elements()
|
</e4x>.elements()
|
||||||
@@ -171,7 +176,7 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
html|html > xul|scrollbar { visibility: collapse !important; }",
|
html|html > xul|scrollbar { visibility: collapse !important; }",
|
||||||
true);
|
true);
|
||||||
},
|
},
|
||||||
addElement: function (obj) {
|
addElement: function addElement(obj) {
|
||||||
const self = this;
|
const self = this;
|
||||||
this.elements[obj.name] = obj;
|
this.elements[obj.name] = obj;
|
||||||
|
|
||||||
@@ -185,13 +190,13 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
|
|
||||||
if (!(obj.noValue || obj.getValue))
|
if (!(obj.noValue || obj.getValue))
|
||||||
Object.defineProperty(this, obj.name, Modes.boundProperty({
|
Object.defineProperty(this, obj.name, Modes.boundProperty({
|
||||||
get: function () {
|
get: function get_widgetValue() {
|
||||||
let elem = self.getGroup(obj.name, obj.value)[obj.name];
|
let elem = self.getGroup(obj.name, obj.value)[obj.name];
|
||||||
if (obj.value != null)
|
if (obj.value != null)
|
||||||
return [obj.value[0], obj.get ? obj.get.call(this, elem) : elem.value];
|
return [obj.value[0], obj.get ? obj.get.call(this, elem) : elem.value];
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
set: function (val) {
|
set: function set_widgetValue(val) {
|
||||||
if (val != null && !isArray(val))
|
if (val != null && !isArray(val))
|
||||||
val = [obj.defaultGroup || "", val];
|
val = [obj.defaultGroup || "", val];
|
||||||
obj.value = val;
|
obj.value = val;
|
||||||
@@ -222,12 +227,12 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
.map(function (g) g + " " + nodeSet.group + g).join(" "));
|
.map(function (g) g + " " + nodeSet.group + g).join(" "));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getGroup: function (name, value) {
|
getGroup: function getgroup(name, value) {
|
||||||
if (!statusline.visible)
|
if (!statusline.visible)
|
||||||
return this.commandbar;
|
return this.commandbar;
|
||||||
return this.elements[name].getGroup.call(this, arguments.length > 1 ? value : this[name]);
|
return this.elements[name].getGroup.call(this, arguments.length > 1 ? value : this[name]);
|
||||||
},
|
},
|
||||||
updateVisibility: function () {
|
updateVisibility: function updateVisibility() {
|
||||||
for (let elem in values(this.elements))
|
for (let elem in values(this.elements))
|
||||||
if (elem.getGroup) {
|
if (elem.getGroup) {
|
||||||
let value = elem.getValue ? elem.getValue.call(this)
|
let value = elem.getValue ? elem.getValue.call(this)
|
||||||
@@ -260,10 +265,10 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
commandbar: Class.memoize(function () ({ group: "Cmd" })),
|
commandbar: Class.memoize(function () ({ group: "Cmd" })),
|
||||||
statusbar: Class.memoize(function () ({ group: "Status" })),
|
statusbar: Class.memoize(function () ({ group: "Status" })),
|
||||||
|
|
||||||
_whenReady: function (name, id, processor) {
|
_whenReady: function _whenReady(name, id, processor) {
|
||||||
Object.defineProperty(this, name, {
|
Object.defineProperty(this, name, {
|
||||||
configurable: true, enumerable: true,
|
configurable: true, enumerable: true,
|
||||||
get: function () {
|
get: function get_whenReady() {
|
||||||
let elem = document.getElementById(id);
|
let elem = document.getElementById(id);
|
||||||
while (elem.contentDocument.documentURI != elem.getAttribute("src") ||
|
while (elem.contentDocument.documentURI != elem.getAttribute("src") ||
|
||||||
["viewable", "complete"].indexOf(elem.contentDocument.readyState) < 0)
|
["viewable", "complete"].indexOf(elem.contentDocument.readyState) < 0)
|
||||||
@@ -295,7 +300,7 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
multilineInput: Class.memoize(function () document.getElementById("dactyl-multiline-input")),
|
multilineInput: Class.memoize(function () document.getElementById("dactyl-multiline-input")),
|
||||||
mowContainer: Class.memoize(function () document.getElementById("dactyl-multiline-output-container"))
|
mowContainer: Class.memoize(function () document.getElementById("dactyl-multiline-output-container"))
|
||||||
}, {
|
}, {
|
||||||
getEditor: function (elem) {
|
getEditor: function getEditor(elem) {
|
||||||
elem.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
|
elem.inputField.QueryInterface(Ci.nsIDOMNSEditableElement);
|
||||||
return elem;
|
return elem;
|
||||||
}
|
}
|
||||||
@@ -308,7 +313,7 @@ var CommandWidgets = Class("CommandWidgets", {
|
|||||||
* this class when the chrome is ready.
|
* this class when the chrome is ready.
|
||||||
*/
|
*/
|
||||||
var CommandLine = Module("commandline", {
|
var CommandLine = Module("commandline", {
|
||||||
init: function () {
|
init: function init() {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
this._callbacks = {};
|
this._callbacks = {};
|
||||||
@@ -422,23 +427,17 @@ var CommandLine = Module("commandline", {
|
|||||||
// way of calling "open"
|
// way of calling "open"
|
||||||
this.currentExtendedMode = null; // the extended mode which we last opened the command line for
|
this.currentExtendedMode = null; // the extended mode which we last opened the command line for
|
||||||
|
|
||||||
// save the arguments for the inputMultiline method which are needed in the event handler
|
|
||||||
this._multilineEnd = null;
|
|
||||||
this._multilineCallback = null;
|
|
||||||
|
|
||||||
this._input = {};
|
this._input = {};
|
||||||
|
|
||||||
this.registerCallback("submit", modes.EX, function (command) {
|
this.registerCallback("submit", modes.EX, function (command) {
|
||||||
try {
|
io.withSavedValues(["readHeredoc", "sourcing"], function () {
|
||||||
var readHeredoc = io.readHeredoc;
|
this.sourcing = { file: "[Command Line]", line: 1 };
|
||||||
io.readHeredoc = commandline.readHeredoc;
|
this.readHeredoc = commandline.readHeredoc;
|
||||||
commands.repeat = command;
|
commands.repeat = command;
|
||||||
commands.execute(command);
|
dactyl.execute(command);
|
||||||
}
|
|
||||||
finally {
|
|
||||||
io.readHeredoc = readHeredoc;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
this.registerCallback("complete", modes.EX, function (context) {
|
this.registerCallback("complete", modes.EX, function (context) {
|
||||||
context.fork("ex", 0, completion, "ex");
|
context.fork("ex", 0, completion, "ex");
|
||||||
});
|
});
|
||||||
@@ -489,7 +488,7 @@ var CommandLine = Module("commandline", {
|
|||||||
/**
|
/**
|
||||||
* Ensure that the multiline input widget is the correct size.
|
* Ensure that the multiline input widget is the correct size.
|
||||||
*/
|
*/
|
||||||
_autosizeMultilineInputWidget: function () {
|
_autosizeMultilineInputWidget: function _autosizeMultilineInputWidget() {
|
||||||
let lines = this.widgets.multilineInput.value.split("\n").length - 1;
|
let lines = this.widgets.multilineInput.value.split("\n").length - 1;
|
||||||
|
|
||||||
this.widgets.multilineInput.setAttribute("rows", Math.max(lines, 1));
|
this.widgets.multilineInput.setAttribute("rows", Math.max(lines, 1));
|
||||||
@@ -538,13 +537,13 @@ var CommandLine = Module("commandline", {
|
|||||||
// "change"
|
// "change"
|
||||||
// "cancel"
|
// "cancel"
|
||||||
// "complete"
|
// "complete"
|
||||||
registerCallback: function (type, mode, func) {
|
registerCallback: function registerCallback(type, mode, func) {
|
||||||
if (!(type in this._callbacks))
|
if (!(type in this._callbacks))
|
||||||
this._callbacks[type] = {};
|
this._callbacks[type] = {};
|
||||||
this._callbacks[type][mode] = func;
|
this._callbacks[type][mode] = func;
|
||||||
},
|
},
|
||||||
|
|
||||||
triggerCallback: function (type, mode) {
|
triggerCallback: function triggerCallback(type, mode) {
|
||||||
if (this._callbacks[type] && this._callbacks[type][mode])
|
if (this._callbacks[type] && this._callbacks[type][mode])
|
||||||
try {
|
try {
|
||||||
this._callbacks[type][mode].apply(this, Array.slice(arguments, 2));
|
this._callbacks[type][mode].apply(this, Array.slice(arguments, 2));
|
||||||
@@ -554,19 +553,22 @@ var CommandLine = Module("commandline", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
runSilently: function (func, self) {
|
runSilently: function runSilently(func, self) {
|
||||||
this.withSavedValues(["_silent"], function () {
|
this.withSavedValues(["_silent"], function () {
|
||||||
this._silent = true;
|
this._silent = true;
|
||||||
func.call(self);
|
func.call(self);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
hideCompletions: function () {
|
hideCompletions: function hideCompletions() {
|
||||||
for (let nodeSet in values([this.widgets.statusbar, this.widgets.commandbar]))
|
for (let nodeSet in values([this.widgets.statusbar, this.widgets.commandbar]))
|
||||||
if (nodeSet.commandline._completionList)
|
if (nodeSet.commandline._completionList)
|
||||||
nodeSet.commandline._completionList.hide();
|
nodeSet.commandline._completionList.hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_multilineEnd: Modes.boundProperty(),
|
||||||
|
_multilineCallback: Modes.boundProperty(),
|
||||||
|
|
||||||
currentExtendedMode: Modes.boundProperty(),
|
currentExtendedMode: Modes.boundProperty(),
|
||||||
_completions: Modes.boundProperty(),
|
_completions: Modes.boundProperty(),
|
||||||
_history: Modes.boundProperty(),
|
_history: Modes.boundProperty(),
|
||||||
@@ -575,10 +577,10 @@ var CommandLine = Module("commandline", {
|
|||||||
messages: Modes.boundProperty(),
|
messages: Modes.boundProperty(),
|
||||||
|
|
||||||
multilineInputVisible: Modes.boundProperty({
|
multilineInputVisible: Modes.boundProperty({
|
||||||
set: function (value) { this.widgets.multilineInput.collapsed = !value; }
|
set: function set_miwVisible(value) { this.widgets.multilineInput.collapsed = !value; }
|
||||||
}),
|
}),
|
||||||
multilineOutputVisible: Modes.boundProperty({
|
multilineOutputVisible: Modes.boundProperty({
|
||||||
set: function (value) {
|
set: function set_mowVisible(value) {
|
||||||
this.widgets.mowContainer.collapsed = !value;
|
this.widgets.mowContainer.collapsed = !value;
|
||||||
let elem = this.widgets.multilineOutput;
|
let elem = this.widgets.multilineOutput;
|
||||||
if (!value && elem && elem.contentWindow == document.commandDispatcher.focusedWindow)
|
if (!value && elem && elem.contentWindow == document.commandDispatcher.focusedWindow)
|
||||||
@@ -602,7 +604,7 @@ var CommandLine = Module("commandline", {
|
|||||||
this.currentExtendedMode = extendedMode || null;
|
this.currentExtendedMode = extendedMode || null;
|
||||||
modes.push(modes.COMMAND_LINE, this.currentExtendedMode, {
|
modes.push(modes.COMMAND_LINE, this.currentExtendedMode, {
|
||||||
autocomplete: cmd.length,
|
autocomplete: cmd.length,
|
||||||
onEvent: this.closure.onEvent,
|
onKeyPress: this.closure.onKeyPress,
|
||||||
history: (extendedMode || {}).params.history,
|
history: (extendedMode || {}).params.history,
|
||||||
leave: function (params) {
|
leave: function (params) {
|
||||||
if (params.pop)
|
if (params.pop)
|
||||||
@@ -671,7 +673,7 @@ var CommandLine = Module("commandline", {
|
|||||||
get lastCommand() this._lastCommand || this.command,
|
get lastCommand() this._lastCommand || this.command,
|
||||||
set lastCommand(val) { this._lastCommand = val },
|
set lastCommand(val) { this._lastCommand = val },
|
||||||
|
|
||||||
clear: function () {
|
clear: function clear() {
|
||||||
if (this.widgets.message && this.widgets.message[1] === this._lastClearable)
|
if (this.widgets.message && this.widgets.message[1] === this._lastClearable)
|
||||||
this.widgets.message = null;
|
this.widgets.message = null;
|
||||||
if (modes.main != modes.COMMAND_LINE)
|
if (modes.main != modes.COMMAND_LINE)
|
||||||
@@ -688,7 +690,7 @@ var CommandLine = Module("commandline", {
|
|||||||
*
|
*
|
||||||
* @param {XML} xml The output as an E4X XML object.
|
* @param {XML} xml The output as an E4X XML object.
|
||||||
*/
|
*/
|
||||||
commandOutput: function (xml) {
|
commandOutput: function commandOutput(xml) {
|
||||||
XML.ignoreWhitespace = false;
|
XML.ignoreWhitespace = false;
|
||||||
XML.prettyPrinting = false;
|
XML.prettyPrinting = false;
|
||||||
if (this.command)
|
if (this.command)
|
||||||
@@ -747,7 +749,7 @@ var CommandLine = Module("commandline", {
|
|||||||
this._startHints = false;
|
this._startHints = false;
|
||||||
if (modes.main != modes.OUTPUT_MULTILINE) {
|
if (modes.main != modes.OUTPUT_MULTILINE) {
|
||||||
modes.push(modes.OUTPUT_MULTILINE, null, {
|
modes.push(modes.OUTPUT_MULTILINE, null, {
|
||||||
onEvent: this.closure.onMultilineOutputEvent,
|
onKeyPress: this.closure.onMOWKeyPress,
|
||||||
leave: this.closure(function leave(stack) {
|
leave: this.closure(function leave(stack) {
|
||||||
if (stack.pop)
|
if (stack.pop)
|
||||||
for (let message in values(this.messages))
|
for (let message in values(this.messages))
|
||||||
@@ -896,18 +898,17 @@ var CommandLine = Module("commandline", {
|
|||||||
*/
|
*/
|
||||||
input: function _input(prompt, callback, extra) {
|
input: function _input(prompt, callback, extra) {
|
||||||
extra = extra || {};
|
extra = extra || {};
|
||||||
let closure = extra.closure || extra;
|
|
||||||
|
|
||||||
this._input = {
|
this._input = {
|
||||||
submit: callback || closure.onAccept,
|
submit: callback || extra.onAccept,
|
||||||
change: closure.onChange,
|
change: extra.onChange,
|
||||||
complete: closure.completer,
|
complete: extra.completer,
|
||||||
cancel: closure.onCancel
|
cancel: extra.onCancel
|
||||||
};
|
};
|
||||||
|
|
||||||
modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended,
|
modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended,
|
||||||
update(Object.create(extra), {
|
update(Object.create(extra), {
|
||||||
onEvent: closure.onEvent || this.closure.onEvent,
|
onKeyPress: extra.onKeyPress || this.closure.onKeyPress,
|
||||||
leave: function leave(stack) {
|
leave: function leave(stack) {
|
||||||
commandline.leave(stack);
|
commandline.leave(stack);
|
||||||
leave.supercall(extra, stack);
|
leave.supercall(extra, stack);
|
||||||
@@ -923,12 +924,10 @@ var CommandLine = Module("commandline", {
|
|||||||
this.enter();
|
this.enter();
|
||||||
},
|
},
|
||||||
|
|
||||||
readHeredoc: function (end) {
|
readHeredoc: function readHeredoc(end) {
|
||||||
let args;
|
let args;
|
||||||
commandline.inputMultiline(end,
|
commandline.inputMultiline(end, function (res) { args = res; });
|
||||||
function (res) { args = res; });
|
util.waitFor(function () args !== undefined);
|
||||||
while (args === undefined)
|
|
||||||
util.threadYield(true);
|
|
||||||
return args;
|
return args;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -943,11 +942,13 @@ var CommandLine = Module("commandline", {
|
|||||||
// FIXME: Buggy, especially when pasting.
|
// FIXME: Buggy, especially when pasting.
|
||||||
inputMultiline: function inputMultiline(end, callbackFunc) {
|
inputMultiline: function inputMultiline(end, callbackFunc) {
|
||||||
let cmd = this.command;
|
let cmd = this.command;
|
||||||
modes.push(modes.COMMAND_LINE, modes.INPUT_MULTILINE);
|
modes.push(modes.COMMAND_LINE, modes.INPUT_MULTILINE, {
|
||||||
|
keyModes: [modes.INPUT_MULTILINE]
|
||||||
|
});
|
||||||
if (cmd != false)
|
if (cmd != false)
|
||||||
this._echoLine(cmd, this.HL_NORMAL);
|
this._echoLine(cmd, this.HL_NORMAL);
|
||||||
|
|
||||||
// save the arguments, they are needed in the event handler onEvent
|
// save the arguments, they are needed in the event handler onKeyPress
|
||||||
this._multilineEnd = "\n" + end + "\n";
|
this._multilineEnd = "\n" + end + "\n";
|
||||||
this._multilineCallback = callbackFunc;
|
this._multilineCallback = callbackFunc;
|
||||||
|
|
||||||
@@ -968,7 +969,6 @@ var CommandLine = Module("commandline", {
|
|||||||
|
|
||||||
for (let node in array.iterValues(event.target.children)) {
|
for (let node in array.iterValues(event.target.children)) {
|
||||||
let group = node.getAttributeNS(NS, "group");
|
let group = node.getAttributeNS(NS, "group");
|
||||||
util.dump(node, group, group && !group.split(/\s+/).every(function (g) enabled[g]));
|
|
||||||
node.hidden = group && !group.split(/\s+/).every(function (g) enabled[g]);
|
node.hidden = group && !group.split(/\s+/).every(function (g) enabled[g]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -978,87 +978,36 @@ var CommandLine = Module("commandline", {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
onKeyPress: function onKeyPress(event) {
|
||||||
* Handles all command-line events. All key events are passed here when
|
let key = events.toString(event);
|
||||||
* COMMAND_LINE mode is active, as well as all input, keyup, focus, and
|
if (this._completions)
|
||||||
* blur events sent to the command-line XUL element.
|
this._completions.previewClear();
|
||||||
*
|
|
||||||
* @param {Event} event
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
onEvent: function onEvent(event) {
|
|
||||||
const KILL = false, PASS = true;
|
|
||||||
|
|
||||||
try {
|
return true; /* Pass event */
|
||||||
let command = this.command;
|
},
|
||||||
|
|
||||||
if (event.type == "blur") {
|
events: {
|
||||||
|
blur: function onBlur(event) {
|
||||||
this.timeout(function () {
|
this.timeout(function () {
|
||||||
if (this.commandVisible && event.originalTarget == this.widgets.active.command.inputField)
|
if (this.commandVisible && event.originalTarget == this.widgets.active.command.inputField)
|
||||||
dactyl.focus(this.widgets.active.command.inputField);
|
dactyl.focus(this.widgets.active.command.inputField);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
else if (event.type == "focus") {
|
focus: function onFocus(event) {
|
||||||
if (!this.commandVisible && event.target == this.widgets.active.command.inputField) {
|
if (!this.commandVisible && event.target == this.widgets.active.command.inputField) {
|
||||||
event.target.blur();
|
event.target.blur();
|
||||||
dactyl.beep();
|
dactyl.beep();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
else if (event.type == "input") {
|
input: function onInput(event) {
|
||||||
this.resetCompletions();
|
this.resetCompletions();
|
||||||
commandline.triggerCallback("change", this.currentExtendedMode, command);
|
this.triggerCallback("change", this.currentExtendedMode, this.command);
|
||||||
}
|
},
|
||||||
else if (event.type == "keypress") {
|
keyup: function onKeyUp(event) {
|
||||||
let key = events.toString(event);
|
let key = events.toString(event);
|
||||||
if (this._completions)
|
if (/-?Tab>$/.test(key))
|
||||||
this._completions.previewClear();
|
|
||||||
if (!this.currentExtendedMode)
|
|
||||||
return PASS;
|
|
||||||
|
|
||||||
// user pressed <Enter> to carry out a command
|
|
||||||
// user pressing <Esc> is handled in the global onEscape
|
|
||||||
// FIXME: <Esc> should trigger "cancel" event
|
|
||||||
if (events.isAcceptKey(key)) {
|
|
||||||
this._keepCommand = userContext.hidden_option_command_afterimage;
|
|
||||||
let mode = this.currentExtendedMode;
|
|
||||||
this.currentExtendedMode = null; // Don't let modes.pop trigger "cancel"
|
|
||||||
modes.pop();
|
|
||||||
commandline.triggerCallback("submit", mode, command);
|
|
||||||
}
|
|
||||||
// user pressed <Up> or <Down> arrow to cycle history completion
|
|
||||||
else if (/^<(Up|Down|S-Up|S-Down)>$/.test(key)) {
|
|
||||||
dactyl.assert(this._history);
|
|
||||||
this._history.select(/Up/.test(key), !/S-/.test(key));
|
|
||||||
return KILL;
|
|
||||||
}
|
|
||||||
// user pressed <Tab> to get completions of a command
|
|
||||||
else if (/^<(?:A-)?(?:S-)?Tab>$/.test(key)) {
|
|
||||||
this._tabTimer.tell(event);
|
|
||||||
return KILL;
|
|
||||||
}
|
|
||||||
else if (key == "<BS>") {
|
|
||||||
// reset the tab completion
|
|
||||||
//this.resetCompletions();
|
|
||||||
|
|
||||||
// and blur the command line if there is no text left
|
|
||||||
if (command.length == 0) {
|
|
||||||
commandline.triggerCallback("cancel", this.currentExtendedMode);
|
|
||||||
modes.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// allow this event to be handled by the host app
|
|
||||||
return PASS;
|
|
||||||
}
|
|
||||||
else if (event.type == "keyup") {
|
|
||||||
let key = events.toString(event);
|
|
||||||
if (/^<(?:A-)?(?:S-)?Tab>$/.test(key))
|
|
||||||
this._tabTimer.flush();
|
this._tabTimer.flush();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
dactyl.reportError(e, true);
|
|
||||||
}
|
|
||||||
return PASS;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1067,97 +1016,62 @@ var CommandLine = Module("commandline", {
|
|||||||
*
|
*
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
onMultilineInputEvent: function onMultilineInputEvent(event) {
|
multilineInputEvents: {
|
||||||
const KILL = false, PASS = true;
|
blur: function onBlur(event) {
|
||||||
|
|
||||||
if (event.type == "keypress") {
|
|
||||||
let key = events.toString(event);
|
|
||||||
if (events.isAcceptKey(key)) {
|
|
||||||
let text = "\n" + this.widgets.multilineInput.value.substr(0, this.widgets.multilineInput.selectionStart) + "\n";
|
|
||||||
let index = text.indexOf(this._multilineEnd);
|
|
||||||
if (index >= 0) {
|
|
||||||
text = text.substring(1, index);
|
|
||||||
let callback = this._multilineCallback;
|
|
||||||
modes.pop();
|
|
||||||
callback.call(this, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (events.isCancelKey(key)) {
|
|
||||||
modes.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event.type == "blur") {
|
|
||||||
if (modes.extended & modes.INPUT_MULTILINE)
|
if (modes.extended & modes.INPUT_MULTILINE)
|
||||||
this.timeout(function () { dactyl.focus(this.widgets.multilineInput.inputField); }, 0);
|
this.timeout(function () {
|
||||||
}
|
dactyl.focus(this.widgets.multilineInput.inputField);
|
||||||
else if (event.type == "input")
|
});
|
||||||
|
},
|
||||||
|
input: function onInput(event) {
|
||||||
this._autosizeMultilineInputWidget();
|
this._autosizeMultilineInputWidget();
|
||||||
return PASS;
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
multilineOutputEvents: {
|
||||||
* Handle events when we are in multi-line output mode, these come from
|
click: function onClick(event) {
|
||||||
* dactyl when modes.extended & modes.OUTPUT_MULTILINE and also from
|
if (event.getPreventDefault())
|
||||||
* #dactyl-multiline-output in the XUL.
|
return;
|
||||||
*
|
|
||||||
* @param {Event} event
|
|
||||||
*/
|
|
||||||
// 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) {
|
|
||||||
try {
|
|
||||||
const KILL = false, PASS = true;
|
|
||||||
|
|
||||||
let win = this.widgets.multilineOutput.contentWindow;
|
|
||||||
let elem = win.document.documentElement;
|
|
||||||
|
|
||||||
let key = events.toString(event);
|
|
||||||
|
|
||||||
const openLink = function openLink(where) {
|
const openLink = function openLink(where) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
dactyl.open(event.target.href, where);
|
dactyl.open(event.target.href, where);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Wouldn't multiple handlers be cleaner? --djk
|
if (event.target instanceof HTMLAnchorElement)
|
||||||
if (event.type == "click" && event.target instanceof HTMLAnchorElement) {
|
switch (events.toString(event)) {
|
||||||
|
|
||||||
if (event.getPreventDefault())
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case "<LeftMouse>":
|
case "<LeftMouse>":
|
||||||
event.preventDefault();
|
|
||||||
openLink(dactyl.CURRENT_TAB);
|
openLink(dactyl.CURRENT_TAB);
|
||||||
return KILL;
|
break;
|
||||||
case "<MiddleMouse>":
|
case "<MiddleMouse>":
|
||||||
case "<C-LeftMouse>":
|
case "<C-LeftMouse>":
|
||||||
case "<C-M-LeftMouse>":
|
case "<C-M-LeftMouse>":
|
||||||
openLink({ where: dactyl.NEW_TAB, background: true });
|
openLink({ where: dactyl.NEW_TAB, background: true });
|
||||||
return KILL;
|
break;
|
||||||
case "<S-MiddleMouse>":
|
case "<S-MiddleMouse>":
|
||||||
case "<C-S-LeftMouse>":
|
case "<C-S-LeftMouse>":
|
||||||
case "<C-M-S-LeftMouse>":
|
case "<C-M-S-LeftMouse>":
|
||||||
openLink({ where: dactyl.NEW_TAB, background: false });
|
openLink({ where: dactyl.NEW_TAB, background: false });
|
||||||
return KILL;
|
break;
|
||||||
case "<S-LeftMouse>":
|
case "<S-LeftMouse>":
|
||||||
openLink(dactyl.NEW_WINDOW);
|
openLink(dactyl.NEW_WINDOW);
|
||||||
return KILL;
|
break;
|
||||||
}
|
}
|
||||||
return PASS;
|
},
|
||||||
|
unload: function onUnload(event) {
|
||||||
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
if (event instanceof MouseEvent)
|
onMOWKeyPress: function onMOWKeyPress(event) {
|
||||||
return KILL;
|
const KILL = false, PASS = true;
|
||||||
|
|
||||||
if (!options["more"] || !mow.isScrollable(1)) {
|
if (options["more"] && mow.isScrollable(1))
|
||||||
modes.pop();
|
|
||||||
events.feedkeys(key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
commandline.updateMorePrompt(false, true);
|
commandline.updateMorePrompt(false, true);
|
||||||
}
|
else {
|
||||||
catch (e) {
|
modes.pop();
|
||||||
util.reportError(e);
|
events.feedkeys(events.toString(event));
|
||||||
|
return KILL;
|
||||||
}
|
}
|
||||||
return PASS;
|
return PASS;
|
||||||
},
|
},
|
||||||
@@ -1226,7 +1140,7 @@ var CommandLine = Module("commandline", {
|
|||||||
this._history.reset();
|
this._history.reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
withOutputToString: function (fn, self) {
|
withOutputToString: function withOutputToString(fn, self) {
|
||||||
dactyl.registerObserver("echoLine", observe, true);
|
dactyl.registerObserver("echoLine", observe, true);
|
||||||
dactyl.registerObserver("echoMultiline", observe, true);
|
dactyl.registerObserver("echoMultiline", observe, true);
|
||||||
|
|
||||||
@@ -1249,7 +1163,7 @@ var CommandLine = Module("commandline", {
|
|||||||
* @param {string} mode The mode for which we need history.
|
* @param {string} mode The mode for which we need history.
|
||||||
*/
|
*/
|
||||||
History: Class("History", {
|
History: Class("History", {
|
||||||
init: function (inputField, mode) {
|
init: function init(inputField, mode) {
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
this.input = inputField;
|
this.input = inputField;
|
||||||
this.reset();
|
this.reset();
|
||||||
@@ -1259,14 +1173,14 @@ var CommandLine = Module("commandline", {
|
|||||||
/**
|
/**
|
||||||
* Reset the history index to the first entry.
|
* Reset the history index to the first entry.
|
||||||
*/
|
*/
|
||||||
reset: function () {
|
reset: function reset() {
|
||||||
this.index = null;
|
this.index = null;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Save the last entry to the permanent store. All duplicate entries
|
* Save the last entry to the permanent store. All duplicate entries
|
||||||
* are removed and the list is truncated, if necessary.
|
* are removed and the list is truncated, if necessary.
|
||||||
*/
|
*/
|
||||||
save: function () {
|
save: function save() {
|
||||||
if (events.feedingKeys)
|
if (events.feedingKeys)
|
||||||
return;
|
return;
|
||||||
let str = this.input.value;
|
let str = this.input.value;
|
||||||
@@ -1285,7 +1199,7 @@ var CommandLine = Module("commandline", {
|
|||||||
* @property {function} Returns whether a data item should be
|
* @property {function} Returns whether a data item should be
|
||||||
* considered private.
|
* considered private.
|
||||||
*/
|
*/
|
||||||
checkPrivate: function (str) {
|
checkPrivate: function checkPrivate(str) {
|
||||||
// Not really the ideal place for this check.
|
// Not really the ideal place for this check.
|
||||||
if (this.mode == "command")
|
if (this.mode == "command")
|
||||||
return commands.hasPrivateData(str);
|
return commands.hasPrivateData(str);
|
||||||
@@ -1296,7 +1210,8 @@ var CommandLine = Module("commandline", {
|
|||||||
*
|
*
|
||||||
* @param {string} val The new value.
|
* @param {string} val The new value.
|
||||||
*/
|
*/
|
||||||
replace: function (val) {
|
replace: function replace(val) {
|
||||||
|
delete this.input.dactylKeyPress;
|
||||||
this.input.value = val;
|
this.input.value = val;
|
||||||
commandline.triggerCallback("change", commandline.currentExtendedMode, val, "history");
|
commandline.triggerCallback("change", commandline.currentExtendedMode, val, "history");
|
||||||
},
|
},
|
||||||
@@ -1308,7 +1223,7 @@ var CommandLine = Module("commandline", {
|
|||||||
* @param {boolean} matchCurrent Search for matches starting
|
* @param {boolean} matchCurrent Search for matches starting
|
||||||
* with the current input value.
|
* with the current input value.
|
||||||
*/
|
*/
|
||||||
select: function (backward, matchCurrent) {
|
select: function select(backward, matchCurrent) {
|
||||||
// always reset the tab completion if we use up/down keys
|
// always reset the tab completion if we use up/down keys
|
||||||
if (commandline._completions)
|
if (commandline._completions)
|
||||||
commandline._completions.reset();
|
commandline._completions.reset();
|
||||||
@@ -1358,10 +1273,11 @@ var CommandLine = Module("commandline", {
|
|||||||
* @param {Object} input
|
* @param {Object} input
|
||||||
*/
|
*/
|
||||||
Completions: Class("Completions", {
|
Completions: Class("Completions", {
|
||||||
init: function (input) {
|
init: function init(input) {
|
||||||
this.context = CompletionContext(input.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
|
this.context = CompletionContext(input.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
|
||||||
this.context.onUpdate = this.closure._reset;
|
this.context.onUpdate = this.closure._reset;
|
||||||
this.editor = input.editor;
|
this.editor = input.editor;
|
||||||
|
this.input = input;
|
||||||
this.selected = null;
|
this.selected = null;
|
||||||
this.wildmode = options.get("wildmode");
|
this.wildmode = options.get("wildmode");
|
||||||
this.wildtypes = this.wildmode.value;
|
this.wildtypes = this.wildmode.value;
|
||||||
@@ -1392,6 +1308,8 @@ var CommandLine = Module("commandline", {
|
|||||||
// Reset the caret to one position after the completion.
|
// Reset the caret to one position after the completion.
|
||||||
this.caret = this.prefix.length + completion.length;
|
this.caret = this.prefix.length + completion.length;
|
||||||
this._caret = this.caret;
|
this._caret = this.caret;
|
||||||
|
|
||||||
|
delete this.input.dactylKeyPress;
|
||||||
},
|
},
|
||||||
|
|
||||||
get caret() this.editor.selection.getRangeAt(0).startOffset,
|
get caret() this.editor.selection.getRangeAt(0).startOffset,
|
||||||
@@ -1417,7 +1335,7 @@ var CommandLine = Module("commandline", {
|
|||||||
this.wildIndex = 0;
|
this.wildIndex = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
haveType: function (type)
|
haveType: function haveType(type)
|
||||||
this.wildmode.checkHas(this.wildtype, type == "first" ? "" : type),
|
this.wildmode.checkHas(this.wildtype, type == "first" ? "" : type),
|
||||||
|
|
||||||
preview: function preview() {
|
preview: function preview() {
|
||||||
@@ -1644,7 +1562,7 @@ var CommandLine = Module("commandline", {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
commands: function () {
|
commands: function init_commands() {
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
name: "ec[ho]",
|
name: "ec[ho]",
|
||||||
@@ -1705,7 +1623,40 @@ var CommandLine = Module("commandline", {
|
|||||||
subCommand: 0
|
subCommand: 0
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
mappings: function () {
|
mappings: function init_mappings() {
|
||||||
|
|
||||||
|
mappings.add([modes.COMMAND],
|
||||||
|
[":"], "Enter command-line mode",
|
||||||
|
function () { commandline.open(":", "", modes.EX); });
|
||||||
|
|
||||||
|
mappings.add([modes.COMMAND],
|
||||||
|
["g<lt>"], "Redisplay the last command output",
|
||||||
|
function () {
|
||||||
|
dactyl.assert(commandline._lastMowOutput, "No previous command output");
|
||||||
|
commandline._echoMultiline(commandline._lastMowOutput, commandline.HL_NORMAL);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
mappings.add([modes.INPUT_MULTILINE],
|
||||||
|
["<Return>", "<C-j>", "<C-m>"], "Begin a new line",
|
||||||
|
function (args) {
|
||||||
|
let text = "\n" + commandline.widgets.multilineInput
|
||||||
|
.value.substr(0, commandline.widgets.multilineInput.selectionStart)
|
||||||
|
+ "\n";
|
||||||
|
|
||||||
|
let index = text.indexOf(commandline._multilineEnd);
|
||||||
|
if (index >= 0) {
|
||||||
|
text = text.substring(1, index);
|
||||||
|
let callback = commandline._multilineCallback;
|
||||||
|
modes.pop();
|
||||||
|
|
||||||
|
return function () callback.call(commandline, text);
|
||||||
|
}
|
||||||
|
return Events.PASS;
|
||||||
|
});
|
||||||
|
|
||||||
|
let bind = function bind()
|
||||||
|
mappings.add.apply(mappings, [[modes.COMMAND_LINE]].concat(Array.slice(arguments)))
|
||||||
|
|
||||||
// Any "non-keyword" character triggers abbreviation expansion
|
// Any "non-keyword" character triggers abbreviation expansion
|
||||||
// TODO: Add "<CR>" and "<Tab>" to this list
|
// TODO: Add "<CR>" and "<Tab>" to this list
|
||||||
@@ -1714,37 +1665,55 @@ var CommandLine = Module("commandline", {
|
|||||||
// TODO: Make non-keyword recognition smarter so that there need not
|
// TODO: Make non-keyword recognition smarter so that there need not
|
||||||
// be two lists of the same characters (one here and a regexp in
|
// be two lists of the same characters (one here and a regexp in
|
||||||
// mappings.js)
|
// mappings.js)
|
||||||
mappings.add([modes.COMMAND_LINE],
|
bind(["<Space>", '"', "'"], "Expand command line abbreviation",
|
||||||
["<Space>", '"', "'"], "Expand command line abbreviation",
|
|
||||||
function () {
|
function () {
|
||||||
commandline.resetCompletions();
|
commandline.resetCompletions();
|
||||||
editor.expandAbbreviation(modes.COMMAND_LINE);
|
editor.expandAbbreviation(modes.COMMAND_LINE);
|
||||||
return Events.PASS;
|
return Events.PASS;
|
||||||
});
|
});
|
||||||
|
|
||||||
mappings.add([modes.COMMAND_LINE],
|
bind(["<Return>", "<C-j>", "<C-m>"], "Accept the current input",
|
||||||
["<C-]>", "<C-5>"], "Expand command line abbreviation",
|
function (args) {
|
||||||
function () { editor.expandAbbreviation(modes.COMMAND_LINE); });
|
|
||||||
|
|
||||||
mappings.add([modes.NORMAL],
|
commandline._keepCommand = userContext.hidden_option_command_afterimage;
|
||||||
["g<"], "Redisplay the last command output",
|
|
||||||
function () {
|
let mode = commandline.currentExtendedMode;
|
||||||
dactyl.assert(commandline._lastMowOutput, "No previous command output");
|
let command = commandline.command;
|
||||||
commandline._echoMultiline(commandline._lastMowOutput, commandline.HL_NORMAL);
|
commandline.currentExtendedMode = null; // Don't let modes.pop trigger "cancel"
|
||||||
|
modes.pop();
|
||||||
|
|
||||||
|
return function () commandline.triggerCallback("submit", mode, command);
|
||||||
});
|
});
|
||||||
|
|
||||||
mappings.add([modes.COMMAND_LINE],
|
[
|
||||||
["<C-p>", "<PageUp>"], "Recall the previous command line from the history list",
|
[["<Up>", "<A-p>"], "previous matching", true, true],
|
||||||
function () { events.feedkeys("<S-Up>"); });
|
[["<S-Up>", "<C-p>", "<PageUp>"], "previous", true, false],
|
||||||
|
[["<Down>", "<A-n>"], "next matching", false, true],
|
||||||
|
[["<S-Down>", "<C-n>", "<PageDown>"], "next", false, false]
|
||||||
|
].forEach(function ([keys, desc, up, search]) {
|
||||||
|
bind(keys, "Recall the " + desc + " command line from the history list",
|
||||||
|
function (args) {
|
||||||
|
dactyl.assert(commandline._history);
|
||||||
|
commandline._history.select(up, search);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
mappings.add([modes.COMMAND_LINE],
|
bind(["<A-Tab>", "<Tab>"], "Select the next matching completion item",
|
||||||
["<C-n>", "<PageDown>"], "Recall the next command line from the history list",
|
function ({ events }) { commandline._tabTimer.tell(events[0]); });
|
||||||
function () { events.feedkeys("<S-Down>"); });
|
|
||||||
|
|
||||||
// add the ":" mapping in all but insert mode mappings
|
bind(["<A-S-Tab>", "<S-Tab>"], "Select the previous matching completion item",
|
||||||
mappings.add(modes.COMMAND,
|
function ({ events }) { commandline._tabTimer.tell(events[0]); });
|
||||||
[":"], "Enter command-line mode",
|
|
||||||
function () { commandline.open(":", "", modes.EX); });
|
bind(["<BS>", "<C-h>"], "Delete the previous character",
|
||||||
|
function () {
|
||||||
|
if (!commandline.command)
|
||||||
|
modes.pop();
|
||||||
|
else
|
||||||
|
return Events.PASS;
|
||||||
|
});
|
||||||
|
|
||||||
|
bind(["<C-]>", "<C-5>"], "Expand command line abbreviation",
|
||||||
|
function () { editor.expandAbbreviation(modes.COMMAND_LINE); });
|
||||||
|
|
||||||
let mow = modules.mow = {
|
let mow = modules.mow = {
|
||||||
__noSuchMethod__: function (meth, args) Buffer[meth].apply(Buffer, [this.body].concat(args))
|
__noSuchMethod__: function (meth, args) Buffer[meth].apply(Buffer, [this.body].concat(args))
|
||||||
@@ -1756,7 +1725,7 @@ var CommandLine = Module("commandline", {
|
|||||||
const DROP = false;
|
const DROP = false;
|
||||||
const BEEP = {};
|
const BEEP = {};
|
||||||
|
|
||||||
function bind(keys, description, action, test, default_) {
|
bind = function bind(keys, description, action, test, default_) {
|
||||||
mappings.add([modes.OUTPUT_MULTILINE],
|
mappings.add([modes.OUTPUT_MULTILINE],
|
||||||
keys, description,
|
keys, description,
|
||||||
function (command) {
|
function (command) {
|
||||||
@@ -1826,7 +1795,7 @@ var CommandLine = Module("commandline", {
|
|||||||
function () {},
|
function () {},
|
||||||
function () false, DROP);
|
function () false, DROP);
|
||||||
},
|
},
|
||||||
options: function () {
|
options: function init_options() {
|
||||||
options.add(["history", "hi"],
|
options.add(["history", "hi"],
|
||||||
"Number of Ex commands and search patterns to store in the command-line history",
|
"Number of Ex commands and search patterns to store in the command-line history",
|
||||||
"number", 500,
|
"number", 500,
|
||||||
@@ -1850,7 +1819,7 @@ var CommandLine = Module("commandline", {
|
|||||||
"Show the current mode in the command line",
|
"Show the current mode in the command line",
|
||||||
"boolean", true);
|
"boolean", true);
|
||||||
},
|
},
|
||||||
sanitizer: function () {
|
sanitizer: function init_sanitizer() {
|
||||||
sanitizer.addItem("commandline", {
|
sanitizer.addItem("commandline", {
|
||||||
description: "Command-line and search history",
|
description: "Command-line and search history",
|
||||||
persistent: true,
|
persistent: true,
|
||||||
@@ -1897,7 +1866,7 @@ var CommandLine = Module("commandline", {
|
|||||||
* necessary.
|
* necessary.
|
||||||
*/
|
*/
|
||||||
var ItemList = Class("ItemList", {
|
var ItemList = Class("ItemList", {
|
||||||
init: function (id) {
|
init: function init(id) {
|
||||||
this._completionElements = [];
|
this._completionElements = [];
|
||||||
|
|
||||||
var iframe = document.getElementById(id);
|
var iframe = document.getElementById(id);
|
||||||
@@ -1921,9 +1890,9 @@ var ItemList = Class("ItemList", {
|
|||||||
this._minHeight = 0;
|
this._minHeight = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
_dom: function (xml, map) util.xmlToDom(xml instanceof XML ? xml : <>{xml}</>, this._doc, map),
|
_dom: function _dom(xml, map) util.xmlToDom(xml instanceof XML ? xml : <>{xml}</>, this._doc, map),
|
||||||
|
|
||||||
_autoSize: function () {
|
_autoSize: function _autoSize() {
|
||||||
if (this._container.collapsed)
|
if (this._container.collapsed)
|
||||||
this._div.style.minWidth = document.getElementById("dactyl-commandline").scrollWidth + "px";
|
this._div.style.minWidth = document.getElementById("dactyl-commandline").scrollWidth + "px";
|
||||||
|
|
||||||
@@ -1942,9 +1911,9 @@ var ItemList = Class("ItemList", {
|
|||||||
this.timeout(function () { this._container.height -= commandline.getSpaceNeeded(); }, 0);
|
this.timeout(function () { this._container.height -= commandline.getSpaceNeeded(); }, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
_getCompletion: function (index) this._completionElements.snapshotItem(index - this._startIndex),
|
_getCompletion: function _getCompletion(index) this._completionElements.snapshotItem(index - this._startIndex),
|
||||||
|
|
||||||
_init: function () {
|
_init: function _init() {
|
||||||
this._div = this._dom(
|
this._div = this._dom(
|
||||||
<div class="ex-command-output" highlight="Normal" style="white-space: nowrap">
|
<div class="ex-command-output" highlight="Normal" style="white-space: nowrap">
|
||||||
<div highlight="Completions" key="noCompletions"><span highlight="Title">No Completions</span></div>
|
<div highlight="Completions" key="noCompletions"><span highlight="Title">No Completions</span></div>
|
||||||
@@ -1989,7 +1958,7 @@ var ItemList = Class("ItemList", {
|
|||||||
*
|
*
|
||||||
* @param {number} offset Start at this index and show options["maxitems"].
|
* @param {number} offset Start at this index and show options["maxitems"].
|
||||||
*/
|
*/
|
||||||
_fill: function (offset) {
|
_fill: function _fill(offset) {
|
||||||
XML.ignoreWhiteSpace = false;
|
XML.ignoreWhiteSpace = false;
|
||||||
let diff = offset - this._startIndex;
|
let diff = offset - this._startIndex;
|
||||||
if (this._items == null || offset == null || diff == 0 || offset < 0)
|
if (this._items == null || offset == null || diff == 0 || offset < 0)
|
||||||
@@ -2072,7 +2041,7 @@ var ItemList = Class("ItemList", {
|
|||||||
show: function show() { this._container.collapsed = false; },
|
show: function show() { this._container.collapsed = false; },
|
||||||
visible: function visible() !this._container.collapsed,
|
visible: function visible() !this._container.collapsed,
|
||||||
|
|
||||||
reset: function (brief) {
|
reset: function reset(brief) {
|
||||||
this._startIndex = this._endIndex = this._selIndex = -1;
|
this._startIndex = this._endIndex = this._selIndex = -1;
|
||||||
this._div = null;
|
this._div = null;
|
||||||
if (!brief)
|
if (!brief)
|
||||||
@@ -2142,7 +2111,7 @@ var ItemList = Class("ItemList", {
|
|||||||
// util.dump({ time: Date.now() - this.start });
|
// util.dump({ time: Date.now() - this.start });
|
||||||
},
|
},
|
||||||
|
|
||||||
onEvent: function onEvent(event) false
|
onKeyPress: function onKeyPress(event) false
|
||||||
}, {
|
}, {
|
||||||
WAITING_MESSAGE: "Generating results..."
|
WAITING_MESSAGE: "Generating results..."
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
* (@link CommandOption.FLOAT),
|
* (@link CommandOption.FLOAT),
|
||||||
* (@link CommandOption.LIST),
|
* (@link CommandOption.LIST),
|
||||||
* (@link CommandOption.ANY)
|
* (@link CommandOption.ANY)
|
||||||
* @property {object} default The option's default value
|
|
||||||
* @property {function} validator A validator function
|
* @property {function} validator A validator function
|
||||||
* @property {function (CompletionContext, object)} completer A list of
|
* @property {function (CompletionContext, object)} completer A list of
|
||||||
* completions, or a completion function which will be passed a
|
* completions, or a completion function which will be passed a
|
||||||
@@ -33,6 +32,7 @@
|
|||||||
* completeOpt - The name of the option currently being completed.
|
* completeOpt - The name of the option currently being completed.
|
||||||
* @property {boolean} multiple Whether this option can be specified multiple times
|
* @property {boolean} multiple Whether this option can be specified multiple times
|
||||||
* @property {string} description A description of the option
|
* @property {string} description A description of the option
|
||||||
|
* @property {object} default The option's default value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var CommandOption = Struct("names", "type", "validator", "completer", "multiple", "description", "default");
|
var CommandOption = Struct("names", "type", "validator", "completer", "multiple", "description", "default");
|
||||||
|
|||||||
@@ -851,7 +851,7 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
}, [function (context, args) completion.file(context)]),
|
}, [function (context, args) completion.file(context)]),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a help entry and writes it to the clipboard.
|
* Generates a help entry and returns it as a string.
|
||||||
*
|
*
|
||||||
* @param {Command|Map|Option} obj A dactyl *Command*, *Map* or *Option*
|
* @param {Command|Map|Option} obj A dactyl *Command*, *Map* or *Option*
|
||||||
* object
|
* object
|
||||||
@@ -953,7 +953,6 @@ var Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), {
|
|||||||
*
|
*
|
||||||
* @param {string} topic The help topic to open.
|
* @param {string} topic The help topic to open.
|
||||||
* @param {boolean} unchunked Whether to use the unchunked help page.
|
* @param {boolean} unchunked Whether to use the unchunked help page.
|
||||||
* @returns {string}
|
|
||||||
*/
|
*/
|
||||||
help: function (topic, unchunked) {
|
help: function (topic, unchunked) {
|
||||||
dactyl.initHelp();
|
dactyl.initHelp();
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ var Editor = Module("editor", {
|
|||||||
elem.scrollTop = top;
|
elem.scrollTop = top;
|
||||||
elem.scrollLeft = left;
|
elem.scrollLeft = left;
|
||||||
|
|
||||||
let event = elem.ownerDocument.createEvent("Event");
|
events.dispatch(elem, events.create(elem.ownerDocument, "input"));
|
||||||
event.initEvent("input", true, false);
|
|
||||||
events.dispatch(elem, event);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,225 @@
|
|||||||
|
|
||||||
/** @scope modules */
|
/** @scope modules */
|
||||||
|
|
||||||
|
var ProcessorStack = Class("ProcessorStack", {
|
||||||
|
init: function (mode, hives, keyModes) {
|
||||||
|
this.main = mode.main;
|
||||||
|
this.actions = [];
|
||||||
|
this.buffer = "";
|
||||||
|
this.events = [];
|
||||||
|
|
||||||
|
this.processors = keyModes.map(function (m) hives.map(function (h) KeyProcessor(m, h)))
|
||||||
|
.flatten().array;
|
||||||
|
|
||||||
|
for (let [i, input] in Iterator(this.processors)) {
|
||||||
|
let params = input.main == mode.main ? mode.params : input.main.params;
|
||||||
|
if (params.preExecute)
|
||||||
|
input.preExecute = params.preExecute;
|
||||||
|
if (params.postExecute)
|
||||||
|
input.postExecute = params.postExecute;
|
||||||
|
if (params.onKeyPress && input.hive === mappings.builtin)
|
||||||
|
input.fallthrough = function (event) {
|
||||||
|
return params.onKeyPress(event) === false ? Events.KILL : Events.PASS;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
process: function process(event) {
|
||||||
|
function dbg() {}
|
||||||
|
|
||||||
|
let key = events.toString(event);
|
||||||
|
this.events.push(event);
|
||||||
|
|
||||||
|
this.buffer += key;
|
||||||
|
|
||||||
|
let actions = [];
|
||||||
|
let processors = [];
|
||||||
|
|
||||||
|
dbg("\n\n");
|
||||||
|
dbg("KEY: " + key + " skipmap: " + event.skipmap + " macro: " + event.isMacro);
|
||||||
|
|
||||||
|
for (let [i, input] in Iterator(this.processors)) {
|
||||||
|
let res = input.process(event);
|
||||||
|
if (res !== Events.ABORT)
|
||||||
|
var result = res;
|
||||||
|
|
||||||
|
dbg("RES: " + input + " " + (callable(res) ? {}.toString.call(res) : res));
|
||||||
|
|
||||||
|
if (res === Events.KILL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
buffer = buffer || input.inputBuffer;
|
||||||
|
|
||||||
|
if (callable(res))
|
||||||
|
actions.push(res);
|
||||||
|
|
||||||
|
if (isinstance(res, KeyProcessor))
|
||||||
|
processors.push(res);
|
||||||
|
if (res === Events.WAIT || input.waiting)
|
||||||
|
processors.push(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg("RESULT: " + (callable(result) ? {}.toString.call(result) : result) + " " + event.getPreventDefault());
|
||||||
|
dbg("ACTIONS: " + actions.length + " " + this.actions.length);
|
||||||
|
dbg("PROCESSORS:", processors);
|
||||||
|
|
||||||
|
if (!processors.some(function (p) p.main.ownsBuffer))
|
||||||
|
statusline.updateInputBuffer(processors.length ? this.buffer : "");
|
||||||
|
|
||||||
|
this.actions = actions.concat(this.actions);
|
||||||
|
|
||||||
|
if (result === Events.KILL)
|
||||||
|
this.actions = [];
|
||||||
|
else if (!this.actions.length)
|
||||||
|
for (let input in values(this.processors))
|
||||||
|
if (input.fallthrough) {
|
||||||
|
if (result === Events.KILL)
|
||||||
|
break;
|
||||||
|
result = dactyl.trapErrors(input.fallthrough, input, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processors = processors;
|
||||||
|
|
||||||
|
if (processors.length)
|
||||||
|
result = Events.KILL;
|
||||||
|
else if (this.actions.length) {
|
||||||
|
if (actions.length == 0)
|
||||||
|
dactyl.beep();
|
||||||
|
|
||||||
|
if (modes.replaying && !events.waitForPageLoad())
|
||||||
|
result = Events.KILL;
|
||||||
|
else {
|
||||||
|
for (var res = this.actions[0]; callable(res);)
|
||||||
|
res = res();
|
||||||
|
result = res === Events.PASS ? Events.PASS : Events.KILL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (result !== Events.KILL && processors.some(function (p) !p.main.passUnknown)) {
|
||||||
|
result = Events.KILL;
|
||||||
|
dactyl.beep();
|
||||||
|
}
|
||||||
|
else if (result === undefined)
|
||||||
|
result = Events.PASS;
|
||||||
|
|
||||||
|
if (result !== Events.PASS)
|
||||||
|
Events.kill(event);
|
||||||
|
|
||||||
|
if (result === Events.PASS || result === Events.ABORT)
|
||||||
|
this.events.filter(function (e) e.getPreventDefault())
|
||||||
|
.forEach(function (event, i) {
|
||||||
|
if (event.originalTarget) {
|
||||||
|
let evt = events.create(event.originalTarget.ownerDocument, event.type, event);
|
||||||
|
events.dispatch(event.originalTarget, evt, { skipmap: true, isMacro: true });
|
||||||
|
}
|
||||||
|
else if (i > 0)
|
||||||
|
events.events.keypress.call(events, event);
|
||||||
|
});
|
||||||
|
return this.processors.length == 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var KeyProcessor = Class("KeyProcessor", {
|
||||||
|
init: function init(main, hive) {
|
||||||
|
this.main = main;
|
||||||
|
this.events = [];
|
||||||
|
this.hive = hive;
|
||||||
|
this.wantCount = this.main.count;
|
||||||
|
},
|
||||||
|
|
||||||
|
get toStringParams() [this.main.name, this.hive.name],
|
||||||
|
|
||||||
|
countStr: "",
|
||||||
|
command: "",
|
||||||
|
get count() this.countStr ? Number(this.countStr) : null,
|
||||||
|
|
||||||
|
append: function append(event) {
|
||||||
|
this.events.push(event);
|
||||||
|
let key = events.toString(event);
|
||||||
|
|
||||||
|
if (this.wantCount && !this.command &&
|
||||||
|
(this.countStr ? /^[0-9]$/ : /^[1-9]$/).test(key))
|
||||||
|
this.countStr += key;
|
||||||
|
else
|
||||||
|
this.command += key;
|
||||||
|
return this.events;
|
||||||
|
},
|
||||||
|
|
||||||
|
process: function process(event) {
|
||||||
|
this.append(event);
|
||||||
|
this.waiting = false;
|
||||||
|
return this.onKeyPress(event);
|
||||||
|
},
|
||||||
|
|
||||||
|
execute: function execute(map)
|
||||||
|
let (self = this, args = arguments)
|
||||||
|
function execute() {
|
||||||
|
if (self.preExecute)
|
||||||
|
self.preExecute.apply(self, args);
|
||||||
|
let res = map.execute.apply(map, Array.slice(args, 1));
|
||||||
|
if (self.postExecute)
|
||||||
|
self.postExecute.apply(self, args);
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
|
||||||
|
onKeyPress: function onKeyPress(event) {
|
||||||
|
if (event.skipmap)
|
||||||
|
return Events.ABORT;
|
||||||
|
|
||||||
|
if (!this.command)
|
||||||
|
return Events.WAIT;
|
||||||
|
|
||||||
|
var map = this.hive.get(this.main, this.command);
|
||||||
|
this.waiting = this.hive.getCandidates(this.main, this.command);
|
||||||
|
if (map) {
|
||||||
|
if (map.arg)
|
||||||
|
return KeyArgProcessor(this, map, false, "arg");
|
||||||
|
else if (map.motion)
|
||||||
|
return KeyArgProcessor(this, map, true, "motion");
|
||||||
|
|
||||||
|
return this.execute(map, { count: this.count, command: this.command, events: this.events });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.waiting)
|
||||||
|
return this.main.input ? Events.PASS : Events.ABORT;
|
||||||
|
|
||||||
|
return Events.WAIT;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var KeyArgProcessor = Class("KeyArgProcessor", KeyProcessor, {
|
||||||
|
init: function init(input, map, wantCount, argName) {
|
||||||
|
init.supercall(this, input.main, input.hive);
|
||||||
|
this.map = map;
|
||||||
|
this.parent = input;
|
||||||
|
this.argName = argName;
|
||||||
|
this.wantCount = wantCount;
|
||||||
|
},
|
||||||
|
|
||||||
|
onKeyPress: function onKeyPress(event) {
|
||||||
|
if (Events.isEscape(event))
|
||||||
|
return Events.KILL;
|
||||||
|
if (!this.command)
|
||||||
|
return Events.WAIT;
|
||||||
|
|
||||||
|
let args = {
|
||||||
|
command: this.parent.command,
|
||||||
|
count: this.count || this.parent.count,
|
||||||
|
events: this.parent.events.concat(this.events)
|
||||||
|
};
|
||||||
|
args[this.argName] = this.command;
|
||||||
|
|
||||||
|
return this.execute(this.map, args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @instance events
|
* @instance events
|
||||||
*/
|
*/
|
||||||
var Events = Module("events", {
|
var Events = Module("events", {
|
||||||
init: function () {
|
init: function () {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
XML.ignoreWhitespace = true;
|
||||||
util.overlayWindow(window, {
|
util.overlayWindow(window, {
|
||||||
append: <e4x xmlns={XUL}>
|
append: <e4x xmlns={XUL}>
|
||||||
<window id={document.documentElement.id}>
|
<window id={document.documentElement.id}>
|
||||||
@@ -32,7 +246,6 @@ var Events = Module("events", {
|
|||||||
this._currentMacro = "";
|
this._currentMacro = "";
|
||||||
this._macroKeys = [];
|
this._macroKeys = [];
|
||||||
this._lastMacro = "";
|
this._lastMacro = "";
|
||||||
this._processors = [];
|
|
||||||
|
|
||||||
this.sessionListeners = [];
|
this.sessionListeners = [];
|
||||||
|
|
||||||
@@ -92,17 +305,12 @@ var Events = Module("events", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._activeMenubar = false;
|
this._activeMenubar = false;
|
||||||
this.addSessionListener(window, "DOMMenuBarActive", this.onDOMMenuBarActive, true);
|
for (let [event, callback] in Iterator(this.events))
|
||||||
this.addSessionListener(window, "DOMMenuBarInactive", this.onDOMMenuBarInactive, true);
|
this.addSessionListener(window, event, callback, true);
|
||||||
this.addSessionListener(window, "blur", this.onBlur, true);
|
|
||||||
this.addSessionListener(window, "focus", this.onFocus, true);
|
dactyl.registerObserver("modeChange", function () {
|
||||||
this.addSessionListener(window, "keydown", this.onKeyUpOrDown, true);
|
delete self.processor;
|
||||||
this.addSessionListener(window, "keypress", this.onKeyPress, true);
|
});
|
||||||
this.addSessionListener(window, "keyup", this.onKeyUpOrDown, true);
|
|
||||||
this.addSessionListener(window, "mousedown", this.onMouseDown, true);
|
|
||||||
this.addSessionListener(window, "popuphidden", this.onPopupHidden, true);
|
|
||||||
this.addSessionListener(window, "popupshown", this.onPopupShown, true);
|
|
||||||
this.addSessionListener(window, "resize", this.onResize, true);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
@@ -296,7 +504,7 @@ var Events = Module("events", {
|
|||||||
if (!evt_obj.dactylString && !evt_obj.dactylShift && !mode)
|
if (!evt_obj.dactylString && !evt_obj.dactylShift && !mode)
|
||||||
events.dispatch(dactyl.focusedElement || buffer.focusedFrame, event, evt);
|
events.dispatch(dactyl.focusedElement || buffer.focusedFrame, event, evt);
|
||||||
else
|
else
|
||||||
events.onKeyPress(event);
|
events.events.keypress.call(events, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.feedingKeys)
|
if (!this.feedingKeys)
|
||||||
@@ -326,9 +534,10 @@ var Events = Module("events", {
|
|||||||
*
|
*
|
||||||
* @param {Document} doc The DOM document to associate this event with
|
* @param {Document} doc The DOM document to associate this event with
|
||||||
* @param {Type} type The type of event (keypress, click, etc.)
|
* @param {Type} type The type of event (keypress, click, etc.)
|
||||||
* @param {Object} opts The pseudo-event.
|
* @param {Object} opts The pseudo-event. @optional
|
||||||
*/
|
*/
|
||||||
create: function (doc, type, opts) {
|
create: function (doc, type, opts) {
|
||||||
|
opts = opts || {};
|
||||||
var DEFAULTS = {
|
var DEFAULTS = {
|
||||||
HTML: {
|
HTML: {
|
||||||
type: type, bubbles: true, cancelable: false
|
type: type, bubbles: true, cancelable: false
|
||||||
@@ -353,7 +562,7 @@ var Events = Module("events", {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const TYPES = {
|
const TYPES = {
|
||||||
change: "",
|
change: "", input: "",
|
||||||
click: "Mouse", mousedown: "Mouse", mouseup: "Mouse",
|
click: "Mouse", mousedown: "Mouse", mouseup: "Mouse",
|
||||||
mouseover: "Mouse", mouseout: "Mouse",
|
mouseover: "Mouse", mouseout: "Mouse",
|
||||||
keypress: "Key", keyup: "Key", keydown: "Key"
|
keypress: "Key", keyup: "Key", keydown: "Key"
|
||||||
@@ -362,7 +571,9 @@ var Events = Module("events", {
|
|||||||
var evt = doc.createEvent((t || "HTML") + "Events");
|
var evt = doc.createEvent((t || "HTML") + "Events");
|
||||||
|
|
||||||
let defaults = DEFAULTS[t || "HTML"]
|
let defaults = DEFAULTS[t || "HTML"]
|
||||||
evt["init" + t + "Event"].apply(evt, Object.keys(defaults).map(function (k) k in opts ? opts[k] : defaults[k]));
|
evt["init" + t + "Event"].apply(evt, Object.keys(defaults)
|
||||||
|
.map(function (k) k in opts ? opts[k]
|
||||||
|
: defaults[k]));
|
||||||
return evt;
|
return evt;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -697,16 +908,6 @@ var Events = Module("events", {
|
|||||||
return buffer.loaded;
|
return buffer.loaded;
|
||||||
},
|
},
|
||||||
|
|
||||||
onDOMMenuBarActive: function () {
|
|
||||||
this._activeMenubar = true;
|
|
||||||
modes.add(modes.MENU);
|
|
||||||
},
|
|
||||||
|
|
||||||
onDOMMenuBarInactive: function () {
|
|
||||||
this._activeMenubar = false;
|
|
||||||
modes.remove(modes.MENU);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that the currently focused element is visible and blurs
|
* Ensures that the currently focused element is visible and blurs
|
||||||
* it if it's not.
|
* it if it's not.
|
||||||
@@ -723,7 +924,19 @@ var Events = Module("events", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onBlur: function onFocus(event) {
|
events: {
|
||||||
|
DOMMenuBarActive: function () {
|
||||||
|
this._activeMenubar = true;
|
||||||
|
if (modes.main != modes.MENU)
|
||||||
|
modes.push(modes.MENU);
|
||||||
|
},
|
||||||
|
|
||||||
|
DOMMenuBarInactive: function () {
|
||||||
|
this._activeMenubar = false;
|
||||||
|
modes.remove(modes.MENU);
|
||||||
|
},
|
||||||
|
|
||||||
|
blur: function onBlur(event) {
|
||||||
if (event.originalTarget instanceof Window && services.focus.activeWindow == null) {
|
if (event.originalTarget instanceof Window && services.focus.activeWindow == null) {
|
||||||
// Deals with circumstances where, after the main window
|
// Deals with circumstances where, after the main window
|
||||||
// blurs while a collapsed frame has focus, re-activating
|
// blurs while a collapsed frame has focus, re-activating
|
||||||
@@ -735,7 +948,7 @@ var Events = Module("events", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Merge with onFocusChange
|
// TODO: Merge with onFocusChange
|
||||||
onFocus: function onFocus(event) {
|
focus: function onFocus(event) {
|
||||||
let elem = event.originalTarget;
|
let elem = event.originalTarget;
|
||||||
if (elem instanceof Element) {
|
if (elem instanceof Element) {
|
||||||
let win = elem.ownerDocument.defaultView;
|
let win = elem.ownerDocument.defaultView;
|
||||||
@@ -784,6 +997,179 @@ var Events = Module("events", {
|
|||||||
},
|
},
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
input: function onInput(event) {
|
||||||
|
delete event.originalTarget.dactylKeyPress;
|
||||||
|
},
|
||||||
|
|
||||||
|
// this keypress handler gets always called first, even if e.g.
|
||||||
|
// the command-line has focus
|
||||||
|
// TODO: ...help me...please...
|
||||||
|
keypress: function onKeyPress(event) {
|
||||||
|
event.dactylDefaultPrevented = event.getPreventDefault();
|
||||||
|
|
||||||
|
// Hack to deal with <BS> and so forth not dispatching input
|
||||||
|
// events
|
||||||
|
if (event.originalTarget instanceof HTMLInputElement) {
|
||||||
|
let elem = event.originalTarget;
|
||||||
|
elem.dactylKeyPress = elem.value;
|
||||||
|
util.timeout(function () {
|
||||||
|
if ("dactylKeyPress" in elem && elem.value !== elem.dactylKeyPress)
|
||||||
|
events.dispatch(elem, events.create(elem.ownerDocument, "input"));
|
||||||
|
delete events.dactylKeyPress;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let duringFeed = this.duringFeed || [];
|
||||||
|
this.duringFeed = [];
|
||||||
|
try {
|
||||||
|
if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) {
|
||||||
|
for (let [k, v] in Iterator(this.feedingEvent))
|
||||||
|
if (!(k in event))
|
||||||
|
event[k] = v;
|
||||||
|
this.feedingEvent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = events.toString(event);
|
||||||
|
if (!key)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (modes.recording && (!this._input || !mappings.user.hasMap(modes.main, this._input.buffer + key)))
|
||||||
|
events._macroKeys.push(key);
|
||||||
|
|
||||||
|
// feedingKeys needs to be separate from interrupted so
|
||||||
|
// we can differentiate between a recorded <C-c>
|
||||||
|
// interrupting whatever it's started and a real <C-c>
|
||||||
|
// interrupting our playback.
|
||||||
|
if (events.feedingKeys && !event.isMacro) {
|
||||||
|
if (!event.originalTarget)
|
||||||
|
util.dumpStack();
|
||||||
|
if (key == "<C-c>") {
|
||||||
|
events.feedingKeys = false;
|
||||||
|
if (modes.replaying) {
|
||||||
|
modes.replaying = false;
|
||||||
|
this.timeout(function () { dactyl.echomsg("Canceled playback of macro '" + this._lastMacro + "'"); }, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
duringFeed.push(event);
|
||||||
|
|
||||||
|
return Events.kill(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.processor) {
|
||||||
|
let mode = modes.getStack(0);
|
||||||
|
if (event.dactylMode)
|
||||||
|
mode = Modes.StackElement(event.dactylMode);
|
||||||
|
|
||||||
|
let ignore = false;
|
||||||
|
|
||||||
|
if (modes.main == modes.PASS_THROUGH)
|
||||||
|
ignore = !Events.isEscape(key) && key != "<C-v>";
|
||||||
|
else if (modes.main == modes.QUOTE) {
|
||||||
|
if (modes.getStack(1).main == modes.PASS_THROUGH) {
|
||||||
|
mode.params.mainMode = modes.getStack(2).main;
|
||||||
|
ignore = Events.isEscape(key);
|
||||||
|
}
|
||||||
|
else if (events.shouldPass(event))
|
||||||
|
mode.params.mainMode = modes.getStack(1).main;
|
||||||
|
else
|
||||||
|
ignore = true;
|
||||||
|
|
||||||
|
if (ignore && !Events.isEscape(key))
|
||||||
|
modes.pop();
|
||||||
|
}
|
||||||
|
else if (!event.isMacro && !event.noremap && events.shouldPass(event))
|
||||||
|
ignore = true;
|
||||||
|
|
||||||
|
if (ignore)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (key == "<C-c>")
|
||||||
|
util.interrupted = true;
|
||||||
|
|
||||||
|
if (config.ignoreKeys[key] & mode.main)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let hives = mappings.hives.slice(event.noremap ? -1 : 0);
|
||||||
|
|
||||||
|
let keyModes = array([mode.params.keyModes, mode.main, mode.main.allBases]).flatten().compact();
|
||||||
|
|
||||||
|
this.processor = ProcessorStack(mode, hives, keyModes);
|
||||||
|
}
|
||||||
|
|
||||||
|
let processor = this.processor;
|
||||||
|
this.processor = null;
|
||||||
|
if (!processor.process(event))
|
||||||
|
this.processor = processor;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
dactyl.reportError(e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
[duringFeed, this.duringFeed] = [this.duringFeed, duringFeed];
|
||||||
|
if (this.feedingKeys)
|
||||||
|
this.duringFeed = this.duringFeed.concat(duringFeed);
|
||||||
|
else
|
||||||
|
for (let event in values(duringFeed))
|
||||||
|
try {
|
||||||
|
this.dispatch(event.originalTarget, event, event);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
util.reportError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
keyup: function onKeyUp(event) {
|
||||||
|
// Prevent certain sites from transferring focus to an input box
|
||||||
|
// before we get a chance to process our key bindings on the
|
||||||
|
// "keypress" event.
|
||||||
|
|
||||||
|
if (modes.main == modes.PASS_THROUGH ||
|
||||||
|
modes.main == modes.QUOTE
|
||||||
|
&& modes.getStack(1).main !== modes.PASS_THROUGH
|
||||||
|
&& !events.shouldPass(event) ||
|
||||||
|
!modes.passThrough && events.shouldPass(event))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!Events.isInputElement(dactyl.focusedElement))
|
||||||
|
event.stopPropagation();
|
||||||
|
},
|
||||||
|
keydown: function onKeyDown(event) {
|
||||||
|
this.events.keyup.call(this, event);
|
||||||
|
},
|
||||||
|
|
||||||
|
mousedown: function onMouseDown(event) {
|
||||||
|
let elem = event.target;
|
||||||
|
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
||||||
|
|
||||||
|
for (; win; win = win != win.parent && win.parent)
|
||||||
|
win.document.dactylFocusAllowed = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
popupshown: function onPopupShown(event) {
|
||||||
|
if (event.originalTarget.localName !== "tooltip" && event.originalTarget.id !== "dactyl-visualbell")
|
||||||
|
if (modes.main != modes.MENU)
|
||||||
|
modes.push(modes.MENU);
|
||||||
|
},
|
||||||
|
|
||||||
|
popuphidden: function onPopupHidden() {
|
||||||
|
// gContextMenu is set to NULL, when a context menu is closed
|
||||||
|
if (window.gContextMenu == null && !this._activeMenubar)
|
||||||
|
modes.remove(modes.MENU);
|
||||||
|
},
|
||||||
|
|
||||||
|
resize: function onResize(event) {
|
||||||
|
if (window.fullScreen != this._fullscreen) {
|
||||||
|
statusline.statusBar.removeAttribute("moz-collapsed");
|
||||||
|
this._fullscreen = window.fullScreen;
|
||||||
|
dactyl.triggerObserver("fullscreen", this._fullscreen);
|
||||||
|
autocommands.trigger("Fullscreen", { url: this._fullscreen ? "on" : "off", state: this._fullscreen });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// argument "event" is deliberately not used, as i don't seem to have
|
// argument "event" is deliberately not used, as i don't seem to have
|
||||||
// access to the real focus target
|
// access to the real focus target
|
||||||
// Huh? --djk
|
// Huh? --djk
|
||||||
@@ -858,245 +1244,6 @@ var Events = Module("events", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// this keypress handler gets always called first, even if e.g.
|
|
||||||
// the command-line has focus
|
|
||||||
// TODO: ...help me...please...
|
|
||||||
onKeyPress: function onKeyPress(event) {
|
|
||||||
event.dactylDefaultPrevented = event.getPreventDefault();
|
|
||||||
|
|
||||||
function kill(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
function shouldPass()
|
|
||||||
(!dactyl.focusedElement || events.isContentNode(dactyl.focusedElement)) &&
|
|
||||||
options.get("passkeys").has(events.toString(event));
|
|
||||||
|
|
||||||
let duringFeed = this.duringFeed || [];
|
|
||||||
this.duringFeed = [];
|
|
||||||
try {
|
|
||||||
if (this.feedingEvent && [!(k in event) || event[k] === v for ([k, v] in Iterator(this.feedingEvent))].every(util.identity)) {
|
|
||||||
for (let [k, v] in Iterator(this.feedingEvent))
|
|
||||||
if (!(k in event))
|
|
||||||
event[k] = v;
|
|
||||||
this.feedingEvent = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let key = events.toString(event);
|
|
||||||
if (!key)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (modes.recording && (!this._input || !mappings.user.hasMap(modes.main, this._input.buffer + key)))
|
|
||||||
events._macroKeys.push(key);
|
|
||||||
|
|
||||||
// feedingKeys needs to be separate from interrupted so
|
|
||||||
// we can differentiate between a recorded <C-c>
|
|
||||||
// interrupting whatever it's started and a real <C-c>
|
|
||||||
// interrupting our playback.
|
|
||||||
if (events.feedingKeys && !event.isMacro) {
|
|
||||||
if (!event.originalTarget)
|
|
||||||
util.dumpStack();
|
|
||||||
if (key == "<C-c>") {
|
|
||||||
events.feedingKeys = false;
|
|
||||||
if (modes.replaying) {
|
|
||||||
modes.replaying = false;
|
|
||||||
this.timeout(function () { dactyl.echomsg("Canceled playback of macro '" + this._lastMacro + "'"); }, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
duringFeed.push(event);
|
|
||||||
|
|
||||||
return kill(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mode = modes.getStack(0);
|
|
||||||
if (event.dactylMode)
|
|
||||||
mode = Modes.StackElement(event.dactylMode);
|
|
||||||
|
|
||||||
let processors = this._processors;
|
|
||||||
this._processors = [];
|
|
||||||
if (!processors.length) {
|
|
||||||
let ignore = false;
|
|
||||||
let overrideMode = null;
|
|
||||||
|
|
||||||
// menus have their own command handlers
|
|
||||||
if (modes.extended & modes.MENU)
|
|
||||||
overrideMode = modes.MENU;
|
|
||||||
|
|
||||||
if (modes.main == modes.PASS_THROUGH)
|
|
||||||
ignore = !Events.isEscape(key) && key != "<C-v>";
|
|
||||||
else if (modes.main == modes.QUOTE) {
|
|
||||||
if (modes.getStack(1).main == modes.PASS_THROUGH) {
|
|
||||||
mode.params.mainMode = modes.getStack(2).main;
|
|
||||||
ignore = Events.isEscape(key);
|
|
||||||
}
|
|
||||||
else if (shouldPass())
|
|
||||||
mode.params.mainMode = modes.getStack(1).main;
|
|
||||||
else
|
|
||||||
ignore = true;
|
|
||||||
|
|
||||||
if (ignore && !Events.isEscape(key))
|
|
||||||
modes.pop();
|
|
||||||
}
|
|
||||||
else if (!event.isMacro && !event.noremap && shouldPass())
|
|
||||||
ignore = true;
|
|
||||||
|
|
||||||
if (ignore)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (key == "<C-c>")
|
|
||||||
util.interrupted = true;
|
|
||||||
|
|
||||||
if (config.ignoreKeys[key] & mode.main)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (overrideMode)
|
|
||||||
var keyModes = array([overrideMode]);
|
|
||||||
else
|
|
||||||
keyModes = array([mode.params.keyModes, mode.main, mode.main.allBases]).flatten().compact();
|
|
||||||
|
|
||||||
let hives = mappings.hives.slice(event.noremap ? -1 : 0);
|
|
||||||
|
|
||||||
processors = keyModes.map(function (m) hives.map(function (h) Events.KeyProcessor(m, h)))
|
|
||||||
.flatten().array;
|
|
||||||
|
|
||||||
for (let [i, input] in Iterator(processors)) {
|
|
||||||
let params = input.main == mode.main ? mode.params : input.main.params;
|
|
||||||
if (params.preExecute)
|
|
||||||
input.preExecute = params.preExecute;
|
|
||||||
if (params.postExecute)
|
|
||||||
input.postExecute = params.postExecute;
|
|
||||||
if (params.onEvent && input.hive === mappings.builtin)
|
|
||||||
input.fallthrough = function (event) {
|
|
||||||
return params.onEvent(event) === false ? Events.KILL : Events.PASS;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let refeed, buffer, waiting = 0, action;
|
|
||||||
for (let input in values(processors)) {
|
|
||||||
var res = input.process(event);
|
|
||||||
waiting += res == Events.WAIT;
|
|
||||||
buffer = buffer || input.inputBuffer;
|
|
||||||
if (callable(res))
|
|
||||||
action = action || res;
|
|
||||||
|
|
||||||
if (isArray(res) && !waiting)
|
|
||||||
refeed = res;
|
|
||||||
if (res === Events.KILL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!refeed || refeed.length == 1)
|
|
||||||
for (let input in values(processors))
|
|
||||||
if (input.fallthrough) {
|
|
||||||
if (res === Events.KILL)
|
|
||||||
break;
|
|
||||||
res = dactyl.trapErrors(input.fallthrough, input, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!processors.some(function (p) p.main.ownsBuffer))
|
|
||||||
statusline.updateInputBuffer(buffer);
|
|
||||||
|
|
||||||
if (waiting) {
|
|
||||||
res = Events.KILL;
|
|
||||||
this._processors = processors;
|
|
||||||
}
|
|
||||||
else if (action)
|
|
||||||
res = action(res) === Events.PASS ? Events.PASS : Events.KILL;
|
|
||||||
|
|
||||||
if (res !== Events.KILL && (mode.main & (modes.TEXT_EDIT | modes.VISUAL))) {
|
|
||||||
res = Events.KILL;
|
|
||||||
dactyl.beep();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res !== Events.PASS && !isArray(res))
|
|
||||||
refeed = null;
|
|
||||||
|
|
||||||
if (refeed && refeed[0] && (!refeed[0].getPreventDefault() || refeed[0].dactylDefaultPrevented)) {
|
|
||||||
res = Events.PASS;
|
|
||||||
refeed.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res !== Events.PASS)
|
|
||||||
kill(event);
|
|
||||||
|
|
||||||
if (refeed)
|
|
||||||
for (let [i, event] in Iterator(refeed))
|
|
||||||
if (event.originalTarget) {
|
|
||||||
let evt = events.create(event.originalTarget.ownerDocument, event.type, event);
|
|
||||||
events.dispatch(event.originalTarget, evt, { skipmap: true, isMacro: true });
|
|
||||||
}
|
|
||||||
else if (i > 0)
|
|
||||||
events.onKeyPress(event);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
dactyl.reportError(e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
[duringFeed, this.duringFeed] = [this.duringFeed, duringFeed];
|
|
||||||
if (this.feedingKeys)
|
|
||||||
this.duringFeed = this.duringFeed.concat(duringFeed);
|
|
||||||
else
|
|
||||||
for (let event in values(duringFeed))
|
|
||||||
try {
|
|
||||||
this.dispatch(event.originalTarget, event, event);
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
util.reportError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeyUpOrDown: function onKeyUpOrDown(event) {
|
|
||||||
// Prevent certain sites from transferring focus to an input box
|
|
||||||
// before we get a chance to process our key bindings on the
|
|
||||||
// "keypress" event.
|
|
||||||
|
|
||||||
function shouldPass() // FIXME.
|
|
||||||
(!dactyl.focusedElement || events.isContentNode(dactyl.focusedElement)) &&
|
|
||||||
options.get("passkeys").has(events.toString(event));
|
|
||||||
|
|
||||||
if (modes.main == modes.PASS_THROUGH ||
|
|
||||||
modes.main == modes.QUOTE
|
|
||||||
&& modes.getStack(1).main !== modes.PASS_THROUGH
|
|
||||||
&& !shouldPass() ||
|
|
||||||
!modes.passThrough && shouldPass())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!Events.isInputElement(dactyl.focusedElement))
|
|
||||||
event.stopPropagation();
|
|
||||||
},
|
|
||||||
|
|
||||||
onMouseDown: function onMouseDown(event) {
|
|
||||||
let elem = event.target;
|
|
||||||
let win = elem.ownerDocument && elem.ownerDocument.defaultView || elem;
|
|
||||||
|
|
||||||
for (; win; win = win != win.parent && win.parent)
|
|
||||||
win.document.dactylFocusAllowed = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
onPopupShown: function onPopupShown(event) {
|
|
||||||
if (event.originalTarget.localName !== "tooltip" && event.originalTarget.id !== "dactyl-visualbell")
|
|
||||||
modes.add(modes.MENU);
|
|
||||||
},
|
|
||||||
|
|
||||||
onPopupHidden: function onPopupHidden() {
|
|
||||||
// gContextMenu is set to NULL, when a context menu is closed
|
|
||||||
if (window.gContextMenu == null && !this._activeMenubar)
|
|
||||||
modes.remove(modes.MENU);
|
|
||||||
},
|
|
||||||
|
|
||||||
onResize: function onResize(event) {
|
|
||||||
if (window.fullScreen != this._fullscreen) {
|
|
||||||
statusline.statusBar.removeAttribute("moz-collapsed");
|
|
||||||
this._fullscreen = window.fullScreen;
|
|
||||||
dactyl.triggerObserver("fullscreen", this._fullscreen);
|
|
||||||
autocommands.trigger("Fullscreen", { url: this._fullscreen ? "on" : "off", state: this._fullscreen });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onSelectionChange: function onSelectionChange(event) {
|
onSelectionChange: function onSelectionChange(event) {
|
||||||
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
|
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
|
||||||
let couldCopy = controller && controller.isCommandEnabled("cmd_copy");
|
let couldCopy = controller && controller.isCommandEnabled("cmd_copy");
|
||||||
@@ -1111,137 +1258,17 @@ var Events = Module("events", {
|
|||||||
else if (modes.main == modes.CARET)
|
else if (modes.main == modes.CARET)
|
||||||
modes.push(modes.VISUAL);
|
modes.push(modes.VISUAL);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
|
shouldPass: function shouldPass(event)
|
||||||
|
(!dactyl.focusedElement || events.isContentNode(dactyl.focusedElement)) &&
|
||||||
|
options.get("passkeys").has(events.toString(event))
|
||||||
}, {
|
}, {
|
||||||
|
ABORT: {},
|
||||||
KILL: true,
|
KILL: true,
|
||||||
PASS: false,
|
PASS: false,
|
||||||
WAIT: null,
|
WAIT: null,
|
||||||
|
|
||||||
|
|
||||||
KeyProcessor: Class("KeyProcessor", {
|
|
||||||
init: function init(main, hive) {
|
|
||||||
this.main = main;
|
|
||||||
this.events = [];
|
|
||||||
this.hive = hive;
|
|
||||||
},
|
|
||||||
|
|
||||||
get toStringParams() [this.main.name, this.hive.name],
|
|
||||||
|
|
||||||
buffer: "", // partial command storage
|
|
||||||
pendingMotionMap: null, // e.g. "d{motion}" if we wait for a motion of the "d" command
|
|
||||||
pendingArgMap: null, // pending map storage for commands like m{a-z}
|
|
||||||
count: null, // parsed count from the input buffer
|
|
||||||
motionCount: null,
|
|
||||||
|
|
||||||
append: function append(event) {
|
|
||||||
this.events.push(event);
|
|
||||||
this.buffer += events.toString(event);
|
|
||||||
return this.events;
|
|
||||||
},
|
|
||||||
|
|
||||||
process: function process(event) {
|
|
||||||
function kill(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = this.onKeyPress(event);
|
|
||||||
|
|
||||||
if (res != Events.WAIT)
|
|
||||||
this.inputBuffer = "";
|
|
||||||
else {
|
|
||||||
let motionMap = (this.pendingMotionMap && this.pendingMotionMap.names[0]) || "";
|
|
||||||
this.inputBuffer = motionMap + this.buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
execute: function execute(map)
|
|
||||||
let (self = this, args = arguments)
|
|
||||||
function execute() {
|
|
||||||
if (self.preExecute)
|
|
||||||
self.preExecute.apply(self, args);
|
|
||||||
let res = map.execute.apply(map, Array.slice(args, 1));
|
|
||||||
if (self.postExecute) // To do: get rid of self.
|
|
||||||
self.postExecute.apply(self, args);
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
|
|
||||||
onKeyPress: function onKeyPress(event) {
|
|
||||||
// This all needs to go. It's horrible. --Kris
|
|
||||||
|
|
||||||
let key = events.toString(event);
|
|
||||||
let [, countStr, command] = /^((?:[1-9][0-9]*)?)(.*)/.exec(this.buffer + key);
|
|
||||||
|
|
||||||
var map = this.hive.get(this.main, command);
|
|
||||||
|
|
||||||
let candidates = this.hive.getCandidates(this.main, command);
|
|
||||||
if (candidates == 0 && !map) {
|
|
||||||
[map] = this.pendingMap || [];
|
|
||||||
this.pendingMap = null;
|
|
||||||
if (map && map.arg)
|
|
||||||
this.pendingArgMap = [map, command];
|
|
||||||
}
|
|
||||||
|
|
||||||
// counts must be at the start of a complete mapping (10j -> go 10 lines down)
|
|
||||||
if (countStr && !command) {
|
|
||||||
// no count for insert mode mappings
|
|
||||||
if (!this.main.count)
|
|
||||||
return this.append(event);
|
|
||||||
else if (this.main.input)
|
|
||||||
return Events.PASS;
|
|
||||||
else
|
|
||||||
this.append(event);
|
|
||||||
}
|
|
||||||
else if (this.pendingArgMap) {
|
|
||||||
let [map, command] = this.pendingArgMap;
|
|
||||||
if (!Events.isEscape(key))
|
|
||||||
return this.execute(map, null, this.count, key, command);
|
|
||||||
return Events.KILL;
|
|
||||||
}
|
|
||||||
else if (!event.skipmap && map && candidates == 0) {
|
|
||||||
this.pendingMap = null;
|
|
||||||
|
|
||||||
let count = this.pendingMotionMap ? "motionCount" : "count";
|
|
||||||
this[count] = parseInt(countStr, 10);
|
|
||||||
|
|
||||||
if (isNaN(this[count]))
|
|
||||||
this[count] = null;
|
|
||||||
|
|
||||||
if (map.arg) {
|
|
||||||
this.append(event);
|
|
||||||
this.pendingArgMap = [map, command];
|
|
||||||
}
|
|
||||||
else if (this.pendingMotionMap) {
|
|
||||||
let [map, command] = this.pendingMotionMap;
|
|
||||||
if (!Events.isEscape(key))
|
|
||||||
return this.execute(map, command, this.motionCount || this.count, null, command);
|
|
||||||
return Events.KILL;
|
|
||||||
}
|
|
||||||
else if (map.motion) {
|
|
||||||
this.buffer = "";
|
|
||||||
this.pendingMotionMap = [map, command];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (modes.replaying && !events.waitForPageLoad())
|
|
||||||
return Events.KILL;
|
|
||||||
|
|
||||||
return this.execute(map, null, this.count, null, command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!event.skipmap && this.hive.getCandidates(this.main, command) > 0) {
|
|
||||||
this.append(event);
|
|
||||||
this.pendingMap = [map, command];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.append(event);
|
|
||||||
return this.events;
|
|
||||||
}
|
|
||||||
return Events.WAIT;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
isEscape: function isEscape(event)
|
isEscape: function isEscape(event)
|
||||||
let (key = isString(event) ? event : events.toString(event))
|
let (key = isString(event) ? event : events.toString(event))
|
||||||
key === "<Esc>" || key === "<C-[>",
|
key === "<Esc>" || key === "<C-[>",
|
||||||
@@ -1253,6 +1280,11 @@ var Events = Module("events", {
|
|||||||
HTMLTextAreaElement,
|
HTMLTextAreaElement,
|
||||||
Ci.nsIDOMXULTreeElement, Ci.nsIDOMXULTextBoxElement]) ||
|
Ci.nsIDOMXULTreeElement, Ci.nsIDOMXULTextBoxElement]) ||
|
||||||
elem instanceof Window && Editor.getEditor(elem);
|
elem instanceof Window && Editor.getEditor(elem);
|
||||||
|
},
|
||||||
|
|
||||||
|
kill: function kill(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
commands: function () {
|
commands: function () {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -97,22 +97,22 @@ var Map = Class("Map", {
|
|||||||
/**
|
/**
|
||||||
* Execute the action for this mapping.
|
* Execute the action for this mapping.
|
||||||
*
|
*
|
||||||
* @param {string} motion The motion argument if accepted by this mapping.
|
* @param {object} args The arguments object for the given mapping.
|
||||||
* E.g. "w" for "dw"
|
|
||||||
* @param {number} count The associated count. E.g. "5" for "5j"
|
|
||||||
* @default -1
|
|
||||||
* @param {string} argument The normal argument if accepted by this
|
|
||||||
* mapping. E.g. "a" for "ma"
|
|
||||||
*/
|
*/
|
||||||
execute: function (motion, count, argument, command) {
|
execute: function (args) {
|
||||||
let args = { count: count, arg: argument, motion: motion, command: command };
|
if (!isObject(args)) // Backwards compatibility :(
|
||||||
|
args = iter(["motion", "count", "arg", "command"])
|
||||||
|
.map(function ([i, prop]) [prop, this[i]], arguments)
|
||||||
|
.toObject()
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
function repeat() self.action(args)
|
function repeat() self.action(args)
|
||||||
if (this.names[0] != ".") // FIXME: Kludge.
|
if (this.names[0] != ".") // FIXME: Kludge.
|
||||||
mappings.repeat = repeat;
|
mappings.repeat = repeat;
|
||||||
|
|
||||||
dactyl.assert(!this.executing, "Attempt to execute mapping recursively");
|
if (this.executing)
|
||||||
|
util.dumpStack("Attempt to execute mapping recursively: " + args.command);
|
||||||
|
dactyl.assert(!this.executing, "Attempt to execute mapping recursively: " + args.command);
|
||||||
this.executing = true;
|
this.executing = true;
|
||||||
let res = dactyl.trapErrors(repeat);
|
let res = dactyl.trapErrors(repeat);
|
||||||
this.executing = false;
|
this.executing = false;
|
||||||
|
|||||||
@@ -148,13 +148,18 @@ var Modes = Module("modes", {
|
|||||||
// Fix me.
|
// Fix me.
|
||||||
preExecute: function (map) { if (modes.main == modes.QUOTE && map.name !== "<C-v>") modes.pop() },
|
preExecute: function (map) { if (modes.main == modes.QUOTE && map.name !== "<C-v>") modes.pop() },
|
||||||
postExecute: function (map) { if (modes.main == modes.QUOTE && map.name === "<C-v>") modes.pop() },
|
postExecute: function (map) { if (modes.main == modes.QUOTE && map.name === "<C-v>") modes.pop() },
|
||||||
onEvent: function () { if (modes.main == modes.QUOTE) modes.pop() }
|
onKeyPress: function () { if (modes.main == modes.QUOTE) modes.pop() }
|
||||||
});
|
});
|
||||||
this.addMode("IGNORE", { hidden: true }, {
|
this.addMode("IGNORE", { hidden: true }, {
|
||||||
onEvent: function (event) Events.KILL,
|
onKeyPress: function (event) Events.KILL,
|
||||||
bases: []
|
bases: []
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.addMode("MENU", {
|
||||||
|
description: "Active when a menu or other pop-up is open",
|
||||||
|
input: true
|
||||||
|
});
|
||||||
|
|
||||||
// this._extended modes, can include multiple modes, and even main modes
|
// this._extended modes, can include multiple modes, and even main modes
|
||||||
this.addMode("EX", {
|
this.addMode("EX", {
|
||||||
extended: true,
|
extended: true,
|
||||||
@@ -172,14 +177,9 @@ var Modes = Module("modes", {
|
|||||||
hidden: true,
|
hidden: true,
|
||||||
input: true
|
input: true
|
||||||
});
|
});
|
||||||
this.addMode("MENU", {
|
|
||||||
extended: true,
|
|
||||||
input: true,
|
|
||||||
description: "Active when a menu or other pop-up is open",
|
|
||||||
}); // a popupmenu is active
|
|
||||||
this.addMode("LINE", {
|
this.addMode("LINE", {
|
||||||
extended: true, hidden: true
|
extended: true, hidden: true
|
||||||
}); // linewise visual mode
|
});
|
||||||
this.addMode("PROMPT", {
|
this.addMode("PROMPT", {
|
||||||
extended: true,
|
extended: true,
|
||||||
description: "Active when a prompt is open in the command line",
|
description: "Active when a prompt is open in the command line",
|
||||||
@@ -219,14 +219,9 @@ var Modes = Module("modes", {
|
|||||||
else if (modes.replaying)
|
else if (modes.replaying)
|
||||||
macromode = "replaying";
|
macromode = "replaying";
|
||||||
|
|
||||||
let ext = "";
|
|
||||||
if (this._extended & modes.MENU) // TODO: desirable?
|
|
||||||
ext += " (menu)";
|
|
||||||
ext += " --" + macromode;
|
|
||||||
|
|
||||||
let val = this._modeMap[this._main].display();
|
let val = this._modeMap[this._main].display();
|
||||||
if (val)
|
if (val)
|
||||||
return "-- " + val + ext;
|
return "-- " + val + " --" + macromode;;
|
||||||
return macromode;
|
return macromode;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -270,6 +265,8 @@ var Modes = Module("modes", {
|
|||||||
|
|
||||||
getStack: function (idx) this._modeStack[this._modeStack.length - idx - 1] || this._modeStack[0],
|
getStack: function (idx) this._modeStack[this._modeStack.length - idx - 1] || this._modeStack[0],
|
||||||
|
|
||||||
|
get stack() this._modeStack.slice(),
|
||||||
|
|
||||||
getCharModes: function (chr) (this.modeChars[chr] || []).slice(),
|
getCharModes: function (chr) (this.modeChars[chr] || []).slice(),
|
||||||
|
|
||||||
matchModes: function (obj)
|
matchModes: function (obj)
|
||||||
@@ -285,10 +282,11 @@ var Modes = Module("modes", {
|
|||||||
commandline.widgets.mode = msg || null;
|
commandline.widgets.mode = msg || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// add/remove always work on the this._extended mode only
|
remove: function remove(mode) {
|
||||||
add: function add(mode) {
|
if (this.stack.some(function (m) m.main == mode)) {
|
||||||
this._extended |= mode;
|
this.pop(mode);
|
||||||
this.show();
|
this.pop();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
delayed: [],
|
delayed: [],
|
||||||
@@ -391,13 +389,6 @@ var Modes = Module("modes", {
|
|||||||
this.pop();
|
this.pop();
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function remove(mode) {
|
|
||||||
if (this._extended & mode) {
|
|
||||||
this._extended &= ~mode;
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get recording() this._recording,
|
get recording() this._recording,
|
||||||
set recording(value) { this._recording = value; this.show(); },
|
set recording(value) { this._recording = value; this.show(); },
|
||||||
|
|
||||||
@@ -505,10 +496,13 @@ var Modes = Module("modes", {
|
|||||||
"Return to the previous mode",
|
"Return to the previous mode",
|
||||||
function () { modes.pop(); });
|
function () { modes.pop(); });
|
||||||
|
|
||||||
mappings.add([modes.MENU],
|
mappings.add([modes.MENU], ["<Esc>"],
|
||||||
["<Esc>", "<C-[>"],
|
|
||||||
"Close the current popup",
|
"Close the current popup",
|
||||||
function () Events.PASS);
|
function () Events.PASS);
|
||||||
|
|
||||||
|
mappings.add([modes.MENU], ["<C-[>"],
|
||||||
|
"Close the current popup",
|
||||||
|
function () { events.feedkeys("<Esc>") });
|
||||||
},
|
},
|
||||||
prefs: function () {
|
prefs: function () {
|
||||||
prefs.watch("accessibility.browsewithcaret", modes.closure.onCaretChange);
|
prefs.watch("accessibility.browsewithcaret", modes.closure.onCaretChange);
|
||||||
|
|||||||
@@ -46,20 +46,13 @@ var StatusLine = Module("statusline", {
|
|||||||
<!-- insertbefore="dactyl.statusBefore;" insertafter="dactyl.statusAfter;" -->
|
<!-- insertbefore="dactyl.statusBefore;" insertafter="dactyl.statusAfter;" -->
|
||||||
<hbox key="container" hidden="false" align="center" flex="1">
|
<hbox key="container" hidden="false" align="center" flex="1">
|
||||||
<stack orient="horizontal" align="stretch" flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
|
<stack orient="horizontal" align="stretch" flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
|
||||||
<hbox highlight="CmdLine StatusCmdLine" class="dactyl-container">
|
<hbox highlight="CmdLine StatusCmdLine" class="dactyl-container" id="dactyl-statusline-stack">
|
||||||
<label key="mode" crop="end" class="plain" collapsed="true"/>
|
<label key="mode" crop="end" class="plain" collapsed="true"/>
|
||||||
<stack flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
|
<stack flex="1" highlight="CmdLine StatusCmdLine" class="dactyl-container">
|
||||||
<textbox key="url" crop="end" flex="1" class="plain dactyl-status-field-url" readonly="true"/>
|
<textbox key="url" crop="end" flex="1" class="plain dactyl-status-field-url" readonly="true"/>
|
||||||
<textbox key="message" crop="end" flex="1" highlight="Normal StatusNormal" class="plain" readonly="true"/>
|
<textbox key="message" crop="end" flex="1" highlight="Normal StatusNormal" class="plain" readonly="true"/>
|
||||||
</stack>
|
</stack>
|
||||||
</hbox>
|
</hbox>
|
||||||
|
|
||||||
<hbox key="commandline" hidden="false" class="dactyl-container" highlight="Normal StatusNormal" collapsed="true">
|
|
||||||
<label key="commandline-prompt" class="dactyl-commandline-prompt plain" flex="0" crop="end" value="" collapsed="true"/>
|
|
||||||
<textbox key="commandline-command" class="dactyl-commandline-command plain" flex="1" type="text" timeout="100"
|
|
||||||
oninput={_commandline + ".onEvent(event);"} onkeyup={_commandline + ".onEvent(event);"}
|
|
||||||
onfocus={_commandline + ".onEvent(event);"} onblur={_commandline + ".onEvent(event);"}/>
|
|
||||||
</hbox>
|
|
||||||
</stack>
|
</stack>
|
||||||
<label class="plain" key="inputbuffer" flex="0"/>
|
<label class="plain" key="inputbuffer" flex="0"/>
|
||||||
<label class="plain" key="progress" flex="0"/>
|
<label class="plain" key="progress" flex="0"/>
|
||||||
|
|||||||
@@ -233,19 +233,11 @@ var Addon = Class("Addon", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
["cancelUninstall", "findUpdates", "getResourceURI", "hasResource",
|
iter.forEach(properties(config.addon), function (prop) {
|
||||||
"isCompatibleWith", "uninstall"].forEach(function (prop) {
|
let desc = Object.getOwnPropertyDescriptor(config.addon, prop);
|
||||||
|
if (callable(desc.value))
|
||||||
Addon.prototype[prop] = function proxy() this.addon[prop].apply(this.addon, arguments);
|
Addon.prototype[prop] = function proxy() this.addon[prop].apply(this.addon, arguments);
|
||||||
});
|
else
|
||||||
|
|
||||||
["aboutURL", "appDisabled", "applyBackgroundUpdates", "blocklistState",
|
|
||||||
"contributors", "creator", "description", "developers", "homepageURL",
|
|
||||||
"iconURL", "id", "install", "installDate", "isActive", "isCompatible",
|
|
||||||
"isPlatformCompatible", "name", "operationsRequiringRestart",
|
|
||||||
"optionsURL", "pendingOperations", "pendingUpgrade", "permissions",
|
|
||||||
"providesUpdatesSecurely", "releaseNotesURI", "scope", "screenshots",
|
|
||||||
"size", "sourceURI", "translators", "type", "updateDate",
|
|
||||||
"userDisabled", "version"].forEach(function (prop) {
|
|
||||||
Object.defineProperty(Addon.prototype, prop, {
|
Object.defineProperty(Addon.prototype, prop, {
|
||||||
get: function get_proxy() this.addon[prop],
|
get: function get_proxy() this.addon[prop],
|
||||||
set: function set_proxy(val) this.addon[prop] = val
|
set: function set_proxy(val) this.addon[prop] = val
|
||||||
|
|||||||
@@ -807,10 +807,23 @@ Class.prototype = {
|
|||||||
};
|
};
|
||||||
memoize(Class.prototype, "closure", function () {
|
memoize(Class.prototype, "closure", function () {
|
||||||
const self = this;
|
const self = this;
|
||||||
function closure(fn) function () fn.apply(self, arguments);
|
function closure(fn) function () {
|
||||||
for (let k in iter(properties(this), properties(this, true)))
|
try {
|
||||||
|
return fn.apply(self, arguments);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
util.reportError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iter(properties(this), properties(this, true)).forEach(function (k) {
|
||||||
if (!this.__lookupGetter__(k) && callable(this[k]))
|
if (!this.__lookupGetter__(k) && callable(this[k]))
|
||||||
closure[k] = closure(this[k]);
|
closure[k] = closure(this[k]);
|
||||||
|
else if (!(k in closure || k in Object.prototype))
|
||||||
|
Object.defineProperty(closure, k, {
|
||||||
|
get: function get_proxy() self[k],
|
||||||
|
set: function set_proxy(val) self[k] = val,
|
||||||
|
});
|
||||||
|
}, this);
|
||||||
return closure;
|
return closure;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1036,8 +1049,8 @@ var Timer = Class("Timer", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the UTF-8 encoded value of a string mis-encoded into
|
* Idempotent function which returns the UTF-8 encoded value of an
|
||||||
* ISO-8859-1.
|
* improperly-decoded string.
|
||||||
*
|
*
|
||||||
* @param {string} str
|
* @param {string} str
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
|
|||||||
@@ -501,6 +501,8 @@ var ConfigBase = Class("ConfigBase", {
|
|||||||
Button::after content: "]"; color: gray; text-decoration: none !important;
|
Button::after content: "]"; color: gray; text-decoration: none !important;
|
||||||
Button:not([collapsed]) ~ Button:not([collapsed])::before content: "/[";
|
Button:not([collapsed]) ~ Button:not([collapsed])::before content: "/[";
|
||||||
|
|
||||||
|
Buttons
|
||||||
|
|
||||||
DownloadCell display: table-cell; padding: 0 1ex;
|
DownloadCell display: table-cell; padding: 0 1ex;
|
||||||
|
|
||||||
Downloads display: table; margin: 0; padding: 0;
|
Downloads display: table; margin: 0; padding: 0;
|
||||||
@@ -510,8 +512,6 @@ var ConfigBase = Class("ConfigBase", {
|
|||||||
Download display: table-row;
|
Download display: table-row;
|
||||||
Download:not([active]) color: gray;
|
Download:not([active]) color: gray;
|
||||||
|
|
||||||
Buttons
|
|
||||||
|
|
||||||
Download>*;;;DownloadCell
|
Download>*;;;DownloadCell
|
||||||
DownloadButtons
|
DownloadButtons
|
||||||
DownloadPercent
|
DownloadPercent
|
||||||
|
|||||||
@@ -166,10 +166,10 @@ var DownloadList = Class("DownloadList",
|
|||||||
Ci.nsISupportsWeakReference]), {
|
Ci.nsISupportsWeakReference]), {
|
||||||
init: function init(modules, filter) {
|
init: function init(modules, filter) {
|
||||||
this.modules = modules;
|
this.modules = modules;
|
||||||
|
this.filter = filter && filter.toLowerCase();
|
||||||
this.nodes = {
|
this.nodes = {
|
||||||
commandTarget: this
|
commandTarget: this
|
||||||
};
|
};
|
||||||
this.filter = filter && filter.toLowerCase();
|
|
||||||
this.downloads = {};
|
this.downloads = {};
|
||||||
},
|
},
|
||||||
cleanup: function cleanup() {
|
cleanup: function cleanup() {
|
||||||
|
|||||||
@@ -188,10 +188,17 @@ var Highlights = Module("Highlight", {
|
|||||||
* @param {Node} node
|
* @param {Node} node
|
||||||
* @param {string} group
|
* @param {string} group
|
||||||
*/
|
*/
|
||||||
highlightNode: function (node, group) {
|
highlightNode: function (node, group, applyBindings) {
|
||||||
node.setAttributeNS(NS.uri, "highlight", group);
|
node.setAttributeNS(NS.uri, "highlight", group);
|
||||||
for each (let h in group.split(" "))
|
|
||||||
this.loaded[h] = true;
|
let groups = group.split(" ");
|
||||||
|
for each (let group in groups)
|
||||||
|
this.loaded[group] = true;
|
||||||
|
|
||||||
|
if (applyBindings)
|
||||||
|
for each (let group in groups)
|
||||||
|
if (group in template.bindings)
|
||||||
|
template.bindings[group](node, applyBindings);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -270,9 +270,11 @@ var Overlay = Module("Overlay", {
|
|||||||
|
|
||||||
modules.events.addSessionListener(window, "unload", function onUnload() {
|
modules.events.addSessionListener(window, "unload", function onUnload() {
|
||||||
window.removeEventListener("unload", onUnload.wrapped, false);
|
window.removeEventListener("unload", onUnload.wrapped, false);
|
||||||
for (let [, mod] in iter(modules))
|
for (let prop in properties(modules)) {
|
||||||
if (mod instanceof ModuleBase && "destroy" in mod)
|
let desc = Object.getOwnPropertyDescriptor(modules, prop);
|
||||||
util.trapErrors(mod.destroy, mod);
|
if (desc.value instanceof ModuleBase && "destroy" in desc.value)
|
||||||
|
util.trapErrors(desc.value.destroy, desc.value);
|
||||||
|
}
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -131,6 +131,16 @@ var Template = Module("Template", {
|
|||||||
update: function update() {
|
update: function update() {
|
||||||
this.collapsed = !this.commandAllowed;
|
this.collapsed = !this.commandAllowed;
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
Events: Class("Events", Binding, {
|
||||||
|
init: function init(node, params) {
|
||||||
|
init.supercall(this, node);
|
||||||
|
|
||||||
|
let obj = params.eventTarget;
|
||||||
|
for (let [event, handler] in Iterator(obj[this.getAttribute("events") || "events"]))
|
||||||
|
node.addEventListener(event, obj.closure(handler), false);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -329,7 +339,7 @@ var Template = Module("Template", {
|
|||||||
let re = util.regexp(<![CDATA[
|
let re = util.regexp(<![CDATA[
|
||||||
(?P<pre> [/\s]|^)
|
(?P<pre> [/\s]|^)
|
||||||
(?P<tag> '[\w-]+' | :(?:[\w-]+|!) | (?:._)?<[\w-]+> )
|
(?P<tag> '[\w-]+' | :(?:[\w-]+|!) | (?:._)?<[\w-]+> )
|
||||||
(?= [[!,;./\s]|$)
|
(?= [[\)!,;./\s]|$)
|
||||||
]]>, "g");
|
]]>, "g");
|
||||||
return this.highlightSubstrings(str, (function () {
|
return this.highlightSubstrings(str, (function () {
|
||||||
for (let res in re.iterate(str))
|
for (let res in re.iterate(str))
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
|||||||
([^]*?) // 1
|
([^]*?) // 1
|
||||||
(?:
|
(?:
|
||||||
(<\{) | // 2
|
(<\{) | // 2
|
||||||
(< ((?:[a-z]-)?[a-z-]*?) >) | // 3 4
|
(< ((?:[a-z]-)?[a-z-]+?) >) | // 3 4
|
||||||
(\}>) // 5
|
(\}>) // 5
|
||||||
)
|
)
|
||||||
]]>, "giy");
|
]]>, "giy");
|
||||||
@@ -1602,19 +1602,17 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
|||||||
case "element":
|
case "element":
|
||||||
let domnode = doc.createElementNS(node.namespace(), node.localName());
|
let domnode = doc.createElementNS(node.namespace(), node.localName());
|
||||||
|
|
||||||
|
for each (let attr in node.@*::*)
|
||||||
|
if (attr.name() != "highlight")
|
||||||
|
domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr));
|
||||||
|
|
||||||
for each (let child in node.*::*)
|
for each (let child in node.*::*)
|
||||||
domnode.appendChild(xmlToDom(child, doc, nodes));
|
domnode.appendChild(xmlToDom(child, doc, nodes));
|
||||||
if (nodes && node.@key)
|
if (nodes && node.@key)
|
||||||
nodes[node.@key] = domnode;
|
nodes[node.@key] = domnode;
|
||||||
|
|
||||||
for each (let attr in node.@*::*)
|
if (node.@highlight)
|
||||||
if (attr.name() != "highlight")
|
highlight.highlightNode(domnode, String(node.@highlight), nodes || true);
|
||||||
domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr));
|
|
||||||
else {
|
|
||||||
highlight.highlightNode(domnode, String(attr));
|
|
||||||
if (attr in template.bindings)
|
|
||||||
template.bindings[attr](domnode, nodes);
|
|
||||||
}
|
|
||||||
return domnode;
|
return domnode;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
completion system customization.
|
completion system customization.
|
||||||
* The external editor can now be configured to open to a given
|
* The external editor can now be configured to open to a given
|
||||||
line number and column, used for opening source links and
|
line number and column, used for opening source links and
|
||||||
editing input fields with <C-i>. See :h 'editor'.
|
editing input fields with i_<C-i>. See :h 'editor'.
|
||||||
* Command changes:
|
* Command changes:
|
||||||
- :viusage, :optionusage and :exusage were replaced with :listkeys,
|
- :viusage, :optionusage and :exusage were replaced with :listkeys,
|
||||||
:listoptions and :listcommands, providing more powerful and
|
:listoptions and :listcommands, providing more powerful and
|
||||||
@@ -66,16 +66,17 @@
|
|||||||
and linking to source code locations).
|
and linking to source code locations).
|
||||||
- :downloads now opens a download list in the multi-line output
|
- :downloads now opens a download list in the multi-line output
|
||||||
buffer.
|
buffer.
|
||||||
- :extensions has been replaced with a more powerful :addons
|
- :extensions has been replaced with a more powerful :addons.
|
||||||
- Added :cookies command.
|
- Added :cookies command.
|
||||||
* :extadd now supports remote URLs as well as local files on Firefox 4.
|
- :extadd now supports remote URLs as well as local files on Firefox 4.
|
||||||
* Added :if/:elseif/:else/:endif conditionals.
|
- Added :if/:elseif/:else/:endif conditionals.
|
||||||
- Added -charset and -post to :bmark.
|
- Added -charset and -post to :bmark.
|
||||||
- Added -keyword, -tags, -title to :delbmarks.
|
- Added -keyword, -tags, -title to :delbmarks.
|
||||||
- Added :extrehash, :exttoggle, :extupdate, and :rehash commands.
|
- Added :extrehash, :exttoggle, :extupdate, and :rehash commands.
|
||||||
- Added :feedkeys command.
|
- Added :feedkeys command.
|
||||||
- Added -sort option to :history.
|
- Added -sort option to :history.
|
||||||
- Added several new options, including -javascript, to :abbrev and :map.
|
- Added several new options, including -javascript, to :abbreviate and
|
||||||
|
:map.
|
||||||
- Added :mksyntax command to auto-generate Vim syntax files.
|
- Added :mksyntax command to auto-generate Vim syntax files.
|
||||||
- :open now only opens files beginning with /, ./, ../, or ~/
|
- :open now only opens files beginning with /, ./, ../, or ~/
|
||||||
- :saveas now provides completions for default file names, and
|
- :saveas now provides completions for default file names, and
|
||||||
@@ -87,7 +88,7 @@
|
|||||||
- Added :yank command.
|
- Added :yank command.
|
||||||
- :delmarks, :marks and :qmarks now also accept ranges, same as
|
- :delmarks, :marks and :qmarks now also accept ranges, same as
|
||||||
:delqmarks.
|
:delqmarks.
|
||||||
- :command now accepts comma-separated alternative command names
|
- :command now accepts comma-separated alternative command names.
|
||||||
- :command -complete custom now also accepts a completions array, see
|
- :command -complete custom now also accepts a completions array, see
|
||||||
:h :command-completion-custom.
|
:h :command-completion-custom.
|
||||||
* Improvements to :style and :highlight:
|
* Improvements to :style and :highlight:
|
||||||
@@ -127,7 +128,7 @@
|
|||||||
* Option changes:
|
* Option changes:
|
||||||
- Added "bookmarks", "diverted", and "links" to 'activate'
|
- Added "bookmarks", "diverted", and "links" to 'activate'
|
||||||
option.
|
option.
|
||||||
- Added 'altwildmode' and <A-Tab> command-line key binding.
|
- Added 'altwildmode' and c_<A-Tab> command-line key binding.
|
||||||
- Added 'autocomplete' option for specifying which completion
|
- Added 'autocomplete' option for specifying which completion
|
||||||
groups should be auto-completed.
|
groups should be auto-completed.
|
||||||
- Added 'banghist' option.
|
- Added 'banghist' option.
|
||||||
@@ -135,7 +136,7 @@
|
|||||||
- '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.
|
triggers when the URL begins as above.
|
||||||
- Added 'passkeys' option.
|
- Added 'passkeys' option.
|
||||||
- Changed 'urlseparator' default value to '|'.
|
- Changed 'urlseparator' default value to "|".
|
||||||
- Added "passwords" and "venkman" dialogs to :dialog.
|
- Added "passwords" and "venkman" dialogs to :dialog.
|
||||||
- Added 'wildanchor' option.
|
- Added 'wildanchor' option.
|
||||||
- Added 'cookies', 'cookieaccept', and 'cookielifetime' options.
|
- Added 'cookies', 'cookieaccept', and 'cookielifetime' options.
|
||||||
@@ -150,7 +151,7 @@
|
|||||||
* Completion list now behaves better when the multi-line output
|
* Completion list now behaves better when the multi-line output
|
||||||
window is displayed.
|
window is displayed.
|
||||||
* Major help system improvements:
|
* Major help system improvements:
|
||||||
- Plugins may now provide full-fledged ':help' documentation.
|
- Plugins may now provide full-fledged :help documentation.
|
||||||
- Add basic plugin authorship documentation.
|
- Add basic plugin authorship documentation.
|
||||||
- The help system is newly modularized and features significant
|
- The help system is newly modularized and features significant
|
||||||
updates, rewrites, and formatting improvements.
|
updates, rewrites, and formatting improvements.
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ BUGS:
|
|||||||
- :sidebar improvements (:sidebar! Downloads while downloads is open should refocus the sidebar)
|
- :sidebar improvements (:sidebar! Downloads while downloads is open should refocus the sidebar)
|
||||||
- ;s saves the page rather than the image
|
- ;s saves the page rather than the image
|
||||||
- RC file is sourced once per window
|
- RC file is sourced once per window
|
||||||
- the :help version-information page is no longer generated
|
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
8 registers
|
8 registers
|
||||||
@@ -38,7 +37,6 @@ FEATURES:
|
|||||||
7 describe-key command (prompt for a key and display its binding with documentation)
|
7 describe-key command (prompt for a key and display its binding with documentation)
|
||||||
7 Specify all INSERT mode mappings rather than falling through to the host apps
|
7 Specify all INSERT mode mappings rather than falling through to the host apps
|
||||||
mystery meat mappings.
|
mystery meat mappings.
|
||||||
7 consider generating most of :help :index
|
|
||||||
7 use ctrl-n/p in insert mode for word completion
|
7 use ctrl-n/p in insert mode for word completion
|
||||||
7 implement QuickFix window based on ItemList
|
7 implement QuickFix window based on ItemList
|
||||||
7 wherever possible: get rid of dialogs and ask console-like dialog questions
|
7 wherever possible: get rid of dialogs and ask console-like dialog questions
|
||||||
@@ -70,4 +68,3 @@ FEATURES:
|
|||||||
3 Splitting Windows with [:sp :vsp ctrl-w,s ctrl-w,v] and closing with [ctrl-w,q], moving with [ctrl-w,w or tab]
|
3 Splitting Windows with [:sp :vsp ctrl-w,s ctrl-w,v] and closing with [ctrl-w,q], moving with [ctrl-w,w or tab]
|
||||||
have a look into the split browser extension
|
have a look into the split browser extension
|
||||||
1 Reformat dactyl/HACKING so that git diff can find sections and report changes @ somewhere
|
1 Reformat dactyl/HACKING so that git diff can find sections and report changes @ somewhere
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user