diff --git a/keymap/vim.js b/keymap/vim.js
index 53003f6e355bd1e5acbe9cca094890aa0dcca857..d50cc4af459d9e797a34df0c87f33a2728178507 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -851,6 +851,8 @@
       mapCommand: mapCommand,
       _mapCommand: _mapCommand,
 
+      defineRegister: defineRegister,
+
       exitVisualMode: exitVisualMode,
       exitInsertMode: exitInsertMode
     };
@@ -940,6 +942,25 @@
       }
     };
 
+    /**
+     * Defines an external register.
+     *
+     * The name should be a single character that will be used to reference the register.
+     * The register should support setText, pushText, clear, and toString(). See Register
+     * for a reference implementation.
+     */
+    function defineRegister(name, register) {
+      var registers = vimGlobalState.registerController.registers[name];
+      if (!name || name.length != 1) {
+        throw Error('Register name must be 1 character');
+      }
+      if (registers[name]) {
+        throw Error('Register already defined ' + name);
+      }
+      registers[name] = register;
+      validRegisters.push(name);
+    }
+
     /*
      * vim registers allow you to keep many independent copy and paste buffers.
      * See http://usevim.com/2012/04/13/registers/ for an introduction.
@@ -4815,7 +4836,7 @@
       if (macroModeState.isPlaying) { return; }
       var registerName = macroModeState.latestRegister;
       var register = vimGlobalState.registerController.getRegister(registerName);
-      if (register) {
+      if (register && register.pushInsertModeChanges) {
         register.pushInsertModeChanges(macroModeState.lastInsertModeChanges);
       }
     }
@@ -4824,7 +4845,7 @@
       if (macroModeState.isPlaying) { return; }
       var registerName = macroModeState.latestRegister;
       var register = vimGlobalState.registerController.getRegister(registerName);
-      if (register) {
+      if (register && register.pushSearchQuery) {
         register.pushSearchQuery(query);
       }
     }