* A class representing key mappings. Instances are created by the
* {@link Mappings} class.
*
- * @param {number[]} modes The modes in which this mapping is active.
- * @param {string[]} keys The key sequences which are bound to
+ * @param {[Modes.Mode]} modes The modes in which this mapping is active.
+ * @param {[string]} keys The key sequences which are bound to
* *action*.
* @param {string} description A short one line description of the key mapping.
* @param {function} action The action invoked by each key sequence.
*/
var Map = Class("Map", {
init: function (modes, keys, description, action, extraInfo) {
- modes = Array.concat(modes);
- if (!modes.every(util.identity))
- throw TypeError("Invalid modes: " + modes);
-
this.id = ++Map.id;
this.modes = modes;
this._keys = keys;
this.action = action;
this.description = description;
- if (Object.freeze)
- Object.freeze(this.modes);
+ Object.freeze(this.modes);
if (extraInfo)
- update(this, extraInfo);
+ this.update(extraInfo);
},
name: Class.memoize(function () this.names[0]),
- /** @property {string[]} All of this mapping's names (key sequences). */
+ /** @property {[string]} All of this mapping's names (key sequences). */
names: Class.memoize(function () this._keys.map(function (k) events.canonicalKeys(k))),
get toStringParams() [this.modes.map(function (m) m.name), this.names.map(String.quote)],
/** @property {number} A unique ID for this mapping. */
id: null,
- /** @property {number[]} All of the modes for which this mapping applies. */
+ /** @property {[Modes.Mode]} All of the modes for which this mapping applies. */
modes: null,
/** @property {function (number)} The function called to execute this mapping. */
action: null,
*/
hasName: function (name) this.keys.indexOf(name) >= 0,
- get keys() this.names.map(mappings.expandLeader),
+ get keys() array.flatten(this.names.map(mappings.closure.expand)),
/**
* Execute the action for this mapping.
mappings.repeat = repeat;
if (this.executing)
- util.dumpStack("Attempt to execute mapping recursively: " + args.command);
+ util.dumpStack(_("map.recursive", args.command));
dactyl.assert(!this.executing, _("map.recursive", args.command));
try {
},
/**
- * Adds a new default key mapping.
+ * Adds a new key mapping.
*
- * @param {number[]} modes The modes that this mapping applies to.
- * @param {string[]} keys The key sequences which are bound to *action*.
+ * @param {[Modes.Mode]} modes The modes that this mapping applies to.
+ * @param {[string]} keys The key sequences which are bound to *action*.
* @param {string} description A description of the key mapping.
* @param {function} action The action invoked by each key sequence.
* @param {Object} extra An optional extra configuration hash.
add: function (modes, keys, description, action, extra) {
extra = extra || {};
+ modes = Array.concat(modes);
+ if (!modes.every(util.identity))
+ throw TypeError(/*L*/"Invalid modes: " + modes);
+
let map = Map(modes, keys, description, action, extra);
map.definedAt = contexts.getCaller(Components.stack.caller);
map.hive = this;
get userHives() this.allHives.filter(function (h) h !== this.builtin, this),
- expandLeader: function (keyString) keyString.replace(/<Leader>/i, options["mapleader"]),
+ expandLeader: function expandLeader(keyString) keyString.replace(/<Leader>/i, function () options["mapleader"]),
+
+ prefixes: Class.memoize(function () {
+ let list = Array.map("CASM", function (s) s + "-");
+
+ return iter(util.range(0, 1 << list.length)).map(function (mask)
+ list.filter(function (p, i) mask & (1 << i)).join("")).toArray().concat("*-");
+ }),
+
+ expand: function expand(keys) {
+ keys = keys.replace(/<leader>/i, options["mapleader"]);
+ if (!/<\*-/.test(keys))
+ return keys;
+
+ return util.debrace(events.iterKeys(keys).map(function (key) {
+ if (/^<\*-/.test(key))
+ return ["<", this.prefixes, key.slice(3)];
+ return key;
+ }, this).flatten().array).map(function (k) events.canonicalKeys(k));
+ },
iterate: function (mode) {
let seen = {};
for (let hive in this.hives.iterValues())
for (let map in array(hive.getStack(mode)).iterValues())
- if (!set.add(seen, map.name))
+ if (!Set.add(seen, map.name))
yield map;
},
/**
* Adds a new default key mapping.
*
- * @param {number[]} modes The modes that this mapping applies to.
- * @param {string[]} keys The key sequences which are bound to *action*.
+ * @param {[Modes.Mode]} modes The modes that this mapping applies to.
+ * @param {[string]} keys The key sequences which are bound to *action*.
* @param {string} description A description of the key mapping.
* @param {function} action The action invoked by each key sequence.
* @param {Object} extra An optional extra configuration hash.
/**
* Adds a new user-defined key mapping.
*
- * @param {number[]} modes The modes that this mapping applies to.
- * @param {string[]} keys The key sequences which are bound to *action*.
+ * @param {[Modes.Mode]} modes The modes that this mapping applies to.
+ * @param {[string]} keys The key sequences which are bound to *action*.
* @param {string} description A description of the key mapping.
* @param {function} action The action invoked by each key sequence.
* @param {Object} extra An optional extra configuration hash (see
/**
* Returns the map from *mode* named *cmd*.
*
- * @param {number} mode The mode to search.
+ * @param {Modes.Mode} mode The mode to search.
* @param {string} cmd The map name to match.
* @returns {Map}
*/
* Returns an array of maps with names starting with but not equal to
* *prefix*.
*
- * @param {number} mode The mode to search.
+ * @param {Modes.Mode} mode The mode to search.
* @param {string} prefix The map prefix string to match.
- * @returns {Map[]}
+ * @returns {[Map]}
*/
getCandidates: function (mode, prefix)
this.hives.map(function (h) h.getCandidates(mode, prefix))
/**
* Lists all user-defined mappings matching *filter* for the specified
- * *modes*.
+ * *modes* in the specified *hives*.
*
- * @param {number[]} modes An array of modes to search.
- * @param {string} filter The filter string to match.
+ * @param {[Modes.Mode]} modes An array of modes to search.
+ * @param {string} filter The filter string to match. @optional
+ * @param {[MapHive]} hives The map hives to list. @optional
*/
list: function (modes, filter, hives) {
- let modeSign = "";
- modes.filter(function (m) m.char).forEach(function (m) { modeSign += m.char; });
- modes.filter(function (m) !m.char).forEach(function (m) { modeSign += " " + m.name; });
+ let modeSign = modes.map(function (m) m.char || "").join("")
+ + modes.map(function (m) !m.char ? " " + m.name : "").join("");
modeSign = modeSign.replace(/^ /, "");
hives = (hives || mappings.userHives).map(function (h) [h, maps(h)])
let list = <table>
<tr highlight="Title">
<td/>
- <td style="padding-right: 1em;">Mode</td>
- <td style="padding-right: 1em;">Command</td>
- <td style="padding-right: 1em;">Action</td>
+ <td style="padding-right: 1em;">{_("title.Mode")}</td>
+ <td style="padding-right: 1em;">{_("title.Command")}</td>
+ <td style="padding-right: 1em;">{_("title.Action")}</td>
</tr>
<col style="min-width: 6em; padding-right: 1em;"/>
{
return;
}
+ if (args[1] && !/^<nop>$/i.test(args[1])
+ && !args["-count"] && !args["-ex"] && !args["-javascript"]
+ && mapmodes.every(function (m) m.count))
+ args[1] = "<count>" + args[1];
+
let [lhs, rhs] = args;
if (noremap)
args["-builtin"] = true;
contexts.bindMacro(args, "-keys", function (params) params),
{
arg: args["-arg"],
- count: args["-count"],
+ count: args["-count"] || !(args["-ex"] || args["-javascript"]),
noremap: args["-builtin"],
persist: !args["-nopersist"],
get rhs() String(this.action),
}
const opts = {
- completer: function (context, args) {
- let mapmodes = array.uniq(args["-modes"].map(findMode));
- if (args.length == 1)
- return completion.userMapping(context, mapmodes, args["-group"]);
- if (args.length == 2) {
- if (args["-javascript"])
- return completion.javascript(context);
- if (args["-ex"])
- return completion.ex(context);
- }
+ identifier: "map",
+ completer: function (context, args) {
+ let mapmodes = array.uniq(args["-modes"].map(findMode));
+ if (args.length == 1)
+ return completion.userMapping(context, mapmodes, args["-group"]);
+ if (args.length == 2) {
+ if (args["-javascript"])
+ return completion.javascript(context);
+ if (args["-ex"])
+ return completion.ex(context);
+ }
+ },
+ hereDoc: true,
+ literal: 1,
+ options: [
+ {
+ names: ["-arg", "-a"],
+ description: "Accept an argument after the requisite key press",
},
- hereDoc: true,
- literal: 1,
- options: [
- {
- names: ["-arg", "-a"],
- description: "Accept an argument after the requisite key press",
- },
- {
- names: ["-builtin", "-b"],
- description: "Execute this mapping as if there were no user-defined mappings"
- },
- {
- names: ["-count", "-c"],
- description: "Accept a count before the requisite key press"
- },
- {
- names: ["-description", "-desc", "-d"],
- description: "A description of this mapping",
- default: "User-defined mapping",
- type: CommandOption.STRING
- },
- {
- names: ["-ex", "-e"],
- description: "Execute this mapping as an Ex command rather than keys"
- },
- contexts.GroupFlag("mappings"),
- {
- names: ["-javascript", "-js", "-j"],
- description: "Execute this mapping as JavaScript rather than keys"
- },
- update({}, modeFlag, {
- names: ["-modes", "-mode", "-m"],
- type: CommandOption.LIST,
- description: "Create this mapping in the given modes",
- default: mapmodes || ["n", "v"]
- }),
- {
- 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 () {
- return this.name != "map" ? [] :
- array(mappings.userHives)
- .filter(function (h) h.persist)
- .map(function (hive) [
- {
- command: "map",
- options: array([
- hive.name !== "user" && ["-group", hive.name],
- ["-modes", uniqueModes(map.modes)],
- ["-description", map.description],
- map.silent && ["-silent"]])
-
- .filter(util.identity)
- .toObject(),
- arguments: [map.names[0]],
- literalArg: map.rhs,
- ignoreDefaults: true
- }
- for (map in userMappings(hive))
- if (map.persist)
- ])
- .flatten().array;
+ {
+ names: ["-builtin", "-b"],
+ description: "Execute this mapping as if there were no user-defined mappings"
+ },
+ {
+ names: ["-count", "-c"],
+ description: "Accept a count before the requisite key press"
+ },
+ {
+ names: ["-description", "-desc", "-d"],
+ description: "A description of this mapping",
+ default: /*L*/"User-defined mapping",
+ type: CommandOption.STRING
+ },
+ {
+ names: ["-ex", "-e"],
+ description: "Execute this mapping as an Ex command rather than keys"
+ },
+ contexts.GroupFlag("mappings"),
+ {
+ names: ["-javascript", "-js", "-j"],
+ description: "Execute this mapping as JavaScript rather than keys"
+ },
+ update({}, modeFlag, {
+ names: ["-modes", "-mode", "-m"],
+ type: CommandOption.LIST,
+ description: "Create this mapping in the given modes",
+ default: mapmodes || ["n", "v"]
+ }),
+ {
+ 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 () {
+ return this.name != "map" ? [] :
+ array(mappings.userHives)
+ .filter(function (h) h.persist)
+ .map(function (hive) [
+ {
+ command: "map",
+ options: array([
+ hive.name !== "user" && ["-group", hive.name],
+ ["-modes", uniqueModes(map.modes)],
+ ["-description", map.description],
+ map.silent && ["-silent"]])
+
+ .filter(util.identity)
+ .toObject(),
+ arguments: [map.names[0]],
+ literalArg: map.rhs,
+ ignoreDefaults: true
+ }
+ for (map in userMappings(hive))
+ if (map.persist)
+ ])
+ .flatten().array;
+ }
};
function userMappings(hive) {
let seen = {};
for (let stack in values(hive.stacks))
for (let map in array.iterValues(stack))
- if (!set.add(seen, map.id))
+ if (!Set.add(seen, map.id))
yield map;
}
dactyl.echoerr(_("map.noSuch", args[0]));
},
{
+ identifier: "unmap",
argCount: "?",
bang: true,
completer: opts.completer,
validator: function (value) Array.concat(value).every(findMode),
completer: function () [[array.compact([mode.name.toLowerCase().replace(/_/g, "-"), mode.char]), mode.description]
for (mode in values(modes.all))
- if (!mode.hidden)],
+ if (!mode.hidden)]
};
function findMode(name) {
function uniqueModes(modes) {
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));
+ return array.uniq(modes.filter(function (m) chars.indexOf(m.char) < 0)
+ .map(function (m) m.name.toLowerCase())
+ .concat(chars));
}
commands.add(["feedkeys", "fk"],
if (mode.char && !commands.get(mode.char + "map", true))
addMapCommands(mode.char,
[m.mask for (m in modes.mainModes) if (m.char == mode.char)],
- [mode.name.toLowerCase()]);
+ mode.displayName);
let args = {
getMode: function (args) findMode(args["-mode"]),
iterate: function (args, mainOnly) {
let modes = [this.getMode(args)];
if (!mainOnly)
- modes = modes.concat(modes[0].bases);
+ modes = modes[0].allBases;
let seen = {};
// Bloody hell. --Kris
for (let hive in mappings.hives.iterValues())
for (let map in array.iterValues(hive.getStack(mode)))
for (let name in values(map.names))
- if (!set.add(seen, name)) {
+ if (!Set.add(seen, name)) {
yield {
name: name,
columns: [
tags = services["dactyl:"].HELP_TAGS)
({ helpTag: prefix + map.name, __proto__: map }
for (map in self.iterate(args, true))
- if (map.hive === mappings.builtin || set.has(tags, prefix + map.name))),
- description: "List all " + mode.name + " mode mappings along with their short descriptions",
+ if (map.hive === mappings.builtin || Set.has(tags, prefix + map.name))),
+ description: "List all " + mode.displayName + " mode mappings along with their short descriptions",
index: mode.char + "-map",
getMode: function (args) mode,
options: []