X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fcontent%2Fmappings.js;h=68bba94c6e9bed082211128e30069ddb5cf53b8e;hb=3d837eb266a3a01d424192aa4ec1a167366178c5;hp=155849e46fa73a6fb848beef87b9be44f2172129;hpb=70740024f9c028c1fd63e1a1850ab062ff956054;p=dactyl.git diff --git a/common/content/mappings.js b/common/content/mappings.js index 155849e..68bba94 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -1,6 +1,6 @@ // Copyright (c) 2006-2008 by Martin Stubenschrott // Copyright (c) 2007-2011 by Doug Kearns -// Copyright (c) 2008-2011 by Kris Maglione +// Copyright (c) 2008-2012 Kris Maglione // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. @@ -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,20 +119,23 @@ 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) + let repeat = () => this.action(args); if (this.names[0] != ".") // FIXME: Kludge. 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 +145,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 +295,7 @@ var MapHive = Class("MapHive", Contexts.Hive, { delete this.states; }, - states: Class.memoize(function () { + states: Class.Memoize(function () { var states = { candidates: {}, mappings: {} @@ -282,7 +305,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 +321,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(), @@ -306,9 +354,9 @@ var Mappings = Module("mappings", { get userHives() this.allHives.filter(function (h) h !== this.builtin, this), - expandLeader: function expandLeader(keyString) keyString.replace(//i, function () options["mapleader"]), + expandLeader: deprecated("your brain", function expandLeader(keyString) keyString), - 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) @@ -316,15 +364,18 @@ 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)); + 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 +445,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 +454,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 @@ -428,34 +479,30 @@ var Mappings = Module("mappings", { return maps; } - let list = - - - - - - - { - template.map(hives, function ([hive, maps]) let (i = 0) - + - template.map(maps, function (map) - template.map(map.names, function (name) - - - - - - )) + - ) - } -
- {_("title.Mode")}{_("title.Command")}{_("title.Action")}
{!i++ ? hive.name : ""}{modeSign}{name}{map.rhs || map.action.toSource()}
; - - // TODO: Move this to an ItemList to show this automatically - if (list.*.length() === list.text().length() + 2) - dactyl.echomsg(_("map.none")); - else - commandline.commandOutput(list); + let list = ["table", {}, + ["tr", { highlight: "Title" }, + ["td", {}], + ["td", { style: "padding-right: 1em;" }, _("title.Mode")], + ["td", { style: "padding-right: 1em;" }, _("title.Command")], + ["td", { style: "padding-right: 1em;" }, _("title.Action")]], + ["col", { style: "min-width: 6em; padding-right: 1em;" }], + hives.map(function ([hive, maps]) let (i = 0) [ + ["tr", { style: "height: .5ex;" }], + maps.map(function (map) + map.names.map(function (name) + ["tr", {}, + ["td", { highlight: "Title" }, !i++ ? hive.name : ""], + ["td", {}, modeSign], + ["td", {}, name], + ["td", {}, map.rhs || map.action.toSource()]])), + ["tr", { style: "height: .5ex;" }]])]; + + // E4X-FIXME + // // TODO: Move this to an ItemList to show this automatically + // if (list.*.length() === list.text().length() + 2) + // dactyl.echomsg(_("map.none")); + // else + commandline.commandOutput(list); } }, { }, { @@ -487,7 +534,7 @@ var Mappings = Module("mappings", { args["-builtin"] = true; if (!rhs) // list the mapping - mappings.list(mapmodes, mappings.expandLeader(lhs), hives); + mappings.list(mapmodes, lhs, hives); else { util.assert(args["-group"].modifiable, _("map.builtinImmutable")); @@ -524,7 +571,7 @@ var Mappings = Module("mappings", { options: [ { names: ["-arg", "-a"], - description: "Accept an argument after the requisite key press", + description: "Accept an argument after the requisite key press" }, { names: ["-builtin", "-b"], @@ -571,14 +618,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 @@ -606,7 +652,7 @@ var Mappings = Module("mappings", { commands.add([ch + "no[remap]"], "Map a key sequence without remapping keys" + modeDescription, function (args) { map(args, true); }, - update({}, opts)); + update({ deprecated: ":" + ch + "map -builtin" }, opts)); commands.add([ch + "unm[ap]"], "Remove a mapping" + modeDescription, @@ -710,25 +756,28 @@ var Mappings = Module("mappings", { yield { name: name, columns: [ - i === 0 ? "" : {mode.name}, - hive == mappings.builtin ? "" : {hive.name} + i === 0 ? "" : ["span", { highlight: "Object", style: "padding-right: 1em;" }, + mode.name], + hive == mappings.builtin ? "" : ["span", { highlight: "Object", style: "padding-right: 1em;" }, + hive.name] ], __proto__: map }; } }, format: { - description: function (map) (XML.ignoreWhitespace = false, XML.prettyPrinting = false, <> - {options.get("passkeys").has(map.name) - ? (passed by {template.helpLink("'passkeys'")}) - : <>} - {template.linkifyHelp(map.description + (map.rhs ? ": " + map.rhs : ""))} - ), + description: function (map) [ + options.get("passkeys").has(map.name) + ? ["span", { highlight: "URLExtra" }, + "(", template.linkifyHelp(_("option.passkeys.passedBy")), ")"] + : [], + template.linkifyHelp(map.description + (map.rhs ? ": " + map.rhs : "")) + ], help: function (map) let (char = array.compact(map.modes.map(function (m) m.char))[0]) char === "n" ? map.name : char ? char + "_" + map.name : "", headings: ["Command", "Mode", "Group", "Description"] } - } + }; dactyl.addUsageCommand({ __proto__: args, @@ -749,10 +798,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,25 +818,17 @@ 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]))] ]); }, - options: function initOptions(dactyl, modules, window) { - options.add(["mapleader", "ml"], - "Define the replacement keys for the pseudo-key", - "string", "\\", { - setter: function (value) { - if (this.hasChanged) - for (let hive in values(mappings.allHives)) - for (let stack in values(hive.stacks)) - delete stack.states; - return value; - } - }); + mappings: function initMappings(dactyl, modules, window) { + mappings.add([modes.COMMAND], + ["\\"], "Emits pseudo-key", + function () { events.feedkeys(""); }); } }); -// vim: set fdm=marker sw=4 ts=4 et: +// vim: set fdm=marker sw=4 sts=4 ts=8 et: