]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/content/mappings.js
Import 1.0rc1 supporting Firefox up to 11.*
[dactyl.git] / common / content / mappings.js
index 155849e46fa73a6fb848beef87b9be44f2172129..149f3fb86c170e264d2b03435e6e57e03b59b1f3 100644 (file)
@@ -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(/<Leader>/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(/<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));
+        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]))]