X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fcontent%2Fmappings.js;fp=common%2Fcontent%2Fmappings.js;h=149f3fb86c170e264d2b03435e6e57e03b59b1f3;hb=9044153cb63835e39b9de8ec4ade237c03e3888a;hp=155849e46fa73a6fb848beef87b9be44f2172129;hpb=70740024f9c028c1fd63e1a1850ab062ff956054;p=dactyl.git diff --git a/common/content/mappings.js b/common/content/mappings.js index 155849e..149f3fb 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -4,7 +4,7 @@ // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. -"use strict"; +/* use strict */ /** @scope modules */ @@ -17,7 +17,7 @@ * *action*. * @param {string} description A short one line description of the key mapping. * @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. * arg - see {@link Map#arg} * count - see {@link Map#count} @@ -29,7 +29,7 @@ * @private */ var Map = Class("Map", { - init: function (modes, keys, description, action, extraInfo) { + init: function (modes, keys, description, action, info) { this.id = ++Map.id; this.modes = modes; this._keys = keys; @@ -38,14 +38,17 @@ var Map = Class("Map", { Object.freeze(this.modes); - if (extraInfo) - this.update(extraInfo); + if (info) { + 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]), /** @property {[string]} All of this mapping's names (key sequences). */ - names: Class.memoize(function () this._keys.map(function (k) events.canonicalKeys(k))), + names: Class.Memoize(function () this._keys.map(function (k) DOM.Event.canonicalKeys(k))), get toStringParams() [this.modes.map(function (m) m.name), this.names.map(String.quote)], @@ -69,12 +72,24 @@ var Map = Class("Map", { * as an argument. */ motion: false, + /** @property {boolean} Whether the RHS of the mapping should expand mappings recursively. */ 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. */ silent: false, + /** @property {string} The literal RHS expansion of this mapping. */ rhs: null, + + /** @property {string} The type of this mapping. */ + type: "", + /** * @property {boolean} Specifies whether this is a user mapping. User * mappings may be created by plugins, or directly by users. Users and @@ -104,9 +119,9 @@ var Map = Class("Map", { .map(function ([i, prop]) [prop, this[i]], arguments) .toObject(); - args = update({ context: contexts.context }, - this.hive.argsExtra(args), - args); + args = this.hive.makeArgs(this.hive.group.lastDocument, + contexts.context, + args); let self = this; function repeat() self.action(args) @@ -114,10 +129,14 @@ var Map = Class("Map", { mappings.repeat = repeat; if (this.executing) - util.dumpStack(_("map.recursive", args.command)); - dactyl.assert(!this.executing, _("map.recursive", args.command)); + util.assert(!args.keypressEvents[0].isMacro, + _("map.recursive", args.command), + false); try { + dactyl.triggerObserver("mappings.willExecute", this, args); + mappings.pushCommand(); + this.preExecute(args); this.executing = true; var res = repeat(); } @@ -127,12 +146,17 @@ var Map = Class("Map", { } finally { this.executing = false; + mappings.popCommand(); + this.postExecute(args); + dactyl.triggerObserver("mappings.executed", this, args); } return res; } }, { - id: 0 + id: 0, + + types: {} }); var MapHive = Class("MapHive", Contexts.Hive, { @@ -272,7 +296,7 @@ var MapHive = Class("MapHive", Contexts.Hive, { delete this.states; }, - states: Class.memoize(function () { + states: Class.Memoize(function () { var states = { candidates: {}, mappings: {} @@ -282,7 +306,7 @@ var MapHive = Class("MapHive", Contexts.Hive, { for (let name in values(map.keys)) { states.mappings[name] = map; let state = ""; - for (let key in events.iterKeys(name)) { + for (let key in DOM.Event.iterKeys(name)) { state += key; if (state !== name) states.candidates[state] = (states.candidates[state] || 0) + 1; @@ -298,6 +322,31 @@ var MapHive = Class("MapHive", Contexts.Hive, { */ var Mappings = Module("mappings", { init: function () { + this.watches = []; + this._watchStack = 0; + this._yielders = 0; + }, + + afterCommands: function afterCommands(count, cmd, self) { + this.watches.push([cmd, self, Math.max(this._watchStack - 1, 0), count || 1]); + }, + + pushCommand: function pushCommand(cmd) { + this._watchStack++; + this._yielders = util.yielders; + }, + popCommand: function popCommand(cmd) { + this._watchStack = Math.max(this._watchStack - 1, 0); + if (util.yielders > this._yielders) + this._watchStack = 0; + + this.watches = this.watches.filter(function (elem) { + if (this._watchStack <= elem[2]) + elem[3]--; + if (elem[3] <= 0) + elem[0].call(elem[1] || null); + return elem[3] > 0; + }, this); }, repeat: Modes.boundProperty(), @@ -308,7 +357,7 @@ var Mappings = Module("mappings", { expandLeader: function expandLeader(keyString) keyString.replace(//i, function () options["mapleader"]), - prefixes: Class.memoize(function () { + prefixes: Class.Memoize(function () { let list = Array.map("CASM", function (s) s + "-"); return iter(util.range(0, 1 << list.length)).map(function (mask) @@ -317,14 +366,19 @@ var Mappings = Module("mappings", { expand: function expand(keys) { keys = keys.replace(//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)); + if (!/<\*-/.test(keys)) + var res = keys; + else + res = util.debrace(DOM.Event.iterKeys(keys).map(function (key) { + if (/^<\*-/.test(key)) + return ["<", this.prefixes, key.slice(3)]; + return key; + }, this).flatten().array).map(function (k) DOM.Event.canonicalKeys(k)); + + if (keys != arguments[0]) + return [arguments[0]].concat(keys); + return keys; }, iterate: function (mode) { @@ -394,7 +448,7 @@ var Mappings = Module("mappings", { get: function get(mode, cmd) this.hives.map(function (h) h.get(mode, cmd)).compact()[0] || null, /** - * Returns an array of maps with names starting with but not equal to + * Returns a count of maps with names starting with but not equal to * *prefix*. * * @param {Modes.Mode} mode The mode to search. @@ -403,7 +457,7 @@ var Mappings = Module("mappings", { */ getCandidates: function (mode, prefix) this.hives.map(function (h) h.getCandidates(mode, prefix)) - .flatten(), + .reduce(function (a, b) a + b, 0), /** * Lists all user-defined mappings matching *filter* for the specified @@ -571,14 +625,13 @@ var Mappings = Module("mappings", { .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(), + options: { + "-count": map.count ? null : undefined, + "-description": map.description, + "-group": hive.name == "user" ? undefined : hive.name, + "-modes": uniqueModes(map.modes), + "-silent": map.silent ? null : undefined + }, arguments: [map.names[0]], literalArg: map.rhs, ignoreDefaults: true @@ -749,10 +802,10 @@ var Mappings = Module("mappings", { name: [mode.char + "listk[eys]", mode.char + "lk"], iterateIndex: function (args) let (self = this, prefix = /^[bCmn]$/.test(mode.char) ? "" : mode.char + "_", - tags = services["dactyl:"].HELP_TAGS) + haveTag = Set.has(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))), + if (map.hive === mappings.builtin || haveTag(prefix + map.name))), description: "List all " + mode.displayName + " mode mappings along with their short descriptions", index: mode.char + "-map", getMode: function (args) mode, @@ -769,7 +822,7 @@ var Mappings = Module("mappings", { }; }, javascript: function initJavascript(dactyl, modules, window) { - JavaScript.setCompleter([mappings.get, mappings.builtin.get], + JavaScript.setCompleter([Mappings.prototype.get, MapHive.prototype.get], [ null, function (context, obj, args) [[m.names, m.description] for (m in this.iterate(args[0]))]