mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-22 10:37:58 +01:00
Add operator mode per Vim. Wrap most editor commands in transactions. And stuff. Closes issue #439.
This commit is contained in:
@@ -1688,12 +1688,12 @@ var Buffer = Module("buffer", {
|
|||||||
function () { ex.stop(); });
|
function () { ex.stop(); });
|
||||||
|
|
||||||
// scrolling
|
// scrolling
|
||||||
mappings.add([modes.COMMAND], ["j", "<Down>", "<C-e>", "<scroll-down-line>"],
|
mappings.add([modes.NORMAL], ["j", "<Down>", "<C-e>", "<scroll-down-line>"],
|
||||||
"Scroll document down",
|
"Scroll document down",
|
||||||
function (args) { buffer.scrollVertical("lines", Math.max(args.count, 1)); },
|
function (args) { buffer.scrollVertical("lines", Math.max(args.count, 1)); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["k", "<Up>", "<C-y>", "<scroll-up-line>"],
|
mappings.add([modes.NORMAL], ["k", "<Up>", "<C-y>", "<scroll-up-line>"],
|
||||||
"Scroll document up",
|
"Scroll document up",
|
||||||
function (args) { buffer.scrollVertical("lines", -Math.max(args.count, 1)); },
|
function (args) { buffer.scrollVertical("lines", -Math.max(args.count, 1)); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
@@ -1703,30 +1703,30 @@ var Buffer = Module("buffer", {
|
|||||||
function (args) { buffer.scrollHorizontal("columns", -Math.max(args.count, 1)); },
|
function (args) { buffer.scrollHorizontal("columns", -Math.max(args.count, 1)); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], dactyl.has("mail") ? ["l", "<scroll-right-column>"] : ["l", "<Right>", "<scroll-right-column>"],
|
mappings.add([modes.NORMAL], dactyl.has("mail") ? ["l", "<scroll-right-column>"] : ["l", "<Right>", "<scroll-right-column>"],
|
||||||
"Scroll document to the right",
|
"Scroll document to the right",
|
||||||
function (args) { buffer.scrollHorizontal("columns", Math.max(args.count, 1)); },
|
function (args) { buffer.scrollHorizontal("columns", Math.max(args.count, 1)); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["0", "^", "<scroll-begin>"],
|
mappings.add([modes.NORMAL], ["0", "^", "<scroll-begin>"],
|
||||||
"Scroll to the absolute left of the document",
|
"Scroll to the absolute left of the document",
|
||||||
function () { buffer.scrollToPercent(0, null); });
|
function () { buffer.scrollToPercent(0, null); });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["$", "<scroll-end>"],
|
mappings.add([modes.NORMAL], ["$", "<scroll-end>"],
|
||||||
"Scroll to the absolute right of the document",
|
"Scroll to the absolute right of the document",
|
||||||
function () { buffer.scrollToPercent(100, null); });
|
function () { buffer.scrollToPercent(100, null); });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["gg", "<Home>", "<scroll-top>"],
|
mappings.add([modes.NORMAL], ["gg", "<Home>", "<scroll-top>"],
|
||||||
"Go to the top of the document",
|
"Go to the top of the document",
|
||||||
function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 0); },
|
function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 0); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["G", "<End>", "<scroll-bottom>"],
|
mappings.add([modes.NORMAL], ["G", "<End>", "<scroll-bottom>"],
|
||||||
"Go to the end of the document",
|
"Go to the end of the document",
|
||||||
function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 100); },
|
function (args) { buffer.scrollToPercent(null, args.count != null ? args.count : 100); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["%", "<scroll-percent>"],
|
mappings.add([modes.NORMAL], ["%", "<scroll-percent>"],
|
||||||
"Scroll to {count} percent of the document",
|
"Scroll to {count} percent of the document",
|
||||||
function (args) {
|
function (args) {
|
||||||
dactyl.assert(args.count > 0 && args.count <= 100);
|
dactyl.assert(args.count > 0 && args.count <= 100);
|
||||||
@@ -1734,22 +1734,22 @@ var Buffer = Module("buffer", {
|
|||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["<C-d>", "<scroll-down>"],
|
mappings.add([modes.NORMAL], ["<C-d>", "<scroll-down>"],
|
||||||
"Scroll window downwards in the buffer",
|
"Scroll window downwards in the buffer",
|
||||||
function (args) { buffer._scrollByScrollSize(args.count, true); },
|
function (args) { buffer._scrollByScrollSize(args.count, true); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["<C-u>", "<scroll-up>"],
|
mappings.add([modes.NORMAL], ["<C-u>", "<scroll-up>"],
|
||||||
"Scroll window upwards in the buffer",
|
"Scroll window upwards in the buffer",
|
||||||
function (args) { buffer._scrollByScrollSize(args.count, false); },
|
function (args) { buffer._scrollByScrollSize(args.count, false); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["<C-b>", "<PageUp>", "<S-Space>", "<scroll-up-page>"],
|
mappings.add([modes.NORMAL], ["<C-b>", "<PageUp>", "<S-Space>", "<scroll-up-page>"],
|
||||||
"Scroll up a full page",
|
"Scroll up a full page",
|
||||||
function (args) { buffer.scrollVertical("pages", -Math.max(args.count, 1)); },
|
function (args) { buffer.scrollVertical("pages", -Math.max(args.count, 1)); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["<Space>"],
|
mappings.add([modes.NORMAL], ["<Space>"],
|
||||||
"Scroll down a full page",
|
"Scroll down a full page",
|
||||||
function (args) {
|
function (args) {
|
||||||
if (isinstance(content.document.activeElement, [HTMLInputElement, HTMLButtonElement]))
|
if (isinstance(content.document.activeElement, [HTMLInputElement, HTMLButtonElement]))
|
||||||
@@ -1758,7 +1758,7 @@ var Buffer = Module("buffer", {
|
|||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.COMMAND], ["<C-f>", "<PageDown>", "<scroll-down-page>"],
|
mappings.add([modes.NORMAL], ["<C-f>", "<PageDown>", "<scroll-down-page>"],
|
||||||
"Scroll down a full page",
|
"Scroll down a full page",
|
||||||
function (args) { buffer.scrollVertical("pages", Math.max(args.count, 1)); },
|
function (args) { buffer.scrollVertical("pages", Math.max(args.count, 1)); },
|
||||||
{ count: true });
|
{ count: true });
|
||||||
@@ -1969,7 +1969,7 @@ var Buffer = Module("buffer", {
|
|||||||
try {
|
try {
|
||||||
config.browser.docShell.QueryInterface(Ci.nsIDocCharset).charset = val;
|
config.browser.docShell.QueryInterface(Ci.nsIDocCharset).charset = val;
|
||||||
PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, val);
|
PlacesUtils.history.setCharsetForURI(getWebNavigation().currentURI, val);
|
||||||
getWebNavigation().reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
window.getWebNavigation().reload(Ci.nsIWebNavigation.LOAD_FLAGS_CHARSET_CHANGE);
|
||||||
}
|
}
|
||||||
catch (e) { dactyl.reportError(e); }
|
catch (e) { dactyl.reportError(e); }
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -92,68 +92,6 @@ var Editor = Module("editor", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// cmd = y, d, c
|
|
||||||
// motion = b, 0, gg, G, etc.
|
|
||||||
selectMotion: function selectMotion(cmd, motion, count) {
|
|
||||||
// XXX: better as a precondition
|
|
||||||
if (count == null)
|
|
||||||
count = 1;
|
|
||||||
|
|
||||||
if (cmd == motion) {
|
|
||||||
motion = "j";
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (modes.main != modes.VISUAL)
|
|
||||||
modes.push(modes.VISUAL);
|
|
||||||
|
|
||||||
switch (motion) {
|
|
||||||
case "j":
|
|
||||||
this.executeCommand("cmd_beginLine", 1);
|
|
||||||
this.executeCommand("cmd_selectLineNext", count + 1);
|
|
||||||
break;
|
|
||||||
case "k":
|
|
||||||
this.executeCommand("cmd_beginLine", 1);
|
|
||||||
this.executeCommand("cmd_lineNext", 1);
|
|
||||||
this.executeCommand("cmd_selectLinePrevious", count + 1);
|
|
||||||
break;
|
|
||||||
case "h":
|
|
||||||
this.executeCommand("cmd_selectCharPrevious", count);
|
|
||||||
break;
|
|
||||||
case "l":
|
|
||||||
this.executeCommand("cmd_selectCharNext", count);
|
|
||||||
break;
|
|
||||||
case "e":
|
|
||||||
case "w":
|
|
||||||
this.executeCommand("cmd_selectWordNext", count);
|
|
||||||
break;
|
|
||||||
case "b":
|
|
||||||
this.executeCommand("cmd_selectWordPrevious", count);
|
|
||||||
break;
|
|
||||||
case "0":
|
|
||||||
case "^":
|
|
||||||
this.executeCommand("cmd_selectBeginLine", 1);
|
|
||||||
break;
|
|
||||||
case "$":
|
|
||||||
this.executeCommand("cmd_selectEndLine", 1);
|
|
||||||
break;
|
|
||||||
case "gg":
|
|
||||||
this.executeCommand("cmd_endLine", 1);
|
|
||||||
this.executeCommand("cmd_selectTop", 1);
|
|
||||||
this.executeCommand("cmd_selectBeginLine", 1);
|
|
||||||
break;
|
|
||||||
case "G":
|
|
||||||
this.executeCommand("cmd_beginLine", 1);
|
|
||||||
this.executeCommand("cmd_selectBottom", 1);
|
|
||||||
this.executeCommand("cmd_selectEndLine", 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
dactyl.beep();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// This function will move/select up to given "pos"
|
// This function will move/select up to given "pos"
|
||||||
// Simple setSelectionRange() would be better, but we want to maintain the correct
|
// Simple setSelectionRange() would be better, but we want to maintain the correct
|
||||||
// order of selectionStart/End (a Gecko bug always makes selectionStart <= selectionEnd)
|
// order of selectionStart/End (a Gecko bug always makes selectionStart <= selectionEnd)
|
||||||
@@ -427,11 +365,27 @@ var Editor = Module("editor", {
|
|||||||
}, {
|
}, {
|
||||||
mappings: function () {
|
mappings: function () {
|
||||||
|
|
||||||
|
Map.types["editor"] = {
|
||||||
|
preExecute: function preExecute(args) {
|
||||||
|
Editor.getEditor(null).beginTransaction();
|
||||||
|
},
|
||||||
|
postExecute: function preExecute(args) {
|
||||||
|
Editor.getEditor(null).endTransaction();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Map.types["operator"] = {
|
||||||
|
postExecute: function preExecute(args) {
|
||||||
|
if (modes.main == modes.OPERATOR)
|
||||||
|
modes.pop();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// add mappings for commands like h,j,k,l,etc. in CARET, VISUAL and TEXT_EDIT mode
|
// add mappings for commands like h,j,k,l,etc. in CARET, VISUAL and TEXT_EDIT mode
|
||||||
function addMovementMap(keys, description, hasCount, caretModeMethod, caretModeArg, textEditCommand, visualTextEditCommand) {
|
function addMovementMap(keys, description, hasCount, caretModeMethod, caretModeArg, textEditCommand, visualTextEditCommand) {
|
||||||
let extraInfo = {};
|
let extraInfo = {
|
||||||
if (hasCount)
|
count: !!hasCount,
|
||||||
extraInfo.count = true;
|
type: "operator"
|
||||||
|
};
|
||||||
|
|
||||||
function caretExecute(arg, again) {
|
function caretExecute(arg, again) {
|
||||||
function fixSelection() {
|
function fixSelection() {
|
||||||
@@ -486,7 +440,7 @@ var Editor = Module("editor", {
|
|||||||
},
|
},
|
||||||
extraInfo);
|
extraInfo);
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT], keys, description,
|
mappings.add([modes.OPERATOR], keys, description,
|
||||||
function ({ count }) {
|
function ({ count }) {
|
||||||
if (!count)
|
if (!count)
|
||||||
count = 1;
|
count = 1;
|
||||||
@@ -503,7 +457,8 @@ var Editor = Module("editor", {
|
|||||||
commands.forEach(function (cmd)
|
commands.forEach(function (cmd)
|
||||||
editor.executeCommand(cmd, 1));
|
editor.executeCommand(cmd, 1));
|
||||||
modes.push(modes.INSERT);
|
modes.push(modes.INSERT);
|
||||||
});
|
},
|
||||||
|
{ type: "editor" });
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPreviousLine() {
|
function selectPreviousLine() {
|
||||||
@@ -582,77 +537,89 @@ var Editor = Module("editor", {
|
|||||||
addBeginInsertModeMap(["S"], ["cmd_deleteToEndOfLine", "cmd_deleteToBeginningOfLine"], "Delete the current line and start insert");
|
addBeginInsertModeMap(["S"], ["cmd_deleteToEndOfLine", "cmd_deleteToBeginningOfLine"], "Delete the current line and start insert");
|
||||||
addBeginInsertModeMap(["C"], ["cmd_deleteToEndOfLine"], "Delete from the cursor to the end of the line and start insert");
|
addBeginInsertModeMap(["C"], ["cmd_deleteToEndOfLine"], "Delete from the cursor to the end of the line and start insert");
|
||||||
|
|
||||||
function addMotionMap(key, desc, cmd, mode) {
|
function addMotionMap(key, desc, select, cmd, mode) {
|
||||||
mappings.add([modes.TEXT_EDIT], [key],
|
mappings.add([modes.OPERATOR], [key],
|
||||||
desc,
|
desc,
|
||||||
function ({ count, motion }) {
|
function ({ count, motion, command }) {
|
||||||
editor.selectMotion(key, motion, Math.max(count, 1));
|
modes.push(modes.OPERATOR, null, {
|
||||||
if (callable(cmd))
|
leave: function leave(stack) {
|
||||||
cmd.call(events, Editor.getEditor(null));
|
if (stack.push)
|
||||||
else {
|
return;
|
||||||
editor.executeCommand(cmd, 1);
|
|
||||||
modes.pop(modes.TEXT_EDIT);
|
try {
|
||||||
}
|
editor.beginTransaction();
|
||||||
if (mode)
|
|
||||||
modes.push(mode);
|
let range = RangeFind.union(start, sel.getRangeAt(0));
|
||||||
|
sel.removeAllRanges();
|
||||||
|
sel.addRange(select ? range : start);
|
||||||
|
cmd(editor, range);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
editor.endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
modes.delay(function () {
|
||||||
|
if (mode)
|
||||||
|
modes.push(mode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let editor = Editor.getEditor(null);
|
||||||
|
let sel = editor.selection;
|
||||||
|
let start = sel.getRangeAt(0).cloneRange();
|
||||||
},
|
},
|
||||||
{ count: true, motion: true });
|
{ count: true, type: "motion" });
|
||||||
}
|
}
|
||||||
|
|
||||||
addMotionMap("d", "Delete motion", "cmd_delete");
|
addMotionMap("d", "Delete motion", true, function (editor) { editor.cut(); });
|
||||||
addMotionMap("c", "Change motion", "cmd_delete", modes.INSERT);
|
addMotionMap("c", "Change motion", true, function (editor) { editor.cut(); }, modes.INSERT);
|
||||||
addMotionMap("y", "Yank motion", "cmd_copy");
|
addMotionMap("y", "Yank motion", false, function (editor, range) { dactyl.clipboardWrite(util.domToString(range)) });
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
let bind = function bind(names, description, action, params)
|
||||||
["<C-w>"], "Delete previous word",
|
mappings.add([modes.INPUT], names, description,
|
||||||
function () { editor.executeCommand("cmd_deleteWordBackward", 1); });
|
action, update({ type: "editor" }, params));
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
bind(["<C-w>"], "Delete previous word",
|
||||||
["<C-u>"], "Delete until beginning of current line",
|
function () { editor.executeCommand("cmd_deleteWordBackward", 1); });
|
||||||
function () {
|
|
||||||
// Deletes the whole line. What the hell.
|
|
||||||
// editor.executeCommand("cmd_deleteToBeginningOfLine", 1);
|
|
||||||
|
|
||||||
editor.executeCommand("cmd_selectBeginLine", 1);
|
bind(["<C-u>"], "Delete until beginning of current line",
|
||||||
if (Editor.getController().isCommandEnabled("cmd_delete"))
|
function () {
|
||||||
editor.executeCommand("cmd_delete", 1);
|
// Deletes the whole line. What the hell.
|
||||||
});
|
// editor.executeCommand("cmd_deleteToBeginningOfLine", 1);
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
editor.executeCommand("cmd_selectBeginLine", 1);
|
||||||
["<C-k>"], "Delete until end of current line",
|
if (Editor.getController().isCommandEnabled("cmd_delete"))
|
||||||
function () { editor.executeCommand("cmd_deleteToEndOfLine", 1); });
|
editor.executeCommand("cmd_delete", 1);
|
||||||
|
});
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
bind(["<C-k>"], "Delete until end of current line",
|
||||||
["<C-a>"], "Move cursor to beginning of current line",
|
function () { editor.executeCommand("cmd_deleteToEndOfLine", 1); });
|
||||||
function () { editor.executeCommand("cmd_beginLine", 1); });
|
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
bind(["<C-a>"], "Move cursor to beginning of current line",
|
||||||
["<C-e>"], "Move cursor to end of current line",
|
function () { editor.executeCommand("cmd_beginLine", 1); });
|
||||||
function () { editor.executeCommand("cmd_endLine", 1); });
|
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
bind(["<C-e>"], "Move cursor to end of current line",
|
||||||
["<C-h>"], "Delete character to the left",
|
function () { editor.executeCommand("cmd_endLine", 1); });
|
||||||
function () { events.feedkeys("<BS>", true); });
|
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
bind(["<C-h>"], "Delete character to the left",
|
||||||
["<C-d>"], "Delete character to the right",
|
function () { events.feedkeys("<BS>", true); });
|
||||||
function () { editor.executeCommand("cmd_deleteCharForward", 1); });
|
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
bind(["<C-d>"], "Delete character to the right",
|
||||||
["<S-Insert>"], "Insert clipboard/selection",
|
function () { editor.executeCommand("cmd_deleteCharForward", 1); });
|
||||||
function () { editor.pasteClipboard(); });
|
|
||||||
|
|
||||||
mappings.add([modes.INPUT, modes.TEXT_EDIT],
|
bind(["<S-Insert>"], "Insert clipboard/selection",
|
||||||
["<C-i>"], "Edit text field with an external editor",
|
function () { editor.pasteClipboard(); });
|
||||||
function () { editor.editFieldExternally(); });
|
|
||||||
|
|
||||||
mappings.add([modes.INPUT],
|
bind(["<C-i>"], "Edit text field with an external editor",
|
||||||
["<C-t>"], "Edit text field in Vi mode",
|
function () { editor.editFieldExternally(); });
|
||||||
function () {
|
|
||||||
dactyl.assert(dactyl.focusedElement);
|
bind(["<C-t>"], "Edit text field in Vi mode",
|
||||||
dactyl.assert(!editor.isTextEdit);
|
function () {
|
||||||
modes.push(modes.TEXT_EDIT);
|
dactyl.assert(dactyl.focusedElement);
|
||||||
});
|
dactyl.assert(!editor.isTextEdit);
|
||||||
|
modes.push(modes.TEXT_EDIT);
|
||||||
|
});
|
||||||
|
|
||||||
// Ugh.
|
// Ugh.
|
||||||
mappings.add([modes.INPUT, modes.CARET],
|
mappings.add([modes.INPUT, modes.CARET],
|
||||||
@@ -673,6 +640,10 @@ var Editor = Module("editor", {
|
|||||||
["<C-]>", "<C-5>"], "Expand Insert mode abbreviation",
|
["<C-]>", "<C-5>"], "Expand Insert mode abbreviation",
|
||||||
function () { editor.expandAbbreviation(modes.INSERT); });
|
function () { editor.expandAbbreviation(modes.INSERT); });
|
||||||
|
|
||||||
|
let bind = function bind(names, description, action, params)
|
||||||
|
mappings.add([modes.TEXT_EDIT], names, description,
|
||||||
|
action, update({ type: "editor" }, params));
|
||||||
|
|
||||||
// text edit mode
|
// text edit mode
|
||||||
mappings.add([modes.TEXT_EDIT],
|
mappings.add([modes.TEXT_EDIT],
|
||||||
["u"], "Undo changes",
|
["u"], "Undo changes",
|
||||||
@@ -690,9 +661,8 @@ var Editor = Module("editor", {
|
|||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT],
|
bind(["D"], "Delete the characters under the cursor until the end of the line",
|
||||||
["D"], "Delete the characters under the cursor until the end of the line",
|
function () { editor.executeCommand("cmd_deleteToEndOfLine"); });
|
||||||
function () { editor.executeCommand("cmd_deleteToEndOfLine"); });
|
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT],
|
mappings.add([modes.TEXT_EDIT],
|
||||||
["o"], "Open line below current",
|
["o"], "Open line below current",
|
||||||
@@ -711,14 +681,12 @@ var Editor = Module("editor", {
|
|||||||
editor.executeCommand("cmd_linePrevious", 1);
|
editor.executeCommand("cmd_linePrevious", 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT],
|
bind(["X"], "Delete character to the left",
|
||||||
["X"], "Delete character to the left",
|
function (args) { editor.executeCommand("cmd_deleteCharBackward", Math.max(args.count, 1)); },
|
||||||
function (args) { editor.executeCommand("cmd_deleteCharBackward", Math.max(args.count, 1)); },
|
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT],
|
bind(["x"], "Delete character to the right",
|
||||||
["x"], "Delete character to the right",
|
function (args) { editor.executeCommand("cmd_deleteCharForward", Math.max(args.count, 1)); },
|
||||||
function (args) { editor.executeCommand("cmd_deleteCharForward", Math.max(args.count, 1)); },
|
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
// visual mode
|
// visual mode
|
||||||
@@ -764,51 +732,58 @@ var Editor = Module("editor", {
|
|||||||
dactyl.clipboardWrite(buffer.currentWord, true);
|
dactyl.clipboardWrite(buffer.currentWord, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
mappings.add([modes.VISUAL, modes.TEXT_EDIT],
|
bind(["p"], "Paste clipboard contents",
|
||||||
["p"], "Paste clipboard contents",
|
function ({ count }) {
|
||||||
function ({ count }) {
|
|
||||||
dactyl.assert(!editor.isCaret);
|
dactyl.assert(!editor.isCaret);
|
||||||
editor.executeCommand("cmd_paste", count || 1);
|
editor.executeCommand("cmd_paste", count || 1);
|
||||||
modes.pop(modes.TEXT_EDIT);
|
modes.pop(modes.TEXT_EDIT);
|
||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
|
let bind = function bind(names, description, action, params)
|
||||||
|
mappings.add([modes.OPERATOR], names, description,
|
||||||
|
action, update({ type: "editor" }, params));
|
||||||
|
|
||||||
// finding characters
|
// finding characters
|
||||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
function offset(backward, before, pos) {
|
||||||
["f"], "Move to a character on the current line after the cursor",
|
if (!backward && modes.main != modes.TEXT_EDIT)
|
||||||
function ({ arg, count }) {
|
pos += 1;
|
||||||
let pos = editor.findChar(arg, Math.max(count, 1));
|
if (before)
|
||||||
if (pos >= 0)
|
pos += backward ? +1 : -1;
|
||||||
editor.moveToPosition(pos, true, modes.main == modes.VISUAL);
|
return pos;
|
||||||
},
|
}
|
||||||
{ arg: true, count: true });
|
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
bind(["f"], "Move to a character on the current line after the cursor",
|
||||||
["F"], "Move to a character on the current line before the cursor",
|
function ({ arg, count }) {
|
||||||
function ({ arg, count }) {
|
let pos = editor.findChar(arg, Math.max(count, 1));
|
||||||
let pos = editor.findChar(arg, Math.max(count, 1), true);
|
if (pos >= 0)
|
||||||
if (pos >= 0)
|
editor.moveToPosition(offset(false, false, pos), true, modes.main == modes.VISUAL);
|
||||||
editor.moveToPosition(pos, false, modes.main == modes.VISUAL);
|
},
|
||||||
},
|
{ arg: true, count: true, type: "operator" });
|
||||||
{ arg: true, count: true });
|
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
bind(["F"], "Move to a character on the current line before the cursor",
|
||||||
["t"], "Move before a character on the current line",
|
function ({ arg, count }) {
|
||||||
function ({ arg, count }) {
|
let pos = editor.findChar(arg, Math.max(count, 1), true);
|
||||||
let pos = editor.findChar(arg, Math.max(count, 1));
|
if (pos >= 0)
|
||||||
if (pos >= 0)
|
editor.moveToPosition(offset(true, false, pos), false, modes.main == modes.VISUAL);
|
||||||
editor.moveToPosition(pos - 1, true, modes.main == modes.VISUAL);
|
},
|
||||||
},
|
{ arg: true, count: true, type: "operator" });
|
||||||
{ arg: true, count: true });
|
|
||||||
|
|
||||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
bind(["t"], "Move before a character on the current line",
|
||||||
["T"], "Move before a character on the current line, backwards",
|
function ({ arg, count }) {
|
||||||
function ({ arg, count }) {
|
let pos = editor.findChar(arg, Math.max(count, 1));
|
||||||
let pos = editor.findChar(arg, Math.max(count, 1), true);
|
if (pos >= 0)
|
||||||
if (pos >= 0)
|
editor.moveToPosition(offset(false, true, pos), true, modes.main == modes.VISUAL);
|
||||||
editor.moveToPosition(pos + 1, false, modes.main == modes.VISUAL);
|
},
|
||||||
},
|
{ arg: true, count: true, type: "operator" });
|
||||||
{ arg: true, count: true });
|
|
||||||
|
bind(["T"], "Move before a character on the current line, backwards",
|
||||||
|
function ({ arg, count }) {
|
||||||
|
let pos = editor.findChar(arg, Math.max(count, 1), true);
|
||||||
|
if (pos >= 0)
|
||||||
|
editor.moveToPosition(offset(true, true, pos), false, modes.main == modes.VISUAL);
|
||||||
|
},
|
||||||
|
{ arg: true, count: true, type: "operator" });
|
||||||
|
|
||||||
// text edit and visual mode
|
// text edit and visual mode
|
||||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
||||||
@@ -834,8 +809,8 @@ var Editor = Module("editor", {
|
|||||||
},
|
},
|
||||||
{ count: true });
|
{ count: true });
|
||||||
|
|
||||||
function bind() mappings.add.apply(mappings,
|
let bind = function bind() mappings.add.apply(mappings,
|
||||||
[[modes.AUTOCOMPLETE]].concat(Array.slice(arguments)))
|
[[modes.AUTOCOMPLETE]].concat(Array.slice(arguments)))
|
||||||
|
|
||||||
bind(["<Esc>"], "Return to Insert mode",
|
bind(["<Esc>"], "Return to Insert mode",
|
||||||
function () Events.PASS_THROUGH);
|
function () Events.PASS_THROUGH);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
* *action*.
|
* *action*.
|
||||||
* @param {string} description A short one line description of the key mapping.
|
* @param {string} description A short one line description of the key mapping.
|
||||||
* @param {function} action The action invoked by each key sequence.
|
* @param {function} action The action invoked by each key sequence.
|
||||||
* @param {Object} extraInfo An optional extra configuration hash. The
|
* @param {Object} info An optional extra configuration hash. The
|
||||||
* following properties are supported.
|
* following properties are supported.
|
||||||
* arg - see {@link Map#arg}
|
* arg - see {@link Map#arg}
|
||||||
* count - see {@link Map#count}
|
* count - see {@link Map#count}
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
var Map = Class("Map", {
|
var Map = Class("Map", {
|
||||||
init: function (modes, keys, description, action, extraInfo) {
|
init: function (modes, keys, description, action, info) {
|
||||||
this.id = ++Map.id;
|
this.id = ++Map.id;
|
||||||
this.modes = modes;
|
this.modes = modes;
|
||||||
this._keys = keys;
|
this._keys = keys;
|
||||||
@@ -38,8 +38,11 @@ var Map = Class("Map", {
|
|||||||
|
|
||||||
Object.freeze(this.modes);
|
Object.freeze(this.modes);
|
||||||
|
|
||||||
if (extraInfo)
|
if (info) {
|
||||||
this.update(extraInfo);
|
if (Set.has(Map.types, info.type))
|
||||||
|
this.update(Map.types[info.type]);
|
||||||
|
this.update(info);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
name: Class.memoize(function () this.names[0]),
|
name: Class.memoize(function () this.names[0]),
|
||||||
@@ -69,12 +72,24 @@ var Map = Class("Map", {
|
|||||||
* as an argument.
|
* as an argument.
|
||||||
*/
|
*/
|
||||||
motion: false,
|
motion: false,
|
||||||
|
|
||||||
/** @property {boolean} Whether the RHS of the mapping should expand mappings recursively. */
|
/** @property {boolean} Whether the RHS of the mapping should expand mappings recursively. */
|
||||||
noremap: false,
|
noremap: false,
|
||||||
|
|
||||||
|
/** @property {function(object)} A function to be executed before this mapping. */
|
||||||
|
preExecute: function preExecute(args) {},
|
||||||
|
/** @property {function(object)} A function to be executed after this mapping. */
|
||||||
|
postExecute: function postExecute(args) {},
|
||||||
|
|
||||||
/** @property {boolean} Whether any output from the mapping should be echoed on the command line. */
|
/** @property {boolean} Whether any output from the mapping should be echoed on the command line. */
|
||||||
silent: false,
|
silent: false,
|
||||||
|
|
||||||
/** @property {string} The literal RHS expansion of this mapping. */
|
/** @property {string} The literal RHS expansion of this mapping. */
|
||||||
rhs: null,
|
rhs: null,
|
||||||
|
|
||||||
|
/** @property {string} The type of this mapping. */
|
||||||
|
type: "",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {boolean} Specifies whether this is a user mapping. User
|
* @property {boolean} Specifies whether this is a user mapping. User
|
||||||
* mappings may be created by plugins, or directly by users. Users and
|
* mappings may be created by plugins, or directly by users. Users and
|
||||||
@@ -118,6 +133,7 @@ var Map = Class("Map", {
|
|||||||
dactyl.assert(!this.executing, _("map.recursive", args.command));
|
dactyl.assert(!this.executing, _("map.recursive", args.command));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
this.preExecute(args);
|
||||||
this.executing = true;
|
this.executing = true;
|
||||||
var res = repeat();
|
var res = repeat();
|
||||||
}
|
}
|
||||||
@@ -127,12 +143,15 @@ var Map = Class("Map", {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
this.executing = false;
|
this.executing = false;
|
||||||
|
this.postExecute(args);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
id: 0
|
id: 0,
|
||||||
|
|
||||||
|
types: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
var MapHive = Class("MapHive", Contexts.Hive, {
|
var MapHive = Class("MapHive", Contexts.Hive, {
|
||||||
|
|||||||
@@ -57,11 +57,16 @@ var Modes = Module("modes", {
|
|||||||
description: "Active when nothing is focused",
|
description: "Active when nothing is focused",
|
||||||
bases: [this.COMMAND]
|
bases: [this.COMMAND]
|
||||||
});
|
});
|
||||||
|
this.addMode("OPERATOR", {
|
||||||
|
char: "o",
|
||||||
|
description: "Mappings which move the cursor",
|
||||||
|
bases: []
|
||||||
|
});
|
||||||
this.addMode("VISUAL", {
|
this.addMode("VISUAL", {
|
||||||
char: "v",
|
char: "v",
|
||||||
description: "Active when text is selected",
|
description: "Active when text is selected",
|
||||||
display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : ""),
|
display: function () "VISUAL" + (this._extended & modes.LINE ? " LINE" : ""),
|
||||||
bases: [this.COMMAND],
|
bases: [this.COMMAND, this.OPERATOR],
|
||||||
ownsFocus: true
|
ownsFocus: true
|
||||||
}, {
|
}, {
|
||||||
leave: function (stack, newMode) {
|
leave: function (stack, newMode) {
|
||||||
@@ -97,7 +102,7 @@ var Modes = Module("modes", {
|
|||||||
this.addMode("TEXT_EDIT", {
|
this.addMode("TEXT_EDIT", {
|
||||||
char: "t",
|
char: "t",
|
||||||
description: "Vim-like editing of input elements",
|
description: "Vim-like editing of input elements",
|
||||||
bases: [this.COMMAND],
|
bases: [this.OPERATOR, this.COMMAND],
|
||||||
ownsFocus: true
|
ownsFocus: true
|
||||||
}, {
|
}, {
|
||||||
onKeyPress: function (eventList) {
|
onKeyPress: function (eventList) {
|
||||||
@@ -489,7 +494,7 @@ var Modes = Module("modes", {
|
|||||||
init: function init(name, options, params) {
|
init: function init(name, options, params) {
|
||||||
if (options.bases)
|
if (options.bases)
|
||||||
util.assert(options.bases.every(function (m) m instanceof this, this.constructor),
|
util.assert(options.bases.every(function (m) m instanceof this, this.constructor),
|
||||||
_("mode.invalidBases"), true);
|
_("mode.invalidBases"), false);
|
||||||
|
|
||||||
this.update({
|
this.update({
|
||||||
id: 1 << Modes.Mode._id++,
|
id: 1 << Modes.Mode._id++,
|
||||||
@@ -647,7 +652,7 @@ var Modes = Module("modes", {
|
|||||||
|
|
||||||
options.add(["showmode", "smd"],
|
options.add(["showmode", "smd"],
|
||||||
"Show the current mode in the command line when it matches this expression",
|
"Show the current mode in the command line when it matches this expression",
|
||||||
"stringlist", "caret,output_multiline,!normal,base",
|
"stringlist", "caret,output_multiline,!normal,base,operator",
|
||||||
opts);
|
opts);
|
||||||
},
|
},
|
||||||
prefs: function initPrefs() {
|
prefs: function initPrefs() {
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
<dt>i</dt> <dd>Insert mode: When interacting with text fields on a website</dd>
|
<dt>i</dt> <dd>Insert mode: When interacting with text fields on a website</dd>
|
||||||
<dt>t</dt> <dd>Text Edit mode: When editing text fields in Vim-like Normal mode</dd>
|
<dt>t</dt> <dd>Text Edit 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>
|
<dt>c</dt> <dd>Command Line mode: When typing into the &dactyl.appName; command line</dd>
|
||||||
|
<dt>o</dt> <dd>Operator mode: When moving the cursor</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -774,7 +774,14 @@ var RangeFind = Class("RangeFind", {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
selectNodePath: ["a", "xhtml:a", "*[@onclick]"].map(function (p) "ancestor-or-self::" + p).join(" | ")
|
selectNodePath: ["a", "xhtml:a", "*[@onclick]"].map(function (p) "ancestor-or-self::" + p).join(" | "),
|
||||||
|
union: function union(a, b) {
|
||||||
|
let start = a.compareBoundaryPoints(a.START_TO_START, b) < 0 ? a : b;
|
||||||
|
let end = a.compareBoundaryPoints(a.END_TO_END, b) > 0 ? a : b;
|
||||||
|
let res = start.cloneRange();
|
||||||
|
res.setEnd(end.startContainer, end.endOffset);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch(e){ if (typeof e === "string") e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
|
} catch(e){ if (typeof e === "string") e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
• Mapping changes:
|
• Mapping changes:
|
||||||
- It's now possible to map keys in many more modes, including
|
- It's now possible to map keys in many more modes, including
|
||||||
Hint, Multi-line Output, and Menu. [b4]
|
Hint, Multi-line Output, and Menu. [b4]
|
||||||
|
- Added Operator mode for motion maps, per Vim. [b8]
|
||||||
- Added site-specific mapping groups and related command
|
- Added site-specific mapping groups and related command
|
||||||
changes. [b6]
|
changes. [b6]
|
||||||
- Added 'timeout' and 'timeoutlen' options. [b6]
|
- Added 'timeout' and 'timeoutlen' options. [b6]
|
||||||
|
|||||||
Reference in New Issue
Block a user