mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-01-06 00:34:11 +01:00
Merge mode-refactoring.
This commit is contained in:
@@ -271,7 +271,9 @@ const Buffer = Module("buffer", {
|
||||
statusline.updateUrl();
|
||||
statusline.updateProgress();
|
||||
|
||||
autocommands.trigger("LocationChange", { url: buffer.URL });
|
||||
util.timeout(function () {
|
||||
autocommands.trigger("LocationChange", { url: buffer.URL });
|
||||
});
|
||||
|
||||
// if this is not delayed we get the position of the old buffer
|
||||
util.timeout(function () {
|
||||
@@ -1532,11 +1534,7 @@ const Buffer = Module("buffer", {
|
||||
|
||||
mappings.add(myModes, ["i", "<Insert>"],
|
||||
"Start caret mode",
|
||||
function () {
|
||||
// setting this option notifies an observer which takes care of the
|
||||
// mode setting
|
||||
options.setPref("accessibility.browsewithcaret", true);
|
||||
});
|
||||
function () { modes.push(modes.CARET); });
|
||||
|
||||
mappings.add(myModes, ["<C-c>"],
|
||||
"Stop loading the current web page",
|
||||
|
||||
@@ -440,8 +440,13 @@ const CommandLine = Module("commandline", {
|
||||
* @param {number} extendedMode
|
||||
*/
|
||||
open: function open(prompt, cmd, extendedMode) {
|
||||
this.widgets.message = null;
|
||||
|
||||
modes.push(modes.COMMAND_LINE, this.currentExtendedMode, {
|
||||
leave: commandline.closure.leave
|
||||
leave: function (params) {
|
||||
if (params.pop)
|
||||
commandline.leave();
|
||||
}
|
||||
});
|
||||
|
||||
this.currentExtendedMode = extendedMode || null;
|
||||
@@ -474,8 +479,10 @@ const CommandLine = Module("commandline", {
|
||||
this.hideCompletions();
|
||||
|
||||
if (!this._keepCommand || this._silent || this._quiet) {
|
||||
commandline.updateMorePrompt();
|
||||
this.hide();
|
||||
modes.delay(function () {
|
||||
this.updateMorePrompt();
|
||||
this.hide();
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -485,7 +492,7 @@ const CommandLine = Module("commandline", {
|
||||
return this._lastCommand;
|
||||
},
|
||||
set command(val) {
|
||||
if (this.commandVisible)
|
||||
if (this.commandVisible && (modes.extended & modes.EX))
|
||||
return this.widgets.command = val;
|
||||
return this._lastCommand = val;
|
||||
},
|
||||
@@ -552,6 +559,7 @@ const CommandLine = Module("commandline", {
|
||||
let doc = this.widgets.multilineOutput.contentDocument;
|
||||
let win = this.widgets.multilineOutput.contentWindow;
|
||||
|
||||
this.widgets.message = null;
|
||||
if (!this.commandVisible)
|
||||
this.hide();
|
||||
|
||||
@@ -559,7 +567,9 @@ const CommandLine = Module("commandline", {
|
||||
|
||||
this._startHints = false;
|
||||
if (!(modes.extended & modes.OUTPUT_MULTILINE))
|
||||
modes.push(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE);
|
||||
modes.push(modes.COMMAND_LINE, modes.OUTPUT_MULTILINE, {
|
||||
onEvent: this.closure.onMultilineOutputEvent
|
||||
});
|
||||
|
||||
// If it's already XML, assume it knows what it's doing.
|
||||
// Otherwise, white space is significant.
|
||||
@@ -687,15 +697,13 @@ const CommandLine = Module("commandline", {
|
||||
cancel: extra.onCancel
|
||||
};
|
||||
|
||||
modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended, {
|
||||
leave: function (newMode) {
|
||||
commandline.leave(newMode);
|
||||
if (extra.leave)
|
||||
extra.leave(newMode);
|
||||
},
|
||||
restore: function (newMode) { extra.restore && extra.restore(newMode) },
|
||||
save: function (newMode) { extra.save && extra.save(newMode) }
|
||||
});
|
||||
modes.push(modes.COMMAND_LINE, modes.PROMPT | extra.extended,
|
||||
update(Object.create(extra), {
|
||||
leave: function leave(stack) {
|
||||
commandline.leave(stack);
|
||||
leave.supercall(this, stack);
|
||||
}
|
||||
}));
|
||||
this.currentExtendedMode = modes.PROMPT;
|
||||
|
||||
this.widgets.prompt = !prompt ? null : [extra.promptHighlight || "Question", prompt];
|
||||
@@ -927,14 +935,7 @@ const CommandLine = Module("commandline", {
|
||||
}
|
||||
|
||||
if (event instanceof MouseEvent)
|
||||
return;
|
||||
|
||||
if (this._startHints) {
|
||||
statusline.updateInputBuffer("");
|
||||
this._startHints = false;
|
||||
hints.show(key, { window: win });
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
|
||||
function isScrollable() !win.scrollMaxY == 0;
|
||||
function atEnd() win.scrollY / win.scrollMaxY >= 1;
|
||||
@@ -946,7 +947,7 @@ const CommandLine = Module("commandline", {
|
||||
|
||||
case ":":
|
||||
commandline.open(":", "", modes.EX);
|
||||
return;
|
||||
return false;
|
||||
|
||||
// down a line
|
||||
case "j":
|
||||
@@ -1058,9 +1059,8 @@ const CommandLine = Module("commandline", {
|
||||
break;
|
||||
|
||||
case ";":
|
||||
statusline.updateInputBuffer(";");
|
||||
this._startHints = true;
|
||||
break;
|
||||
hints.open(";", { window: win });
|
||||
return false;
|
||||
|
||||
// unmapped key
|
||||
default:
|
||||
@@ -1078,6 +1078,7 @@ const CommandLine = Module("commandline", {
|
||||
}
|
||||
else
|
||||
commandline.updateMorePrompt(showMorePrompt, showMoreHelpPrompt);
|
||||
return false;
|
||||
},
|
||||
|
||||
getSpaceNeeded: function getSpaceNeeded() {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
sandbox.__proto__ = proto || modules;
|
||||
return sandbox;
|
||||
}
|
||||
const jsmodules = { dump: function dump_(arg) window.dump("dactyl: " + arg + "\n") };
|
||||
const jsmodules = {};
|
||||
const modules = {
|
||||
__proto__: jsmodules,
|
||||
get content() window.content,
|
||||
|
||||
@@ -162,7 +162,7 @@ const Dactyl = Module("dactyl", {
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
clipboardRead: function clipboardRead() {
|
||||
clipboardRead: function clipboardRead(getClipboard) {
|
||||
let str = null;
|
||||
|
||||
try {
|
||||
@@ -171,7 +171,7 @@ const Dactyl = Module("dactyl", {
|
||||
|
||||
transferable.addDataFlavor("text/unicode");
|
||||
|
||||
if (clipboard.supportsSelectionClipboard())
|
||||
if (!getClipboard && clipboard.supportsSelectionClipboard())
|
||||
clipboard.getData(transferable, clipboard.kSelectionClipboard);
|
||||
else
|
||||
clipboard.getData(transferable, clipboard.kGlobalClipboard);
|
||||
|
||||
@@ -16,30 +16,11 @@ const Editor = Module("editor", {
|
||||
//
|
||||
this._lastFindChar = null;
|
||||
this._lastFindCharFunc = null;
|
||||
|
||||
// Hack?
|
||||
dactyl.registerObserver("modeChange", function (oldMode, newMode, stack) {
|
||||
switch (oldMode[0]) {
|
||||
case modes.TEXTAREA:
|
||||
case modes.INSERT:
|
||||
editor.unselectText();
|
||||
break;
|
||||
|
||||
case modes.VISUAL:
|
||||
if (newMode[0] == modes.CARET) {
|
||||
try { // clear any selection made; a simple if (selection) does not work
|
||||
let selection = window.content.getSelection();
|
||||
selection.collapseToStart();
|
||||
}
|
||||
catch (e) {}
|
||||
}
|
||||
else
|
||||
editor.unselectText();
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
get isCaret() modes.getStack(1).main === modes.CARET,
|
||||
get isTextEdit() modes.getStack(1).main === modes.TEXT_EDIT,
|
||||
|
||||
line: function () {
|
||||
let line = 1;
|
||||
let text = Editor.getEditor().value;
|
||||
@@ -60,12 +41,15 @@ const Editor = Module("editor", {
|
||||
return col;
|
||||
},
|
||||
|
||||
unselectText: function () {
|
||||
unselectText: function (toEnd) {
|
||||
let elem = dactyl.focus;
|
||||
// A error occurs if the element has been removed when "elem.selectionStart" is executed.
|
||||
try {
|
||||
if (elem && elem.selectionEnd)
|
||||
elem.selectionEnd = elem.selectionStart;
|
||||
if (toEnd)
|
||||
elem.selectionStart = elem.selectionEnd;
|
||||
else
|
||||
elem.selectionEnd = elem.selectionStart;
|
||||
}
|
||||
catch (e) {}
|
||||
},
|
||||
@@ -75,7 +59,7 @@ const Editor = Module("editor", {
|
||||
return text.substring(Editor.getEditor().selectionStart, Editor.getEditor().selectionEnd);
|
||||
},
|
||||
|
||||
pasteClipboard: function () {
|
||||
pasteClipboard: function (clipboard, toStart) {
|
||||
if (dactyl.has("WINNT")) {
|
||||
this.executeCommand("cmd_paste");
|
||||
return;
|
||||
@@ -85,7 +69,7 @@ const Editor = Module("editor", {
|
||||
let elem = dactyl.focus;
|
||||
|
||||
if (elem.setSelectionRange) {
|
||||
let text = dactyl.clipboardRead();
|
||||
let text = dactyl.clipboardRead(clipboard);
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
@@ -101,7 +85,7 @@ const Editor = Module("editor", {
|
||||
let tempStr2 = text;
|
||||
let tempStr3 = elem.value.substring(rangeEnd);
|
||||
elem.value = tempStr1 + tempStr2 + tempStr3;
|
||||
elem.selectionStart = rangeStart + tempStr2.length;
|
||||
elem.selectionStart = rangeStart + (toStart ? 0 : tempStr2.length);
|
||||
elem.selectionEnd = elem.selectionStart;
|
||||
|
||||
elem.scrollTop = curTop;
|
||||
@@ -153,7 +137,8 @@ const Editor = Module("editor", {
|
||||
count--;
|
||||
}
|
||||
|
||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
||||
if (modes.main != modes.VISUAL)
|
||||
modes.push(modes.VISUAL);
|
||||
|
||||
switch (motion) {
|
||||
case "j":
|
||||
@@ -204,16 +189,16 @@ const Editor = Module("editor", {
|
||||
switch (cmd) {
|
||||
case "d":
|
||||
this.executeCommand("cmd_delete", 1);
|
||||
// need to reset the mode as the visual selection changes it
|
||||
modes.main = modes.TEXTAREA;
|
||||
modes.pop(modes.TEXT_EDIT);
|
||||
break;
|
||||
case "c":
|
||||
this.executeCommand("cmd_delete", 1);
|
||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
||||
modes.pop(modes.TEXT_EDIT);
|
||||
modes.push(modes.INSERT);
|
||||
break;
|
||||
case "y":
|
||||
this.executeCommand("cmd_copy", 1);
|
||||
this.unselectText();
|
||||
modes.pop(modes.TEXT_EDIT);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -451,25 +436,43 @@ const Editor = Module("editor", {
|
||||
mappings: function () {
|
||||
var myModes = [modes.INSERT, modes.COMMAND_LINE];
|
||||
|
||||
// add mappings for commands like h,j,k,l,etc. in CARET, VISUAL and TEXTAREA mode
|
||||
function addMovementMap(keys, hasCount, caretModeMethod, caretModeArg, textareaCommand, visualTextareaCommand) {
|
||||
// add mappings for commands like h,j,k,l,etc. in CARET, VISUAL and TEXT_EDIT mode
|
||||
function addMovementMap(keys, hasCount, caretModeMethod, caretModeArg, textEditCommand, visualTextEditCommand) {
|
||||
let extraInfo = {};
|
||||
if (hasCount)
|
||||
extraInfo.count = true;
|
||||
|
||||
function caretExecute(arg, again) {
|
||||
function fixSelection() {
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(RangeFind.endpoint(
|
||||
RangeFind.nodeRange(buffer.focusedFrame.document.documentElement),
|
||||
true));
|
||||
}
|
||||
|
||||
let controller = buffer.selectionController;
|
||||
let sel = controller.getSelection(controller.SELECTION_NORMAL);
|
||||
if (!sel.rangeCount) // Hack.
|
||||
fixSelection();
|
||||
|
||||
try {
|
||||
controller[caretModeMethod](caretModeArg, arg);
|
||||
}
|
||||
catch (e) {
|
||||
dactyl.assert(again && e.result === Cr.NS_ERROR_FAILURE);
|
||||
fixSelection();
|
||||
caretExecute(arg, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mappings.add([modes.CARET], keys, "",
|
||||
function (count) {
|
||||
if (typeof count != "number" || count < 1)
|
||||
count = 1;
|
||||
|
||||
let controller = buffer.selectionController;
|
||||
let sel = controller.getSelection(controller.SELECTION_NORMAL);
|
||||
if (!sel.rangeCount) // Hack.
|
||||
sel.addRange(RangeFind.endpoint(
|
||||
RangeFind.nodeRange(buffer.focusedFrame.document.documentElement),
|
||||
true));
|
||||
while (count--)
|
||||
controller[caretModeMethod](caretModeArg, false);
|
||||
caretExecute(false, true);
|
||||
},
|
||||
extraInfo);
|
||||
|
||||
@@ -479,41 +482,41 @@ const Editor = Module("editor", {
|
||||
count = 1;
|
||||
|
||||
let controller = buffer.selectionController;
|
||||
while (count--) {
|
||||
if (modes.extended & modes.TEXTAREA) {
|
||||
if (typeof visualTextareaCommand == "function")
|
||||
visualTextareaCommand();
|
||||
while (count-- && modes.main == modes.VISUAL) {
|
||||
if (editor.isTextEdit) {
|
||||
if (typeof visualTextEditCommand == "function")
|
||||
visualTextEditCommand();
|
||||
else
|
||||
editor.executeCommand(visualTextareaCommand);
|
||||
editor.executeCommand(visualTextEditCommand);
|
||||
}
|
||||
else
|
||||
controller[caretModeMethod](caretModeArg, true);
|
||||
caretExecute(true, true);
|
||||
}
|
||||
},
|
||||
extraInfo);
|
||||
|
||||
mappings.add([modes.TEXTAREA], keys, "",
|
||||
mappings.add([modes.TEXT_EDIT], keys, "",
|
||||
function (count) {
|
||||
if (typeof count != "number" || count < 1)
|
||||
count = 1;
|
||||
|
||||
editor.executeCommand(textareaCommand, count);
|
||||
editor.executeCommand(textEditCommand, count);
|
||||
},
|
||||
extraInfo);
|
||||
}
|
||||
|
||||
// add mappings for commands like i,a,s,c,etc. in TEXTAREA mode
|
||||
// add mappings for commands like i,a,s,c,etc. in TEXT_EDIT mode
|
||||
function addBeginInsertModeMap(keys, commands) {
|
||||
mappings.add([modes.TEXTAREA], keys, "",
|
||||
mappings.add([modes.TEXT_EDIT], keys, "",
|
||||
function (count) {
|
||||
commands.forEach(function (cmd)
|
||||
editor.executeCommand(cmd, 1));
|
||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
||||
modes.push(modes.INSERT);
|
||||
});
|
||||
}
|
||||
|
||||
function addMotionMap(key) {
|
||||
mappings.add([modes.TEXTAREA], [key],
|
||||
mappings.add([modes.TEXT_EDIT], [key],
|
||||
"Motion command",
|
||||
function (motion, count) { editor.executeCommandWithMotion(key, motion, count); },
|
||||
{ count: true, motion: true });
|
||||
@@ -529,7 +532,7 @@ const Editor = Module("editor", {
|
||||
editor.executeCommand("cmd_selectLineNext");
|
||||
}
|
||||
|
||||
// KEYS COUNT CARET TEXTAREA VISUAL_TEXTAREA
|
||||
// KEYS COUNT CARET TEXT_EDIT VISUAL_TEXT_EDIT
|
||||
addMovementMap(["k", "<Up>"], true, "lineMove", false, "cmd_linePrevious", selectPreviousLine);
|
||||
addMovementMap(["j", "<Down>", "<Return>"], true, "lineMove", true, "cmd_lineNext", selectNextLine);
|
||||
addMovementMap(["h", "<Left>", "<BS>"], true, "characterMove", false, "cmd_charPrevious", "cmd_selectCharPrevious");
|
||||
@@ -608,7 +611,12 @@ const Editor = Module("editor", {
|
||||
|
||||
mappings.add([modes.INSERT],
|
||||
["<C-t>"], "Edit text field in Vi mode",
|
||||
function () { dactyl.mode = modes.TEXTAREA; });
|
||||
function () {
|
||||
if (!editor.isTextEdit)
|
||||
modes.push(modes.TEXT_EDIT);
|
||||
else
|
||||
dactyl.beep();
|
||||
});
|
||||
|
||||
mappings.add([modes.INSERT],
|
||||
["<Space>", "<Return>"], "Expand insert mode abbreviation",
|
||||
@@ -623,67 +631,67 @@ const Editor = Module("editor", {
|
||||
["<C-]>", "<C-5>"], "Expand insert mode abbreviation",
|
||||
function () { editor.expandAbbreviation(modes.INSERT); });
|
||||
|
||||
// textarea mode
|
||||
mappings.add([modes.TEXTAREA],
|
||||
// text edit mode
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["u"], "Undo",
|
||||
function (count) {
|
||||
editor.executeCommand("cmd_undo", count);
|
||||
dactyl.mode = modes.TEXTAREA;
|
||||
editor.unselectText();
|
||||
},
|
||||
{ count: true });
|
||||
|
||||
mappings.add([modes.TEXTAREA],
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["<C-r>"], "Redo",
|
||||
function (count) {
|
||||
editor.executeCommand("cmd_redo", count);
|
||||
dactyl.mode = modes.TEXTAREA;
|
||||
editor.unselectText();
|
||||
},
|
||||
{ count: true });
|
||||
|
||||
mappings.add([modes.TEXTAREA],
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["D"], "Delete the characters under the cursor until the end of the line",
|
||||
function () { editor.executeCommand("cmd_deleteToEndOfLine"); });
|
||||
|
||||
mappings.add([modes.TEXTAREA],
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["o"], "Open line below current",
|
||||
function (count) {
|
||||
editor.executeCommand("cmd_endLine", 1);
|
||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
||||
modes.push(modes.INSERT);
|
||||
events.feedkeys("<Return>");
|
||||
});
|
||||
|
||||
mappings.add([modes.TEXTAREA],
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["O"], "Open line above current",
|
||||
function (count) {
|
||||
editor.executeCommand("cmd_beginLine", 1);
|
||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
||||
modes.push(modes.INSERT);
|
||||
events.feedkeys("<Return>");
|
||||
editor.executeCommand("cmd_linePrevious", 1);
|
||||
});
|
||||
|
||||
mappings.add([modes.TEXTAREA],
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["X"], "Delete character to the left",
|
||||
function (count) { editor.executeCommand("cmd_deleteCharBackward", count); },
|
||||
{ count: true });
|
||||
|
||||
mappings.add([modes.TEXTAREA],
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["x"], "Delete character to the right",
|
||||
function (count) { editor.executeCommand("cmd_deleteCharForward", count); },
|
||||
{ count: true });
|
||||
|
||||
// visual mode
|
||||
mappings.add([modes.CARET, modes.TEXTAREA],
|
||||
mappings.add([modes.CARET, modes.TEXT_EDIT],
|
||||
["v"], "Start visual mode",
|
||||
function (count) { modes.set(modes.VISUAL, dactyl.mode); });
|
||||
function (count) { modes.push(modes.VISUAL); });
|
||||
|
||||
mappings.add([modes.VISUAL],
|
||||
["v"], "End visual mode",
|
||||
function (count) { events.onEscape(); });
|
||||
|
||||
mappings.add([modes.TEXTAREA],
|
||||
mappings.add([modes.TEXT_EDIT],
|
||||
["V"], "Start visual line mode",
|
||||
function (count) {
|
||||
modes.set(modes.VISUAL, modes.TEXTAREA | modes.LINE);
|
||||
modes.push(modes.VISUAL, modes.LINE);
|
||||
editor.executeCommand("cmd_beginLine", 1);
|
||||
editor.executeCommand("cmd_selectLineNext", 1);
|
||||
});
|
||||
@@ -691,17 +699,17 @@ const Editor = Module("editor", {
|
||||
mappings.add([modes.VISUAL],
|
||||
["c", "s"], "Change selected text",
|
||||
function (count) {
|
||||
dactyl.assert(modes.extended & modes.TEXTAREA);
|
||||
dactyl.assert(editor.isTextEdit);
|
||||
editor.executeCommand("cmd_cut");
|
||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
||||
modes.push(modes.INSERT);
|
||||
});
|
||||
|
||||
mappings.add([modes.VISUAL],
|
||||
["d"], "Delete selected text",
|
||||
function (count) {
|
||||
if (modes.extended & modes.TEXTAREA) {
|
||||
if (editor.isTextEdit) {
|
||||
editor.executeCommand("cmd_cut");
|
||||
modes.set(modes.TEXTAREA);
|
||||
modes.pop();
|
||||
}
|
||||
else
|
||||
dactyl.beep();
|
||||
@@ -710,27 +718,27 @@ const Editor = Module("editor", {
|
||||
mappings.add([modes.VISUAL],
|
||||
["y"], "Yank selected text",
|
||||
function (count) {
|
||||
if (modes.extended & modes.TEXTAREA) {
|
||||
if (editor.isTextEdit) {
|
||||
editor.executeCommand("cmd_copy");
|
||||
modes.set(modes.TEXTAREA);
|
||||
modes.pop();
|
||||
}
|
||||
else
|
||||
dactyl.clipboardWrite(buffer.getCurrentWord(), true);
|
||||
});
|
||||
|
||||
mappings.add([modes.VISUAL, modes.TEXTAREA],
|
||||
mappings.add([modes.VISUAL, modes.TEXT_EDIT],
|
||||
["p"], "Paste clipboard contents",
|
||||
function (count) {
|
||||
dactyl.assert(!(modes.extended & modes.CARET));
|
||||
dactyl.assert(!editor.isCaret);
|
||||
if (!count)
|
||||
count = 1;
|
||||
while (count--)
|
||||
editor.executeCommand("cmd_paste");
|
||||
dactyl.mode = modes.TEXTAREA;
|
||||
modes.pop(modes.TEXT_EDIT);
|
||||
});
|
||||
|
||||
// finding characters
|
||||
mappings.add([modes.TEXTAREA, modes.VISUAL],
|
||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
||||
["f"], "Move to a character on the current line after the cursor",
|
||||
function (count, arg) {
|
||||
let pos = editor.findCharForward(arg, count);
|
||||
@@ -739,7 +747,7 @@ const Editor = Module("editor", {
|
||||
},
|
||||
{ arg: true, count: true });
|
||||
|
||||
mappings.add([modes.TEXTAREA, modes.VISUAL],
|
||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
||||
["F"], "Move to a charater on the current line before the cursor",
|
||||
function (count, arg) {
|
||||
let pos = editor.findCharBackward(arg, count);
|
||||
@@ -748,7 +756,7 @@ const Editor = Module("editor", {
|
||||
},
|
||||
{ arg: true, count: true });
|
||||
|
||||
mappings.add([modes.TEXTAREA, modes.VISUAL],
|
||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
||||
["t"], "Move before a character on the current line",
|
||||
function (count, arg) {
|
||||
let pos = editor.findCharForward(arg, count);
|
||||
@@ -757,7 +765,7 @@ const Editor = Module("editor", {
|
||||
},
|
||||
{ arg: true, count: true });
|
||||
|
||||
mappings.add([modes.TEXTAREA, modes.VISUAL],
|
||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
||||
["T"], "Move before a character on the current line, backwards",
|
||||
function (count, arg) {
|
||||
let pos = editor.findCharBackward(arg, count);
|
||||
@@ -766,8 +774,8 @@ const Editor = Module("editor", {
|
||||
},
|
||||
{ arg: true, count: true });
|
||||
|
||||
// textarea and visual mode
|
||||
mappings.add([modes.TEXTAREA, modes.VISUAL],
|
||||
// text edit and visual mode
|
||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
||||
["~"], "Switch case of the character under the cursor and move the cursor to the right",
|
||||
function (count) {
|
||||
if (modes.main == modes.VISUAL)
|
||||
@@ -786,7 +794,7 @@ const Editor = Module("editor", {
|
||||
text.substring(pos + 1);
|
||||
editor.moveToPosition(pos + 1, true, false);
|
||||
}
|
||||
modes.set(modes.TEXTAREA);
|
||||
modes.pop(modes.TEXT_EDIT);
|
||||
},
|
||||
{ count: true });
|
||||
},
|
||||
|
||||
@@ -47,17 +47,16 @@ const Events = Module("events", {
|
||||
this._code_key = {};
|
||||
this._key_code = {};
|
||||
|
||||
for (let [k, v] in Iterator(KeyEvent))
|
||||
if (/^DOM_VK_(?![A-Z0-9]$)/.test(k)) {
|
||||
k = k.substr(7).toLowerCase();
|
||||
let names = [k.replace(/(^|_)(.)/g, function (m, n1, n2) n2.toUpperCase())
|
||||
.replace(/^NUMPAD/, "k")];
|
||||
if (k in this._keyTable)
|
||||
names = this._keyTable[k];
|
||||
this._code_key[v] = names[0];
|
||||
for (let [, name] in Iterator(names))
|
||||
this._key_code[name.toLowerCase()] = v;
|
||||
}
|
||||
for (let [k, v] in Iterator(KeyEvent)) {
|
||||
k = k.substr(7).toLowerCase();
|
||||
let names = [k.replace(/(^|_)(.)/g, function (m, n1, n2) n2.toUpperCase())
|
||||
.replace(/^NUMPAD/, "k")];
|
||||
if (k in this._keyTable)
|
||||
names = this._keyTable[k];
|
||||
this._code_key[v] = names[0];
|
||||
for (let [, name] in Iterator(names))
|
||||
this._key_code[name.toLowerCase()] = v;
|
||||
}
|
||||
|
||||
// HACK: as Gecko does not include an event for <, we must add this in manually.
|
||||
if (!("<" in this._key_code)) {
|
||||
@@ -76,11 +75,11 @@ const Events = Module("events", {
|
||||
this._activeMenubar = false;
|
||||
this.addSessionListener(window, "DOMMenuBarActive", this.closure.onDOMMenuBarActive, true);
|
||||
this.addSessionListener(window, "DOMMenuBarInactive", this.closure.onDOMMenuBarInactive, true);
|
||||
this.addSessionListener(window, "focus", this.wrapListener(this.closure.onFocus), true);
|
||||
this.addSessionListener(window, "keydown", this.wrapListener(this.closure.onKeyUpOrDown), true);
|
||||
this.addSessionListener(window, "keypress", this.wrapListener(this.closure.onKeyPress), true);
|
||||
this.addSessionListener(window, "keyup", this.wrapListener(this.closure.onKeyUpOrDown), true);
|
||||
this.addSessionListener(window, "mousedown", this.wrapListener(this.closure.onMouseDown), true);
|
||||
this.addSessionListener(window, "focus", this.wrapListener(this.onFocus), true);
|
||||
this.addSessionListener(window, "keydown", this.wrapListener(this.onKeyUpOrDown), true);
|
||||
this.addSessionListener(window, "keypress", this.wrapListener(this.onKeyPress), true);
|
||||
this.addSessionListener(window, "keyup", this.wrapListener(this.onKeyUpOrDown), true);
|
||||
this.addSessionListener(window, "mousedown", this.wrapListener(this.onMouseDown), true);
|
||||
this.addSessionListener(window, "popuphidden", this.closure.onPopupHidden, true);
|
||||
this.addSessionListener(window, "popupshown", this.closure.onPopupShown, true);
|
||||
this.addSessionListener(window, "resize", this.closure.onResize, true);
|
||||
@@ -90,7 +89,8 @@ const Events = Module("events", {
|
||||
destroy: function () {
|
||||
util.dump("Removing all event listeners");
|
||||
for (let args in values(this.sessionListeners))
|
||||
args[0].removeEventListener.apply(args[0], args.slice(1));
|
||||
if (args[0].get())
|
||||
args[0].get().removeEventListener.apply(args[0].get(), args.slice(1));
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -105,7 +105,8 @@ const Events = Module("events", {
|
||||
*/
|
||||
addSessionListener: function (target, event, callback, capture) {
|
||||
let args = Array.slice(arguments, 0);
|
||||
target.addEventListener.apply(args[0], args.slice(1));
|
||||
args[0].addEventListener.apply(args[0], args.slice(1));
|
||||
args[0] = Cu.getWeakReference(args[0]);
|
||||
this.sessionListeners.push(args);
|
||||
},
|
||||
|
||||
@@ -113,6 +114,7 @@ const Events = Module("events", {
|
||||
* Wraps an event listener to ensure that errors are reported.
|
||||
*/
|
||||
wrapListener: function wrapListener(method, self) {
|
||||
self = self || this;
|
||||
return function (event) {
|
||||
try {
|
||||
method.apply(self, arguments);
|
||||
@@ -371,7 +373,7 @@ const Events = Module("events", {
|
||||
* @param {string} keys The string to parse.
|
||||
* @returns {Array[Object]}
|
||||
*/
|
||||
fromString: function (input) {
|
||||
fromString: function (input, unknownOk) {
|
||||
let out = [];
|
||||
|
||||
let re = RegExp("<.*?>?>|[^<]|<(?!.*>)", "g");
|
||||
@@ -385,9 +387,10 @@ const Events = Module("events", {
|
||||
let [match, modifier, keyname] = evt_str.match(/^<((?:[CSMA]-)*)(.+?)>$/i) || [false, '', ''];
|
||||
modifier = modifier.toUpperCase();
|
||||
keyname = keyname.toLowerCase();
|
||||
evt_obj.dactylKeyname = keyname;
|
||||
|
||||
if (keyname && !(keyname.length == 1 && modifier.length == 0 || // disallow <> and <a>
|
||||
!(keyname.length == 1 || this._key_code[keyname] || keyname == "nop" || /mouse$/.test(keyname)))) { // disallow <misteak>
|
||||
!(unknownOk || keyname.length == 1 || this._key_code[keyname] || keyname == "nop" || /mouse$/.test(keyname)))) { // disallow <misteak>
|
||||
evt_obj.ctrlKey = /C-/.test(modifier);
|
||||
evt_obj.altKey = /A-/.test(modifier);
|
||||
evt_obj.shiftKey = /S-/.test(modifier);
|
||||
@@ -501,7 +504,7 @@ const Events = Module("events", {
|
||||
else if (charCode > 0) {
|
||||
key = String.fromCharCode(charCode);
|
||||
|
||||
if (key in this._key_code) {
|
||||
if (!/^[a-z0-9]$/i.test(key) && key in this._key_code) {
|
||||
// a named charcode key (<Space> and <lt>) space can be shifted, <lt> must be forced
|
||||
if ((key.match(/^\s$/) && event.shiftKey) || event.dactylShift)
|
||||
modifier += "S-";
|
||||
@@ -625,69 +628,17 @@ const Events = Module("events", {
|
||||
* The global escape key handler. This is called in ALL modes.
|
||||
*/
|
||||
onEscape: function () {
|
||||
if (modes.passNextKey)
|
||||
return;
|
||||
|
||||
if (modes.passAllKeys) {
|
||||
modes.passAllKeys = false;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dactyl.mode) {
|
||||
case modes.NORMAL:
|
||||
// clear any selection made
|
||||
let selection = window.content.getSelection();
|
||||
try { // a simple if (selection) does not seem to work
|
||||
selection.collapseToStart();
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
modes.reset();
|
||||
break;
|
||||
|
||||
case modes.VISUAL:
|
||||
if (modes.extended & modes.TEXTAREA)
|
||||
dactyl.mode = modes.TEXTAREA;
|
||||
else if (modes.extended & modes.CARET)
|
||||
dactyl.mode = modes.CARET;
|
||||
break;
|
||||
|
||||
case modes.CARET:
|
||||
// setting this option will trigger an observer which will
|
||||
// take care of all other details like setting the NORMAL
|
||||
// mode
|
||||
options.setPref("accessibility.browsewithcaret", false);
|
||||
break;
|
||||
|
||||
case modes.TEXTAREA:
|
||||
// TODO: different behaviour for text areas and other input
|
||||
// fields seems unnecessarily complicated. If the user
|
||||
// likes Vi-mode then they probably like it for all input
|
||||
// fields, if not they can enter it explicitly for only
|
||||
// text areas. The mode name TEXTAREA is confusing and
|
||||
// would be better replaced with something indicating that
|
||||
// it's a Vi editing mode. Extended modes really need to be
|
||||
// displayed too. --djk
|
||||
function isInputField() {
|
||||
let elem = dactyl.focus;
|
||||
return elem instanceof HTMLInputElement && set.has(util.editableInputs, elem.type)
|
||||
|| elem instanceof HTMLIsIndexElement;
|
||||
}
|
||||
|
||||
if (options["insertmode"] || isInputField())
|
||||
dactyl.mode = modes.INSERT;
|
||||
else
|
||||
modes.reset();
|
||||
break;
|
||||
|
||||
case modes.COMMAND_LINE:
|
||||
case modes.INSERT:
|
||||
if ((modes.extended & modes.TEXTAREA))
|
||||
dactyl.mode = modes.TEXTAREA;
|
||||
else
|
||||
modes.reset();
|
||||
case modes.PASS_THROUGH:
|
||||
case modes.QUOTE:
|
||||
case modes.TEXT_EDIT:
|
||||
case modes.VISUAL:
|
||||
modes.pop();
|
||||
break;
|
||||
|
||||
default: // HINTS, CUSTOM or COMMAND_LINE
|
||||
default:
|
||||
modes.reset();
|
||||
break;
|
||||
}
|
||||
@@ -752,12 +703,15 @@ const Events = Module("events", {
|
||||
}
|
||||
|
||||
if (elem instanceof HTMLTextAreaElement || (elem && util.computedStyle(elem).MozUserModify == "read-write")) {
|
||||
if (modes.main === modes.VISUAL && elem.selectionEnd == elem.selectionStart)
|
||||
modes.pop();
|
||||
if (options["insertmode"])
|
||||
modes.set(modes.INSERT);
|
||||
else if (elem.selectionEnd - elem.selectionStart > 0)
|
||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
||||
else
|
||||
modes.main = modes.TEXTAREA;
|
||||
else {
|
||||
modes.set(modes.TEXT_EDIT);
|
||||
if (elem.selectionEnd - elem.selectionStart > 0)
|
||||
modes.push(modes.VISUAL);
|
||||
}
|
||||
if (hasHTMLDocument(win))
|
||||
buffer.lastInputField = elem;
|
||||
return;
|
||||
@@ -772,7 +726,7 @@ const Events = Module("events", {
|
||||
if (elem == null && urlbar && urlbar.inputField == this._lastFocus)
|
||||
util.threadYield(true);
|
||||
|
||||
if (dactyl.mode & (modes.EMBED | modes.INSERT | modes.TEXTAREA | modes.VISUAL))
|
||||
if (modes.getMode(modes.main).ownsFocus)
|
||||
modes.reset();
|
||||
}
|
||||
finally {
|
||||
@@ -784,7 +738,7 @@ const Events = Module("events", {
|
||||
// the commandline has focus
|
||||
// TODO: ...help me...please...
|
||||
onKeyPress: function (event) {
|
||||
function isEscapeKey(key) key == "<Esc>" || key == "<C-[>";
|
||||
function isEscape(key) key == "<Esc>" || key == "<C-[>";
|
||||
|
||||
function killEvent() {
|
||||
event.preventDefault();
|
||||
@@ -802,7 +756,7 @@ const Events = Module("events", {
|
||||
dactyl.echomsg("Recorded macro '" + this._currentMacro + "'");
|
||||
return killEvent();
|
||||
}
|
||||
else if (!mappings.hasMap(dactyl.mode, this._input.buffer + key))
|
||||
else if (!mappings.hasMap(mode, this._input.buffer + key))
|
||||
this._macros.set(this._currentMacro, {
|
||||
keys: this._macros.get(this._currentMacro, {}).keys + key,
|
||||
timeRecorded: Date.now()
|
||||
@@ -832,6 +786,7 @@ const Events = Module("events", {
|
||||
|
||||
try {
|
||||
let stop = false;
|
||||
let mode = modes.getStack(0);
|
||||
|
||||
let win = document.commandDispatcher.focusedWindow;
|
||||
if (win && win.document && "designMode" in win.document && win.document.designMode == "on" && !config.isComposeWindow)
|
||||
@@ -839,20 +794,19 @@ const Events = Module("events", {
|
||||
// menus have their own command handlers
|
||||
if (modes.extended & modes.MENU)
|
||||
stop = true;
|
||||
else if (modes.main == modes.PASS_THROUGH)
|
||||
// let flow continue to handle these keys to cancel escape-all-keys mode
|
||||
stop = !isEscape(key) && key != "<C-v>"
|
||||
// handle Escape-one-key mode (Ctrl-v)
|
||||
else if (modes.passNextKey && !modes.passAllKeys) {
|
||||
modes.passNextKey = false;
|
||||
stop = true;
|
||||
else if (modes.main == modes.QUOTE) {
|
||||
stop = modes.getStack(1).main !== modes.PASS_THROUGH || isEscape(key);
|
||||
// We need to preserve QUOTE mode until the escape
|
||||
// handler to escape the <Esc> key
|
||||
if (!stop || !isEscape(key))
|
||||
modes.pop();
|
||||
mode = modes.getStack(1);
|
||||
}
|
||||
// handle Escape-all-keys mode (Ctrl-q)
|
||||
else if (modes.passAllKeys) {
|
||||
if (modes.passNextKey)
|
||||
modes.passNextKey = false; // and then let flow continue
|
||||
else if (isEscapeKey(key) || key == "<C-v>")
|
||||
; // let flow continue to handle these keys to cancel escape-all-keys mode
|
||||
else
|
||||
stop = true;
|
||||
}
|
||||
|
||||
if (stop) {
|
||||
this._input.buffer = "";
|
||||
@@ -861,64 +815,32 @@ const Events = Module("events", {
|
||||
|
||||
stop = true; // set to false if we should NOT consume this event but let the host app handle it
|
||||
|
||||
// just forward event without checking any mappings when the MOW is open
|
||||
if (dactyl.mode == modes.COMMAND_LINE && (modes.extended & modes.OUTPUT_MULTILINE)) {
|
||||
commandline.onMultilineOutputEvent(event);
|
||||
return killEvent();
|
||||
}
|
||||
|
||||
// XXX: ugly hack for now pass certain keys to the host app as
|
||||
// they are without beeping also fixes key navigation in combo
|
||||
// boxes, submitting forms, etc.
|
||||
// FIXME: breaks iabbr for now --mst
|
||||
if (key in config.ignoreKeys && (config.ignoreKeys[key] & dactyl.mode)) {
|
||||
if (key in config.ignoreKeys && (config.ignoreKeys[key] & mode.main)) {
|
||||
this._input.buffer = "";
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: handle middle click in content area
|
||||
if (mode.params.onEvent) {
|
||||
this._input.buffer = "";
|
||||
// Bloody hell.
|
||||
if (key === "<C-h>")
|
||||
key = event.dactylString = "<BS>";
|
||||
|
||||
if (!isEscapeKey(key)) {
|
||||
// custom mode...
|
||||
if (dactyl.mode == modes.CUSTOM) {
|
||||
plugins.onEvent(event);
|
||||
return killEvent();
|
||||
}
|
||||
|
||||
// All of these special cases for hint mode are driving
|
||||
// me insane! -Kris
|
||||
if (modes.extended & modes.HINTS) {
|
||||
// under HINT mode, certain keys are redirected to hints.onEvent
|
||||
if (key == "<Return>" || key == "<Tab>" || key == "<S-Tab>"
|
||||
|| key == options["mapleader"]
|
||||
|| (key == "<BS>" && hints.prevInput == "number")
|
||||
|| (hints.isHintKey(key) && !hints.escNumbers)) {
|
||||
hints.onEvent(event);
|
||||
this._input.buffer = "";
|
||||
return killEvent();
|
||||
}
|
||||
|
||||
// others are left to generate the 'input' event or handled by the host app
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME (maybe): (is an ESC or C-] here): on HINTS mode, it enters
|
||||
// into 'if (map && !skipMap) below. With that (or however) it
|
||||
// triggers the onEscape part, where it resets mode. Here I just
|
||||
// return true, with the effect that it also gets to there (for
|
||||
// whatever reason). if that happens to be correct, well..
|
||||
// XXX: why not just do that as well for HINTS mode actually?
|
||||
|
||||
if (dactyl.mode == modes.CUSTOM)
|
||||
if (mode.params.onEvent(event) === false)
|
||||
killEvent();
|
||||
return null;
|
||||
}
|
||||
|
||||
let inputStr = this._input.buffer + key;
|
||||
let countStr = inputStr.match(/^[1-9][0-9]*|/)[0];
|
||||
let candidateCommand = inputStr.substr(countStr.length);
|
||||
let map = mappings[event.noremap ? "getDefault" : "get"](dactyl.mode, candidateCommand);
|
||||
let map = mappings[event.noremap ? "getDefault" : "get"](mode.main, candidateCommand);
|
||||
|
||||
let candidates = mappings.getCandidates(dactyl.mode, candidateCommand);
|
||||
let candidates = mappings.getCandidates(mode.main, candidateCommand);
|
||||
if (candidates.length == 0 && !map) {
|
||||
map = this._input.pendingMap;
|
||||
this._input.pendingMap = null;
|
||||
@@ -929,7 +851,7 @@ const Events = Module("events", {
|
||||
// counts must be at the start of a complete mapping (10j -> go 10 lines down)
|
||||
if (countStr && !candidateCommand) {
|
||||
// no count for insert mode mappings
|
||||
if (!modes.mainMode.count || modes.mainMode.input)
|
||||
if (!mode.mainMode.count || mode.mainMode.input)
|
||||
stop = false;
|
||||
else
|
||||
this._input.buffer = inputStr;
|
||||
@@ -938,7 +860,7 @@ const Events = Module("events", {
|
||||
this._input.buffer = "";
|
||||
let map = this._input.pendingArgMap;
|
||||
this._input.pendingArgMap = null;
|
||||
if (!isEscapeKey(key)) {
|
||||
if (!isEscape(key)) {
|
||||
if (modes.isReplaying && !this.waitForPageLoad())
|
||||
return null;
|
||||
map.execute(null, this._input.count, key);
|
||||
@@ -957,7 +879,7 @@ const Events = Module("events", {
|
||||
this._input.pendingArgMap = map;
|
||||
}
|
||||
else if (this._input.pendingMotionMap) {
|
||||
if (!isEscapeKey(key))
|
||||
if (!isEscape(key))
|
||||
this._input.pendingMotionMap.execute(candidateCommand, this._input.count, null);
|
||||
this._input.pendingMotionMap = null;
|
||||
}
|
||||
@@ -974,14 +896,14 @@ const Events = Module("events", {
|
||||
stop = false;
|
||||
}
|
||||
}
|
||||
else if (mappings.getCandidates(dactyl.mode, candidateCommand).length > 0 && !event.skipmap) {
|
||||
else if (mappings.getCandidates(mode.main, candidateCommand).length > 0 && !event.skipmap) {
|
||||
this._input.pendingMap = map;
|
||||
this._input.buffer += key;
|
||||
}
|
||||
else { // if the key is neither a mapping nor the start of one
|
||||
// the mode checking is necessary so that things like g<esc> do not beep
|
||||
if (this._input.buffer != "" && !event.skipmap &&
|
||||
(dactyl.mode & (modes.INSERT | modes.COMMAND_LINE | modes.TEXTAREA)))
|
||||
(mode.main & (modes.INSERT | modes.COMMAND_LINE | modes.TEXT_EDIT)))
|
||||
events.feedkeys(this._input.buffer, { noremap: true, skipmap: true });
|
||||
|
||||
this._input.buffer = "";
|
||||
@@ -989,17 +911,17 @@ const Events = Module("events", {
|
||||
this._input.pendingMotionMap = null;
|
||||
this._input.pendingMap = null;
|
||||
|
||||
if (!isEscapeKey(key)) {
|
||||
if (!isEscape(key)) {
|
||||
// allow key to be passed to the host app if we can't handle it
|
||||
stop = (dactyl.mode == modes.TEXTAREA);
|
||||
stop = (mode.main === modes.TEXT_EDIT);
|
||||
|
||||
if (dactyl.mode == modes.COMMAND_LINE) {
|
||||
if (mode.main === modes.COMMAND_LINE) {
|
||||
if (!(modes.extended & modes.INPUT_MULTILINE))
|
||||
dactyl.trapErrors(function () {
|
||||
commandline.onEvent(event); // reroute event in command line mode
|
||||
});
|
||||
}
|
||||
else if (!modes.mainMode.input)
|
||||
else if (!mode.mainMode.input)
|
||||
dactyl.beep();
|
||||
}
|
||||
}
|
||||
@@ -1019,9 +941,8 @@ const Events = Module("events", {
|
||||
|
||||
// this is need for sites like msn.com which focus the input field on keydown
|
||||
onKeyUpOrDown: function (event) {
|
||||
if (modes.passNextKey ^ modes.passAllKeys || Events.isInputElemFocused())
|
||||
return;
|
||||
event.stopPropagation();
|
||||
if (!Events.isInputElemFocused() && !modes.passThrough)
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
onMouseDown: function (event) {
|
||||
@@ -1052,27 +973,19 @@ const Events = Module("events", {
|
||||
},
|
||||
|
||||
onSelectionChange: function (event) {
|
||||
let couldCopy = false;
|
||||
let controller = document.commandDispatcher.getControllerForCommand("cmd_copy");
|
||||
if (controller && controller.isCommandEnabled("cmd_copy"))
|
||||
couldCopy = true;
|
||||
let couldCopy = controller && controller.isCommandEnabled("cmd_copy");
|
||||
|
||||
if (dactyl.mode != modes.VISUAL) {
|
||||
if (couldCopy) {
|
||||
if ((dactyl.mode == modes.TEXTAREA ||
|
||||
(modes.extended & modes.TEXTAREA))
|
||||
&& !options["insertmode"])
|
||||
modes.set(modes.VISUAL, modes.TEXTAREA);
|
||||
else if (dactyl.mode == modes.CARET)
|
||||
modes.set(modes.VISUAL, modes.CARET);
|
||||
}
|
||||
if (dactyl.mode === modes.VISUAL) {
|
||||
if (!couldCopy)
|
||||
modes.pop(); // Really not ideal.
|
||||
}
|
||||
else if (couldCopy) {
|
||||
if (modes.main == modes.TEXT_EDIT && !options["insertmode"])
|
||||
modes.push(modes.VISUAL);
|
||||
else if (dactyl.mode == modes.CARET)
|
||||
modes.push(modes.VISUAL);
|
||||
}
|
||||
// XXX: disabled, as i think automatically starting visual caret mode does more harm than help
|
||||
// else
|
||||
// {
|
||||
// if (!couldCopy && modes.extended & modes.CARET)
|
||||
// dactyl.mode = modes.CARET;
|
||||
// }
|
||||
}
|
||||
}, {
|
||||
isContentNode: function (node) {
|
||||
@@ -1135,17 +1048,17 @@ const Events = Module("events", {
|
||||
["<Tab>"], "Advance keyboard focus",
|
||||
function () { document.commandDispatcher.advanceFocus(); });
|
||||
|
||||
mappings.add([modes.NORMAL, modes.PLAYER, modes.VISUAL, modes.CARET, modes.INSERT, modes.TEXTAREA],
|
||||
mappings.add([modes.NORMAL, modes.PLAYER, modes.VISUAL, modes.CARET, modes.INSERT, modes.TEXT_EDIT],
|
||||
["<S-Tab>"], "Rewind keyboard focus",
|
||||
function () { document.commandDispatcher.rewindFocus(); });
|
||||
|
||||
mappings.add(modes.all,
|
||||
["<C-z>"], "Temporarily ignore all " + config.appName + " key bindings",
|
||||
function () { modes.passAllKeys = true; });
|
||||
function () { modes.push(modes.PASS_THROUGH); });
|
||||
|
||||
mappings.add(modes.all,
|
||||
["<C-v>"], "Pass through next key",
|
||||
function () { modes.passNextKey = true; });
|
||||
function () { modes.push(modes.QUOTE); });
|
||||
|
||||
mappings.add(modes.all,
|
||||
["<Nop>"], "Do nothing",
|
||||
|
||||
@@ -114,8 +114,6 @@ const RangeFinder = Module("rangefinder", {
|
||||
if (options["hlsearch"])
|
||||
this.highlight();
|
||||
this.rangeFind.focus();
|
||||
|
||||
modes.reset();
|
||||
},
|
||||
|
||||
// Called when the search is canceled - for example if someone presses
|
||||
@@ -186,14 +184,14 @@ const RangeFinder = Module("rangefinder", {
|
||||
["N"], "Find previous",
|
||||
function () { rangefinder.findAgain(true); });
|
||||
|
||||
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["*"],
|
||||
mappings.add(myModes.concat([modes.CARET, modes.TEXT_EDIT]), ["*"],
|
||||
"Find word under cursor",
|
||||
function () {
|
||||
rangefinder.find(buffer.getCurrentWord(), false);
|
||||
rangefinder.findAgain();
|
||||
});
|
||||
|
||||
mappings.add(myModes.concat([modes.CARET, modes.TEXTAREA]), ["#"],
|
||||
mappings.add(myModes.concat([modes.CARET, modes.TEXT_EDIT]), ["#"],
|
||||
"Find word under cursor backwards",
|
||||
function () {
|
||||
rangefinder.find(buffer.getCurrentWord(), true);
|
||||
|
||||
@@ -97,7 +97,7 @@ const Hints = Module("hints", {
|
||||
if (!this._usedTabKey) {
|
||||
this._hintNumber = 0;
|
||||
}
|
||||
if (this.__continue && this._validHints.length <= 1) {
|
||||
if (this._continue && this._validHints.length <= 1) {
|
||||
this._hintString = "";
|
||||
commandline.widgets.command = this._hintString;
|
||||
this._showHints();
|
||||
@@ -764,6 +764,20 @@ const Hints = Module("hints", {
|
||||
*/
|
||||
isHintKey: function (key) this.hintKeys.indexOf(key) >= 0,
|
||||
|
||||
open: function (mode, opts) {
|
||||
this._extendedhintCount = opts.count;
|
||||
commandline.input(";", null, {
|
||||
promptHighlight: "Normal",
|
||||
completer: function (context) {
|
||||
context.compare = function () 0;
|
||||
context.completions = [[k, v.prompt] for ([k, v] in Iterator(hints._hintModes))];
|
||||
},
|
||||
onAccept: function (arg) { arg && util.timeout(function () hints.show(arg, opts), 0); },
|
||||
get onCancel() this.onAccept,
|
||||
onChange: function () { modes.pop(); }
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the display of hints.
|
||||
*
|
||||
@@ -777,8 +791,12 @@ const Hints = Module("hints", {
|
||||
|
||||
commandline.input(UTF8(this._hintMode.prompt) + ": ", null, {
|
||||
extended: modes.HINTS,
|
||||
leave: function () { hints.hide(); },
|
||||
onChange: this.closure._onInput
|
||||
leave: function (stack) {
|
||||
if (!stack.push)
|
||||
hints.hide();
|
||||
},
|
||||
onChange: this.closure._onInput,
|
||||
onEvent: this.closure.onEvent
|
||||
});
|
||||
modes.extended = modes.HINTS;
|
||||
|
||||
@@ -860,9 +878,12 @@ const Hints = Module("hints", {
|
||||
}
|
||||
this._showActiveHint(this._hintNumber, oldId);
|
||||
this._updateStatusline();
|
||||
return;
|
||||
return false;
|
||||
|
||||
case "<BS>":
|
||||
if (this.prevInput !== "number")
|
||||
return true;
|
||||
|
||||
if (this._hintNumber > 0 && !this._usedTabKey) {
|
||||
this._hintNumber = Math.floor(this._hintNumber / this.hintKeys.length);
|
||||
if (this._hintNumber == 0)
|
||||
@@ -882,10 +903,10 @@ const Hints = Module("hints", {
|
||||
this._hintNumber = 0;
|
||||
|
||||
this._updateStatusline();
|
||||
return;
|
||||
return false;
|
||||
|
||||
default:
|
||||
if (this.isHintKey(key)) {
|
||||
if (!this.escNumbers && this.isHintKey(key)) {
|
||||
this.prevInput = "number";
|
||||
|
||||
let oldHintNumber = this._hintNumber;
|
||||
@@ -910,8 +931,9 @@ const Hints = Module("hints", {
|
||||
dactyl.assert(this._hintNumber != 0);
|
||||
|
||||
this._checkUnique();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
this._updateStatusline();
|
||||
@@ -923,6 +945,7 @@ const Hints = Module("hints", {
|
||||
this._showHints();
|
||||
this._processHints(followFirst);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//}}}
|
||||
}, {
|
||||
@@ -1048,30 +1071,15 @@ const Hints = Module("hints", {
|
||||
"Start QuickHint mode, but open link in a new tab",
|
||||
function () { hints.show(options.get("activate").has("links") ? "t" : "b"); });
|
||||
|
||||
function inputOpts(opts) ({
|
||||
promptHighlight: "Normal",
|
||||
completer: function (context) {
|
||||
context.compare = function () 0;
|
||||
context.completions = [[k, v.prompt] for ([k, v] in Iterator(hints._hintModes))];
|
||||
},
|
||||
onAccept: function (arg) { arg && util.timeout(function () hints.show(arg, opts), 0); },
|
||||
onChange: function () { modes.pop(); },
|
||||
onCancel: function (arg) { arg && util.timeout(function () hints.show(arg, opts), 0); }
|
||||
});
|
||||
|
||||
mappings.add(myModes, [";"],
|
||||
"Start an extended hint mode",
|
||||
function (count) {
|
||||
this._extendedhintCount = count;
|
||||
commandline.input(";", null, inputOpts());
|
||||
}, { count: true });
|
||||
function (count) { hints.open(";", { count: count }); },
|
||||
{ count: true });
|
||||
|
||||
mappings.add(myModes, ["g;"],
|
||||
"Start an extended hint mode and stay there until <Esc> is pressed",
|
||||
function (count) {
|
||||
this._extendedhintCount = count;
|
||||
commandline.input("g;", null, inputOpts({ continue: true }));
|
||||
}, { count: true });
|
||||
function (count) { hints.open("g;", { continue: true, count: count }); },
|
||||
{ count: true });
|
||||
},
|
||||
options: function () {
|
||||
const DEFAULT_HINTTAGS =
|
||||
|
||||
@@ -30,14 +30,42 @@ const Modes = Module("modes", {
|
||||
this.boundProperties = {};
|
||||
|
||||
// main modes, only one should ever be active
|
||||
this.addMode("NORMAL", { char: "n", display: null });
|
||||
this.addMode("INSERT", { char: "i", input: true });
|
||||
this.addMode("VISUAL", { char: "v", display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : "") });
|
||||
this.addMode("NORMAL", { char: "n", display: function () null });
|
||||
this.addMode("INSERT", { char: "i", input: true, ownsFocus: true });
|
||||
this.addMode("VISUAL", { char: "v", ownsFocus: true, display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : "") }, {
|
||||
leave: function (stack, newMode) {
|
||||
if (newMode.main == modes.CARET) {
|
||||
let selection = window.content.getSelection();
|
||||
if (selection && !selection.isCollapsed)
|
||||
selection.collapseToStart();
|
||||
}
|
||||
else
|
||||
editor.unselectText();
|
||||
}
|
||||
});
|
||||
this.addMode("COMMAND_LINE", { char: "c", input: true });
|
||||
this.addMode("CARET"); // text cursor is visible
|
||||
this.addMode("TEXTAREA", { char: "i" });
|
||||
this.addMode("EMBED", { input: true });
|
||||
this.addMode("CUSTOM", { display: function () plugins.mode });
|
||||
this.addMode("CARET", {}, {
|
||||
get pref() options.getPref("accessibility.browsewithcaret"),
|
||||
set pref(val) options.setPref("accessibility.browsewithcaret", val),
|
||||
enter: function (stack) {
|
||||
if (stack.pop && !this.pref)
|
||||
modes.pop();
|
||||
else if (!stack.pop && !this.pref)
|
||||
this.pref = true;
|
||||
},
|
||||
leave: function (stack) {
|
||||
if (!stack.push && this.pref)
|
||||
this.pref = false;
|
||||
}
|
||||
});
|
||||
this.addMode("TEXT_EDIT", { char: "t", ownsFocus: true });
|
||||
this.addMode("EMBED", { input: true, ownsFocus: true });
|
||||
this.addMode("PASS_THROUGH");
|
||||
this.addMode("QUOTE", {
|
||||
display: function () modes.getStack(1).main == modes.PASS_THROUGH
|
||||
? (modes.getStack(2).mainMode.display() || modes.getStack(2).mainMode.name) + " (next)"
|
||||
: "PASS THROUGH (next)"
|
||||
});
|
||||
// this._extended modes, can include multiple modes, and even main modes
|
||||
this.addMode("EX", true);
|
||||
this.addMode("HINTS", true);
|
||||
@@ -45,30 +73,31 @@ const Modes = Module("modes", {
|
||||
this.addMode("OUTPUT_MULTILINE", true);
|
||||
this.addMode("SEARCH_FORWARD", true);
|
||||
this.addMode("SEARCH_BACKWARD", true);
|
||||
this.addMode("SEARCH_VIEW_FORWARD", true);
|
||||
this.addMode("SEARCH_VIEW_BACKWARD", true);
|
||||
this.addMode("MENU", true); // a popupmenu is active
|
||||
this.addMode("LINE", true); // linewise visual mode
|
||||
this.addMode("PROMPT", true);
|
||||
|
||||
this.push(this.NORMAL, 0, {
|
||||
restore: function (prev) {
|
||||
// disable caret mode when we want to switch to normal mode
|
||||
enter: function (stack, prev) {
|
||||
if (options.getPref("accessibility.browsewithcaret"))
|
||||
options.setPref("accessibility.browsewithcaret", false);
|
||||
|
||||
statusline.updateUrl();
|
||||
dactyl.focusContent(true);
|
||||
if (prev.mainMode.input || prev.mainMode.ownsFocus)
|
||||
dactyl.focusContent(true);
|
||||
if (prev.main === modes.NORMAL) {
|
||||
dactyl.focusContent(true);
|
||||
// clear any selection made
|
||||
let selection = window.content.getSelection();
|
||||
if (selection && !selection.isCollapsed)
|
||||
selection.collapseToStart();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_getModeMessage: function () {
|
||||
if (this._passNextKey && !this._passAllKeys)
|
||||
return "-- PASS THROUGH (next) --";
|
||||
else if (this._passAllKeys && !this._passNextKey)
|
||||
return "-- PASS THROUGH --";
|
||||
|
||||
// when recording a macro
|
||||
let macromode = "";
|
||||
if (modes.isRecording)
|
||||
@@ -81,7 +110,8 @@ const Modes = Module("modes", {
|
||||
ext += " (menu)";
|
||||
ext += " --" + macromode;
|
||||
|
||||
if (this._main in this._modeMap && typeof this._modeMap[this._main].display == "function")
|
||||
let val = this._modeMap[this._main].display();
|
||||
if (val)
|
||||
return "-- " + this._modeMap[this._main].display() + ext;
|
||||
return macromode;
|
||||
},
|
||||
@@ -98,27 +128,31 @@ const Modes = Module("modes", {
|
||||
|
||||
get topOfStack() this._modeStack[this._modeStack.length - 1],
|
||||
|
||||
addMode: function (name, extended, options) {
|
||||
addMode: function (name, extended, options, params) {
|
||||
let disp = name.replace("_", " ", "g");
|
||||
this[name] = 1 << this._lastMode++;
|
||||
|
||||
if (typeof extended == "object") {
|
||||
params = options;
|
||||
options = extended;
|
||||
extended = false;
|
||||
}
|
||||
|
||||
let mode = util.extend({
|
||||
extended: extended,
|
||||
count: true,
|
||||
disp: disp,
|
||||
extended: extended,
|
||||
input: false,
|
||||
mask: this[name],
|
||||
name: name,
|
||||
disp: disp
|
||||
params: params || {}
|
||||
}, options);
|
||||
if (mode.char) {
|
||||
this.modeChars[mode.char] = this.modeChars[mode.char] || [];
|
||||
this.modeChars[mode.char].push(mode);
|
||||
}
|
||||
|
||||
if (mode.display !== null)
|
||||
if (mode.display == null)
|
||||
mode.display = function () disp;
|
||||
this._modeMap[name] = mode;
|
||||
this._modeMap[this[name]] = mode;
|
||||
@@ -129,6 +163,8 @@ const Modes = Module("modes", {
|
||||
|
||||
getMode: function (name) this._modeMap[name],
|
||||
|
||||
getStack: function (idx) this._modeStack[this._modeStack.length - idx - 1] || this._modeStack[0],
|
||||
|
||||
getCharModes: function (chr) [m for (m in values(this._modeMap)) if (m.char == chr)],
|
||||
|
||||
matchModes: function (obj)
|
||||
@@ -139,7 +175,8 @@ const Modes = Module("modes", {
|
||||
let msg = null;
|
||||
if (options["showmode"])
|
||||
msg = this._getModeMessage();
|
||||
commandline.widgets.mode = msg || null;
|
||||
if (loaded.commandline)
|
||||
commandline.widgets.mode = msg || null;
|
||||
},
|
||||
|
||||
// add/remove always work on the this._extended mode only
|
||||
@@ -148,6 +185,9 @@ const Modes = Module("modes", {
|
||||
this.show();
|
||||
},
|
||||
|
||||
delayed: [],
|
||||
delay: function (callback, self) { this.delayed.push([callback, self]) },
|
||||
|
||||
save: function (id, obj, prop) {
|
||||
if (!(id in this.boundProperties))
|
||||
for (let elem in values(this._modeStack))
|
||||
@@ -158,27 +198,11 @@ const Modes = Module("modes", {
|
||||
// helper function to set both modes in one go
|
||||
// if silent == true, you also need to take care of the mode handling changes yourself
|
||||
set: function (mainMode, extendedMode, params, stack) {
|
||||
params = params || {};
|
||||
params = params || this.getMode(mainMode || this.main).params;
|
||||
|
||||
if (!stack && mainMode != null && this._modeStack.length > 1)
|
||||
this.reset();
|
||||
|
||||
let push = mainMode != null && !(stack && stack.pop) &&
|
||||
Modes.StackElem(mainMode, extendedMode || this.NONE, params, {});
|
||||
if (push && this.topOfStack) {
|
||||
if (this.topOfStack.params.save)
|
||||
this.topOfStack.params.save(push);
|
||||
|
||||
for (let [id, { obj, prop }] in Iterator(this.boundProperties)) {
|
||||
if (!obj.get())
|
||||
delete this.boundProperties(id);
|
||||
else
|
||||
this.topOfStack.saved[id] = { obj: obj.get(), prop: prop, value: obj.get()[prop] };
|
||||
}
|
||||
}
|
||||
|
||||
let silent = this._main === mainMode && this._extended === extendedMode;
|
||||
// if a this._main mode is set, the this._extended is always cleared
|
||||
let oldMain = this._main, oldExtended = this._extended;
|
||||
|
||||
if (typeof extendedMode === "number")
|
||||
@@ -189,35 +213,68 @@ const Modes = Module("modes", {
|
||||
this._extended = this.NONE;
|
||||
}
|
||||
|
||||
if (stack && stack.pop && stack.pop.params.leave)
|
||||
stack.pop.params.leave(stack, this.topOfStack);
|
||||
|
||||
let push = mainMode != null && !(stack && stack.pop) &&
|
||||
Modes.StackElem(this._main, this._extended, params, {});
|
||||
if (push && this.topOfStack) {
|
||||
if (this.topOfStack.params.leave)
|
||||
this.topOfStack.params.leave({ push: push }, push);
|
||||
for (let [id, { obj, prop }] in Iterator(this.boundProperties)) {
|
||||
if (!obj.get())
|
||||
delete this.boundProperties(id);
|
||||
else
|
||||
this.topOfStack.saved[id] = { obj: obj.get(), prop: prop, value: obj.get()[prop] };
|
||||
}
|
||||
}
|
||||
|
||||
this.delayed.forEach(function ([fn, self]) fn.call(self));
|
||||
this.delayed = [];
|
||||
|
||||
let prev = stack && stack.pop || this.topOfStack;
|
||||
if (push)
|
||||
this._modeStack.push(push);
|
||||
|
||||
dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
|
||||
if (stack && stack.pop) {
|
||||
for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved))
|
||||
obj[prop] = value;
|
||||
}
|
||||
|
||||
if (!silent)
|
||||
this.show();
|
||||
if (this.topOfStack.params.enter && prev)
|
||||
this.topOfStack.params.enter(push ? { push: push } : stack || {},
|
||||
prev);
|
||||
|
||||
dactyl.triggerObserver("modeChange", [oldMain, oldExtended], [this._main, this._extended], stack);
|
||||
this.show();
|
||||
},
|
||||
|
||||
push: function (mainMode, extendedMode, params) {
|
||||
this.set(mainMode, extendedMode, params, { push: this.topOfStack });
|
||||
},
|
||||
|
||||
pop: function () {
|
||||
let a = this._modeStack.pop();
|
||||
if (a.params.leave)
|
||||
a.params.leave(this.topOfStack);
|
||||
pop: function (mode) {
|
||||
while (this._modeStack.length > 1 && this.main != mode) {
|
||||
let a = this._modeStack.pop();
|
||||
this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params,
|
||||
{ pop: a });
|
||||
|
||||
this.set(this.topOfStack.main, this.topOfStack.extended, this.topOfStack.params, { pop: a });
|
||||
if (this.topOfStack.params.restore)
|
||||
this.topOfStack.params.restore(a);
|
||||
if (mode == null)
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
for (let [k, { obj, prop, value }] in Iterator(this.topOfStack.saved))
|
||||
obj[prop] = value;
|
||||
replace: function (mode, oldMode) {
|
||||
while (oldMode && this._modeStack.length > 1 && this.main != oldMode)
|
||||
this.pop();
|
||||
|
||||
this.set(mode, null, null, { push: this.topOfStack, pop: this._modeStack.pop() });
|
||||
this.push(mode);
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
if (this._modeStack.length == 1 && this.topOfStack.params.restore)
|
||||
this.topOfStack.params.restore(this.topOfStack);
|
||||
if (this._modeStack.length == 1 && this.topOfStack.params.enter)
|
||||
this.topOfStack.params.enter({}, this.topOfStack);
|
||||
while (this._modeStack.length > 1)
|
||||
this.pop();
|
||||
},
|
||||
@@ -229,12 +286,6 @@ const Modes = Module("modes", {
|
||||
}
|
||||
},
|
||||
|
||||
get passNextKey() this._passNextKey,
|
||||
set passNextKey(value) { this._passNextKey = value; this.show(); },
|
||||
|
||||
get passAllKeys() this._passAllKeys,
|
||||
set passAllKeys(value) { this._passAllKeys = value; this.show(); },
|
||||
|
||||
get isRecording() this._isRecording,
|
||||
set isRecording(value) { this._isRecording = value; this.show(); },
|
||||
|
||||
@@ -247,7 +298,17 @@ const Modes = Module("modes", {
|
||||
get extended() this._extended,
|
||||
set extended(value) { this.set(null, value); }
|
||||
}, {
|
||||
StackElem: Struct("main", "extended", "params", "saved"),
|
||||
StackElem: (function () {
|
||||
let struct = Struct("main", "extended", "params", "saved");
|
||||
struct.prototype.__defineGetter__("mainMode", function () modes.getMode(this.main));
|
||||
struct.prototype.toString = function () !loaded.modes ? this.main : "[mode " +
|
||||
modes.getMode(this.main).name +
|
||||
(!this.extended ? "" :
|
||||
"(" +
|
||||
[modes.getMode(1<<i).name for (i in util.range(0, 32)) if (this.extended & (1<<i))].join("|") +
|
||||
")") + "]";
|
||||
return struct;
|
||||
})(),
|
||||
cacheId: 0,
|
||||
boundProperty: function boundProperty(desc) {
|
||||
desc = desc || {};
|
||||
@@ -270,6 +331,15 @@ const Modes = Module("modes", {
|
||||
})
|
||||
}, desc));
|
||||
}
|
||||
}, {
|
||||
options: function () {
|
||||
options.observePref("accessibility.browsewithcaret", function (value) {
|
||||
if (!value && modes.main === modes.CARET)
|
||||
modes.pop();
|
||||
if (value && modes.main === modes.NORMAL)
|
||||
modes.push(modes.CARET);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// vim: set fdm=marker sw=4 ts=4 et:
|
||||
|
||||
@@ -650,13 +650,15 @@ const Options = Module("options", {
|
||||
|
||||
observe: function (subject, topic, data) {
|
||||
if (topic == "nsPref:changed") {
|
||||
// subject is the nsIPrefBranch we're observing (after appropriate QI)
|
||||
// data is the name of the pref that's been changed (relative to subject)
|
||||
switch (data) {
|
||||
case "accessibility.browsewithcaret":
|
||||
let value = options.getPref("accessibility.browsewithcaret", false);
|
||||
dactyl.mode = value ? modes.CARET : modes.NORMAL;
|
||||
break;
|
||||
let observers = this._observers[data];
|
||||
if (observers) {
|
||||
let value = options.getPref(data, false);
|
||||
this._observers[data] = observers.filter(function (callback) {
|
||||
if (!callback.get())
|
||||
return false;
|
||||
dactyl.trapErrors(callback.get(), null, value);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -805,6 +807,20 @@ const Options = Module("options", {
|
||||
template.options(config.host + " Options", prefs()));
|
||||
},
|
||||
|
||||
_observers: Class.memoize(function () ({})),
|
||||
/**
|
||||
* Adds a new preference observer for the given preference.
|
||||
*
|
||||
* @param {string} pref The preference to observe.
|
||||
* @param {function(object)} callback The callback, called with the
|
||||
* new value of the preference whenever it changes.
|
||||
*/
|
||||
observePref: function (pref, callback, weak) {
|
||||
if (!this._observers[pref])
|
||||
this._observers[pref] = [];
|
||||
this._observers[pref].push(weak ? Cu.getWeakReference(callback) : { get: function () callback });
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a :set command's argument string.
|
||||
*
|
||||
|
||||
@@ -90,18 +90,16 @@
|
||||
|
||||
<p>Enable <em>passthrough</em> mode on all Google sites:</p>
|
||||
|
||||
<code><ex>:autocmd LocationChange .* js modes.passAllKeys = /google\.com/.test(buffer.URL)</ex></code>
|
||||
<code><ex>:autocmd LocationChange</ex> <str delim="'">google\.com</str> <hl key="HelpArg">-js</hl> modes.push(modes.PASS_THROUGH)</code>
|
||||
|
||||
<p>Enable <em>passthrough</em> mode on <em>some</em> Google sites:</p>
|
||||
|
||||
<code><ex>:autocmd LocationChange .* js modes.passAllKeys = /(www|mail)\.google\.com/.test(buffer.URL)</ex></code>
|
||||
<code><ex>:autocmd LocationChange</ex> <str delim="'">(www|mail)\.google\.com</str> <hl key="HelpArg">-js</hl> modes.push(modes.PASS_THROUGH)</code>
|
||||
|
||||
<p>Set the filetype to mail when editing email at Gmail:</p>
|
||||
|
||||
<code><!-- Why is the XSLT processor mangling newlines? -->
|
||||
<ex>:autocmd LocationChange !'mail\.google\.com'</ex> <ex>:set editor=<str>gvim -f</str></ex>
|
||||
<ex>:autocmd LocationChange 'mail\.google\.com'</ex> <ex>:set editor=<str>gvim -f -c 'set ft=mail'</str></ex>
|
||||
</code>
|
||||
<code><ex>:autocmd LocationChange</ex> !<str delim="'">mail\.google\.com</str> <ex>:set editor=<str>gvim -f</str></ex>
|
||||
<ex>:autocmd LocationChange</ex> <str delim="'">mail\.google\.com</str> <ex>:set editor=<str>gvim -f -c 'set ft=mail'</str></ex></code>
|
||||
|
||||
</document>
|
||||
|
||||
|
||||
@@ -154,7 +154,8 @@
|
||||
|
||||
<item>
|
||||
<tags>:extu :extupdate</tags>
|
||||
<spec>:extu<oa>pdate</oa><oa>!</oa> <a>extension</a></spec>
|
||||
<spec>:extu<oa>pdate</oa> <a>extension</a></spec>
|
||||
<spec>:extu<oa>pdate</oa>!</spec>
|
||||
<description>
|
||||
<p>
|
||||
Update an extension. When <oa>!</oa> is given, update all
|
||||
|
||||
@@ -16,9 +16,9 @@ This file contains a list of all available commands, mappings and options.
|
||||
<h2 tag="insert-index">Insert mode</h2>
|
||||
|
||||
<dl>
|
||||
<dt><k mode="i">i</k></dt> <dd>Start Insert mode in text areas when <o>insertmode</o> is not set</dd>
|
||||
<dt><k mode="t">i</k></dt> <dd>Start Insert mode in text areas when <o>insertmode</o> is not set</dd>
|
||||
<dt><k name="C-i" mode="i"/></dt> <dd>Launch the external editor</dd>
|
||||
<dt><k name="C-t" mode="i"/></dt> <dd>Enter Textarea mode</dd>
|
||||
<dt><k name="C-t" mode="i"/></dt> <dd>Enter TextEdit mode</dd>
|
||||
<dt><k name="C-]" mode="i"/></dt> <dd>Expand an Insert-mode abbreviation</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
</p>
|
||||
|
||||
<item>
|
||||
<tags>i_i</tags>
|
||||
<spec>i_i</spec>
|
||||
<tags>t_i</tags>
|
||||
<spec>t_i</spec>
|
||||
<description short="true">
|
||||
<p>Starts Insert mode in text areas when <o>insertmode</o> is not set.</p>
|
||||
</description>
|
||||
@@ -42,7 +42,7 @@
|
||||
<spec><C-t></spec>
|
||||
<description short="true">
|
||||
<p>
|
||||
Enter Textarea mode. This is useful for quick editing of text fields
|
||||
Enter TextEdit mode. This is useful for quick editing of text fields
|
||||
with basic Vim-keys support. See also <o>insertmode</o>.
|
||||
</p>
|
||||
</description>
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<dt>n</dt> <dd>Normal mode: When browsing normally</dd>
|
||||
<dt>v</dt> <dd>Visual mode: When selecting text with the cursor keys</dd>
|
||||
<dt>i</dt> <dd>Insert mode: When interacting with text fields on a website</dd>
|
||||
<dt>t</dt> <dd>TextEdit mode: When editing text fields in Vim-like NORMAL mode</dd>
|
||||
<dt>c</dt> <dd>Command-line mode: When typing into the &dactyl.appName; command line</dd>
|
||||
</dl>
|
||||
|
||||
@@ -82,6 +83,8 @@
|
||||
<spec>:vm<oa>ap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:im :imap</tags>
|
||||
<spec>:im<oa>ap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:tm :tmap</tags>
|
||||
<spec>:tm<oa>ap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:cm :cmap</tags>
|
||||
<spec>:cm<oa>ap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<description>
|
||||
@@ -126,6 +129,8 @@
|
||||
<spec>:vn<oa>oremap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:ino :inoremap</tags>
|
||||
<spec>:ino<oa>remap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:tno :tnoremap</tags>
|
||||
<spec>:tno<oa>remap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:cno :cnoremap</tags>
|
||||
<spec>:cno<oa>remap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<description>
|
||||
@@ -150,6 +155,8 @@
|
||||
<spec>:vun<oa>map</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:iu :iunmap</tags>
|
||||
<spec>:iu<oa>nmap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:tu :tunmap</tags>
|
||||
<spec>:tu<oa>nmap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<tags>:cu :cunmap</tags>
|
||||
<spec>:cu<oa>nmap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||
<description>
|
||||
@@ -166,6 +173,8 @@
|
||||
<spec>:vmapc<oa>lear</oa></spec>
|
||||
<tags>:imapc :imapclear</tags>
|
||||
<spec>:imapc<oa>lear</oa></spec>
|
||||
<tags>:tmapc :tmapclear</tags>
|
||||
<spec>:tmapc<oa>lear</oa></spec>
|
||||
<tags>:cmapc :cmapclear</tags>
|
||||
<spec>:cmapc<oa>lear</oa></spec>
|
||||
<description>
|
||||
@@ -180,6 +189,7 @@
|
||||
<spec>:nm<oa>ap</oa></spec>
|
||||
<spec>:vm<oa>ap</oa></spec>
|
||||
<spec>:im<oa>ap</oa></spec>
|
||||
<spec>:tm<oa>ap</oa></spec>
|
||||
<spec>:cm<oa>ap</oa></spec>
|
||||
<description>
|
||||
<p>List all mappings for the applicable mode(s).</p>
|
||||
@@ -195,6 +205,8 @@
|
||||
<spec>:vm<oa>ap</oa> <a>lhs</a></spec>
|
||||
<tags>:imap_l</tags>
|
||||
<spec>:im<oa>ap</oa> <a>lhs</a></spec>
|
||||
<tags>:tmap_l</tags>
|
||||
<spec>:tm<oa>ap</oa> <a>lhs</a></spec>
|
||||
<tags>:cmap_l</tags>
|
||||
<spec>:cm<oa>ap</oa> <a>lhs</a></spec>
|
||||
<description>
|
||||
@@ -224,6 +236,7 @@
|
||||
:nmap :nnoremap :nunmap :nmapclear – Normal mode
|
||||
:vmap :vnoremap :vunmap :vmapclear – Visual mode
|
||||
:imap :inoremap :iunmap :imapclear – Insert mode
|
||||
:tmap :tnoremap :tunmap :tmapclear – Text Edit mode
|
||||
:cmap :cnoremap :cunmap :cmapclear – Command-line mode
|
||||
</code>
|
||||
|
||||
|
||||
@@ -842,7 +842,7 @@
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Textarea mode can be entered with <k name="C-t" mode="i"/> from Insert mode.
|
||||
TextEdit mode can be entered with <k name="C-t" mode="i"/> from Insert mode.
|
||||
</p>
|
||||
</description>
|
||||
</item>
|
||||
|
||||
@@ -57,6 +57,7 @@ const Util = Module("Util", {
|
||||
if (observers[target])
|
||||
observers[target].call(obj, subject, data);
|
||||
});
|
||||
obj.observe.unRegister = function () register("removeObserver");
|
||||
register("addObserver");
|
||||
},
|
||||
|
||||
@@ -73,7 +74,7 @@ const Util = Module("Util", {
|
||||
if (services.get("threadManager").isMainThread)
|
||||
callback.call(self);
|
||||
else
|
||||
mainThread.dispatch(Runnable(self, callback), mainThread.DISPATCH_NORMAL);
|
||||
mainThread.dispatch(Runnable(self, callback, Array.slice(arguments, 2)), mainThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -240,10 +241,10 @@ const Util = Module("Util", {
|
||||
* @param {number} frames The number of frames to print.
|
||||
*/
|
||||
dumpStack: function dumpStack(msg, frames) {
|
||||
let stack = Error().stack.replace(/(?:.*\n){1}/, "");
|
||||
let stack = Error().stack.replace(/(?:.*\n){2}/, "");
|
||||
if (frames != null)
|
||||
[stack] = stack.match(RegExp("(?:.*\n){0," + frames + "}"));
|
||||
util.dump((msg || "Stack") + "\n" + stack + "\n");
|
||||
util.dump((arguments.length == 0 ? "Stack" : msg) + "\n" + stack + "\n");
|
||||
},
|
||||
|
||||
editableInputs: set(["date", "datetime", "datetime-local", "email", "file",
|
||||
|
||||
@@ -63,7 +63,7 @@ const Config = Module("config", ConfigBase, {
|
||||
// we switch to -- MESSAGE -- mode for Teledactyl when the main HTML widget gets focus
|
||||
if (win && win.document instanceof HTMLDocument || dactyl.focus instanceof HTMLAnchorElement) {
|
||||
if (config.isComposeWindow)
|
||||
modes.set(modes.INSERT, modes.TEXTAREA);
|
||||
modes.set(modes.INSERT, modes.TEXT_EDIT);
|
||||
else if (dactyl.mode != modes.MESSAGE)
|
||||
dactyl.mode = modes.MESSAGE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user