mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-21 08:37:58 +01:00
Long awaited augmentation of the :map command. Surrounding code needs cleanup.
--HG-- extra : rebase_source : 6bb2406343f04aff20456e1a9d0cb595f4ec767d
This commit is contained in:
@@ -696,7 +696,7 @@ const Commands = Module("commands", {
|
|||||||
if (opt.multiple)
|
if (opt.multiple)
|
||||||
args[opt.names[0]] = (args[opt.names[0]] || []).concat(arg);
|
args[opt.names[0]] = (args[opt.names[0]] || []).concat(arg);
|
||||||
else
|
else
|
||||||
args[opt.names[0]] = opt.type == this.OPTION_NOARG || arg;
|
args[opt.names[0]] = opt.type == CommandOption.NOARG || arg;
|
||||||
|
|
||||||
i += optname.length + count;
|
i += optname.length + count;
|
||||||
if (i == str.length)
|
if (i == str.length)
|
||||||
@@ -919,7 +919,7 @@ const Commands = Module("commands", {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[prefix] = context.filter.match(/^(?:\w*[\s!]|!)\s*/);
|
[prefix] = context.filter.match(/^(?:\w*[\s!])?\s*/);
|
||||||
let cmdContext = context.fork(command.name, prefix.length);
|
let cmdContext = context.fork(command.name, prefix.length);
|
||||||
let argContext = context.fork("args", prefix.length);
|
let argContext = context.fork("args", prefix.length);
|
||||||
args = command.parseArgs(cmdContext.filter, argContext, { count: count, bang: bang });
|
args = command.parseArgs(cmdContext.filter, argContext, { count: count, bang: bang });
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ const Dactyl = Module("dactyl", {
|
|||||||
* userContext global.
|
* userContext global.
|
||||||
*/
|
*/
|
||||||
userfunc: function () {
|
userfunc: function () {
|
||||||
return this.userEval(
|
return this.usereval(
|
||||||
"(function (" +
|
"(function (" +
|
||||||
Array.slice(arguments, 0, -1).join(", ") +
|
Array.slice(arguments, 0, -1).join(", ") +
|
||||||
") { " + arguments[arguments.length - 1] + " })")
|
") { " + arguments[arguments.length - 1] + " })")
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const Map = Class("Map", {
|
|||||||
init: function (modes, keys, description, action, extraInfo) {
|
init: function (modes, keys, description, action, extraInfo) {
|
||||||
modes = Array.concat(modes).map(function (m) isobject(m) ? m.mask : m);
|
modes = Array.concat(modes).map(function (m) isobject(m) ? m.mask : m);
|
||||||
|
|
||||||
|
this.id = ++Map.id;
|
||||||
this.modes = modes;
|
this.modes = modes;
|
||||||
this.names = keys.map(events.canonicalKeys);
|
this.names = keys.map(events.canonicalKeys);
|
||||||
this.name = this.names[0];
|
this.name = this.names[0];
|
||||||
@@ -117,6 +118,8 @@ const Map = Class("Map", {
|
|||||||
return dactyl.trapErrors(repeat);
|
return dactyl.trapErrors(repeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}, {
|
||||||
|
id: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,8 +180,8 @@ const Mappings = Module("mappings", {
|
|||||||
_mappingsIterator: function (modes, stack) {
|
_mappingsIterator: function (modes, stack) {
|
||||||
modes = modes.slice();
|
modes = modes.slice();
|
||||||
return (map for ([i, map] in Iterator(stack[modes.shift()].sort(function (m1, m2) String.localeCompare(m1.name, m2.name))))
|
return (map for ([i, map] in Iterator(stack[modes.shift()].sort(function (m1, m2) String.localeCompare(m1.name, m2.name))))
|
||||||
if (modes.every(function (mode) stack[mode].some(
|
if (modes.every(function (mode) stack[mode].
|
||||||
function (m) m.rhs == map.rhs && m.name == map.name))))
|
some(function (m) array.equals(m.rhs, map.rhs) && m.name == map.name))))
|
||||||
},
|
},
|
||||||
|
|
||||||
// NOTE: just normal mode for now
|
// NOTE: just normal mode for now
|
||||||
@@ -356,7 +359,7 @@ const Mappings = Module("mappings", {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{modeSign} {name}</td>
|
<td>{modeSign} {name}</td>
|
||||||
<td>{map.noremap ? "*" : " "}</td>
|
<td>{map.noremap ? "*" : " "}</td>
|
||||||
<td>{map.rhs || "function () { ... }"}</td>
|
<td>{map.rhs ? map.rhs.join(" ") : "function () { ... }"}</td>
|
||||||
</tr>))
|
</tr>))
|
||||||
}
|
}
|
||||||
</table>;
|
</table>;
|
||||||
@@ -370,32 +373,49 @@ const Mappings = Module("mappings", {
|
|||||||
}, {
|
}, {
|
||||||
}, {
|
}, {
|
||||||
commands: function () {
|
commands: function () {
|
||||||
function addMapCommands(ch, modes, modeDescription) {
|
const stockDescription = "User defined mapping";
|
||||||
|
function addMapCommands(ch, mapmodes, modeDescription) {
|
||||||
// 0 args -> list all maps
|
// 0 args -> list all maps
|
||||||
// 1 arg -> list the maps starting with args
|
// 1 arg -> list the maps starting with args
|
||||||
// 2 args -> map arg1 to arg*
|
// 2 args -> map arg1 to arg*
|
||||||
function map(args, modes, noremap) {
|
function map(args, mapmodes, noremap) {
|
||||||
|
mapmodes = getModes(args, mapmodes);
|
||||||
if (!args.length) {
|
if (!args.length) {
|
||||||
mappings.list(modes);
|
mappings.list(mapmodes);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [lhs, rhs] = args;
|
let [lhs, rhs] = args;
|
||||||
|
|
||||||
if (!rhs) // list the mapping
|
if (!rhs) // list the mapping
|
||||||
mappings.list(modes, mappings._expandLeader(lhs));
|
mappings.list(mapmodes, mappings._expandLeader(lhs));
|
||||||
else {
|
else {
|
||||||
// this matches Vim's behaviour
|
if (args["-javascript"]) {
|
||||||
if (/^<Nop>$/i.test(rhs))
|
rhs = ["-javascript", rhs];
|
||||||
noremap = true;
|
var action = dactyl.userfunc("count", rhs);
|
||||||
|
}
|
||||||
|
else if (args["-ex"]) {
|
||||||
|
rhs = ["-ex", rhs];
|
||||||
|
action = function (count) {
|
||||||
|
dactyl.execute(commands.replaceTokens(rhs[1], { count: count }));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rhs = [events.canonicalKeys(rhs)];
|
||||||
|
action = function (count) {
|
||||||
|
events.feedkeys(commands.replaceTokens(rhs[0], { count: count }),
|
||||||
|
this.noremap, this.silent);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
mappings.addUserMap(modes, [lhs],
|
mappings.addUserMap(mapmodes, [lhs],
|
||||||
"User defined mapping",
|
args["-description"] || stockDescription,
|
||||||
function (count) { events.feedkeys((count || "") + this.rhs, this.noremap, this.silent); }, {
|
action, {
|
||||||
count: true,
|
count: args["-count"],
|
||||||
rhs: events.canonicalKeys(rhs),
|
rhs: rhs,
|
||||||
noremap: !!noremap,
|
noremap: "-builtin" in args || noremap,
|
||||||
silent: "<silent>" in args
|
persist: !args["-nopersist"],
|
||||||
|
silent: "-silent" in args
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,38 +429,109 @@ const Mappings = Module("mappings", {
|
|||||||
&& /^[nv](nore)?map$/.test(cmd);
|
&& /^[nv](nore)?map$/.test(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findMode(name) {
|
||||||
|
if (typeof name == "number")
|
||||||
|
return name;
|
||||||
|
for (let mode in modes.mainModes)
|
||||||
|
if (name == mode.char || name == mode.name.toLowerCase())
|
||||||
|
return mode.mask;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function getModes(args, def)
|
||||||
|
array.uniq((args["-modes"] || def || ["n", "v"]).map(findMode));
|
||||||
|
function uniqueModes(modes) {
|
||||||
|
modes = modes.map(modules.modes.closure.getMode);
|
||||||
|
let chars = [k for ([k, v] in Iterator(modules.modes.modeChars))
|
||||||
|
if (v.every(function (mode) modes.indexOf(mode) >= 0))];
|
||||||
|
return array.uniq(modes.filter(function (m) chars.indexOf(m.char) < 0).concat(chars));
|
||||||
|
}
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
completer: function (context, args) completion.userMapping(context, args, modes),
|
completer: function (context, args) {
|
||||||
|
if (args.length == 1)
|
||||||
|
return completion.userMapping(context, args, mapmodes)
|
||||||
|
if (args["-javascript"])
|
||||||
|
return completion.javascript(context);
|
||||||
|
if (args["-ex"])
|
||||||
|
return completion.ex(context);
|
||||||
|
},
|
||||||
literal: 1,
|
literal: 1,
|
||||||
options: [{ names: ["<silent>", "<Silent>"] }],
|
options: [
|
||||||
|
{
|
||||||
|
names: ["-builtin", "-b"],
|
||||||
|
description: "Execute this mapping as if there were no user-defined mappings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ["-descripion", "-d"],
|
||||||
|
type: CommandOption.STRING,
|
||||||
|
description: "A discription of this mapping"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ["-ex", "-e"],
|
||||||
|
description: "Execute this mapping as an Ex command rather than keys"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ["-javascript", "-js", "-j"],
|
||||||
|
description: "Execute this mapping as JavaScript rather than keys"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ["-modes", "-mode", "-m"],
|
||||||
|
type: CommandOption.LIST,
|
||||||
|
description: "Create this mapping in the given modes",
|
||||||
|
validator: function (list) !list || list.every(findMode),
|
||||||
|
completer: function () [[array.compact([mode.name.toLowerCase(), mode.char]), mode.disp]
|
||||||
|
for (mode in modes.mainModes)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ["-nopersist", "-n"],
|
||||||
|
description: "Do not save this mapping to an auto-generated RC file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
names: ["-silent", "-s", "<silent>", "<Silent>"],
|
||||||
|
description: "Do not echo any generated keys to the command-line"
|
||||||
|
}
|
||||||
|
],
|
||||||
serialize: function () {
|
serialize: function () {
|
||||||
let noremap = this.name.indexOf("noremap") > -1;
|
return this.name == "map" ? [
|
||||||
return [
|
|
||||||
{
|
{
|
||||||
command: this.name,
|
command: this.name,
|
||||||
options: map.silent ? { "<silent>": null } : {},
|
options: array([
|
||||||
|
["-modes", uniqueModes(map.modes)],
|
||||||
|
map.noremap && ["-builtin"],
|
||||||
|
map.description != stockDescription && ["-description", map.description],
|
||||||
|
map.rhs.length > 1 && [map.rhs[0]],
|
||||||
|
map.silent && ["-silent"]])
|
||||||
|
.filter(util.identity)
|
||||||
|
.toObject(),
|
||||||
arguments: [map.names[0]],
|
arguments: [map.names[0]],
|
||||||
literalArg: map.rhs
|
literalArg: map.rhs[map.rhs.length - 1]
|
||||||
}
|
}
|
||||||
for (map in mappings._mappingsIterator(modes, mappings._user))
|
for (map in userMappings())
|
||||||
if (map.rhs && map.noremap == noremap && !isMultiMode(map, this.name))
|
if (map.persist)
|
||||||
];
|
] : [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
function userMappings() {
|
||||||
|
let seen = {};
|
||||||
|
for (let [, stack] in Iterator(mappings._user))
|
||||||
|
for (let map in values(stack))
|
||||||
|
if (!set.add(seen, map.id))
|
||||||
|
yield map;
|
||||||
|
}
|
||||||
|
|
||||||
commands.add([ch ? ch + "m[ap]" : "map"],
|
commands.add([ch ? ch + "m[ap]" : "map"],
|
||||||
"Map a key sequence" + modeDescription,
|
"Map a key sequence" + modeDescription,
|
||||||
function (args) { map(args, modes, false); },
|
function (args) { map(args, mapmodes, false); },
|
||||||
opts);
|
opts);
|
||||||
|
|
||||||
commands.add([ch + "no[remap]"],
|
commands.add([ch + "no[remap]"],
|
||||||
"Map a key sequence without remapping keys" + modeDescription,
|
"Map a key sequence without remapping keys" + modeDescription,
|
||||||
function (args) { map(args, modes, true); },
|
function (args) { map(args, mapmodes, true); },
|
||||||
opts);
|
opts);
|
||||||
|
|
||||||
commands.add([ch + "mapc[lear]"],
|
commands.add([ch + "mapc[lear]"],
|
||||||
"Remove all mappings" + modeDescription,
|
"Remove all mappings" + modeDescription,
|
||||||
function () { modes.forEach(function (mode) { mappings.removeAll(mode); }); },
|
function () { mapmodes.forEach(function (mode) { mappings.removeAll(mode); }); },
|
||||||
{ argCount: "0" });
|
{ argCount: "0" });
|
||||||
|
|
||||||
commands.add([ch + "unm[ap]"],
|
commands.add([ch + "unm[ap]"],
|
||||||
@@ -449,7 +540,7 @@ const Mappings = Module("mappings", {
|
|||||||
args = args[0];
|
args = args[0];
|
||||||
|
|
||||||
let found = false;
|
let found = false;
|
||||||
for (let [, mode] in Iterator(modes)) {
|
for (let [, mode] in Iterator(mapmodes)) {
|
||||||
if (mappings.hasMap(mode, args)) {
|
if (mappings.hasMap(mode, args)) {
|
||||||
mappings.remove(mode, args);
|
mappings.remove(mode, args);
|
||||||
found = true;
|
found = true;
|
||||||
@@ -460,7 +551,7 @@ const Mappings = Module("mappings", {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
argCount: "1",
|
argCount: "1",
|
||||||
completer: function (context, args) completion.userMapping(context, args, modes)
|
completer: function (context, args) completion.userMapping(context, args, mapmodes)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
const Modes = Module("modes", {
|
const Modes = Module("modes", {
|
||||||
init: function () {
|
init: function () {
|
||||||
|
this.modeChars = {};
|
||||||
this._main = 1; // NORMAL
|
this._main = 1; // NORMAL
|
||||||
this._extended = 0; // NONE
|
this._extended = 0; // NONE
|
||||||
|
|
||||||
@@ -143,6 +144,11 @@ const Modes = Module("modes", {
|
|||||||
name: name,
|
name: name,
|
||||||
disp: disp
|
disp: disp
|
||||||
}, options);
|
}, options);
|
||||||
|
if (mode.char) {
|
||||||
|
this.modeChars[mode.char] = this.modeChars[mode.char] || [];
|
||||||
|
this.modeChars[mode.char].push(mode);
|
||||||
|
}
|
||||||
|
|
||||||
mode.display = mode.display || function () disp;
|
mode.display = mode.display || function () disp;
|
||||||
this._modeMap[name] = mode;
|
this._modeMap[name] = mode;
|
||||||
this._modeMap[this[name]] = mode;
|
this._modeMap[this[name]] = mode;
|
||||||
|
|||||||
@@ -62,8 +62,6 @@
|
|||||||
prefixed with one of the above letters. For instance,
|
prefixed with one of the above letters. For instance,
|
||||||
<ex>:imap</ex> creates a new key mapping in insert mode, while
|
<ex>:imap</ex> creates a new key mapping in insert mode, while
|
||||||
<ex>:cunmap</ex> removes a key mapping from command-line mode.
|
<ex>:cunmap</ex> removes a key mapping from command-line mode.
|
||||||
Although other modes do exist, their mappings may currently only
|
|
||||||
be altered via JavaScript.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<warning>
|
<warning>
|
||||||
@@ -103,6 +101,24 @@
|
|||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
|
||||||
|
<h3 tag=":map-options">Map options</h3>
|
||||||
|
<p>
|
||||||
|
Any of the map commands may be given the following options:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt></dt> <dd></dd>
|
||||||
|
|
||||||
|
<dt>-builtin</dt> <dd>Execute this mapping as if there were no user-defined mappings (short name <em>-b</em>)</dd>
|
||||||
|
<dt>-descripion</dt> <dd>A discription of this mapping (short name <em>-d</em>)</dd>
|
||||||
|
<dt>-ex</dt> <dd>Execute <a>rhs</a> as an Ex command rather than keys (short name <em>-e</em>)</dd>
|
||||||
|
<dt>-javascript</dt> <dd>Execute <a>rhs</a> as JavaScript rather than keys (short names <em>-js</em>, <em>-j</em>)</dd>
|
||||||
|
<dt>-modes</dt> <dd>Create this mapping in the given modes (short names <em>-mode</em>, <em>-m</em>)</dd>
|
||||||
|
<dt>-nopersist</dt> <dd>Do not save this mapping to an auto-generated rc file (short name <em>-n</em>)</dd>
|
||||||
|
<dt>-silent</dt> <dd>Do not echo any generated keys to the command-line (short name <em>-s</em>, also <em><silent></em> for Vim compatibility)</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<tags>:no :noremap</tags>
|
<tags>:no :noremap</tags>
|
||||||
<spec>:no<oa>remap</oa> <a>lhs</a> <a>rhs</a></spec>
|
<spec>:no<oa>remap</oa> <a>lhs</a> <a>rhs</a></spec>
|
||||||
|
|||||||
@@ -937,6 +937,17 @@ const array = Class("array", Array, {
|
|||||||
*/
|
*/
|
||||||
compact: function compact(ary) ary.filter(function (item) item != null),
|
compact: function compact(ary) ary.filter(function (item) item != null),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if each element of ary1 is equal to the
|
||||||
|
* corresponding element in ary2.
|
||||||
|
*
|
||||||
|
* @param {Array} ary1
|
||||||
|
* @param {Array} ary2
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
equals: function (ary1, ary2)
|
||||||
|
ary1.length == ary2.length && Array.every(ary1, function (e, i) e == ary2[i]),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flattens an array, such that all elements of the array are
|
* Flattens an array, such that all elements of the array are
|
||||||
* joined into a single array:
|
* joined into a single array:
|
||||||
|
|||||||
@@ -28,6 +28,9 @@
|
|||||||
* Added ‘transliterated’ option to 'hintmatching'
|
* Added ‘transliterated’ option to 'hintmatching'
|
||||||
* Added 'autocomplete' option for specifying which completion
|
* Added 'autocomplete' option for specifying which completion
|
||||||
contexts should be autocompleted
|
contexts should be autocompleted
|
||||||
|
* Added several new options to :map
|
||||||
|
* Removed the :source line at the end of files generated by
|
||||||
|
:mkpentadactylrc
|
||||||
* gf now toggles between source and content view.
|
* gf now toggles between source and content view.
|
||||||
The | key binding has been removed.
|
The | key binding has been removed.
|
||||||
* :extadd now supports remote URLs as well as local files on
|
* :extadd now supports remote URLs as well as local files on
|
||||||
|
|||||||
Reference in New Issue
Block a user