@@ -80,25 +80,32 @@ define(function (require, exports, module) {
8080 * Maps commandID to the list of shortcuts that are bound to it.
8181 * @type {!Object.<string, Array.<{key: string, displayKey: string}>> }
8282 */
83- var _commandMap = { } ,
84- _allCommands = [ ] ;
83+ var _commandMap = { } ;
84+
85+ /**
86+ * @private
87+ * An array of command ID for all the available commands including the commands
88+ * of installed extensions.
89+ * @type {Array.<string> }
90+ */
91+ var _allCommands = [ ] ;
8592
8693 /**
8794 * @private
8895 * Maps key names to the corresponding unicode symols
8996 * @type {{key: string, displayKey: string} }
9097 */
91- var _displayKeyMap = { "up" : "\u2191" ,
92- "down" : "\u2193" ,
93- "left" : "\u2190" ,
94- "right" : "\u2192" ,
95- "-" : "\u2212" } ;
98+ var _displayKeyMap = { "up" : "\u2191" ,
99+ "down" : "\u2193" ,
100+ "left" : "\u2190" ,
101+ "right" : "\u2192" ,
102+ "-" : "\u2212" } ;
96103
97- var _specialCommands = [ Commands . EDIT_UNDO , Commands . EDIT_REDO , Commands . EDIT_SELECT_ALL ,
98- Commands . EDIT_CUT , Commands . EDIT_COPY , Commands . EDIT_PASTE ] ,
99- _reservedShortcuts = [ "Ctrl-Z" , "Ctrl-Y" , "Ctrl-A" , "Ctrl-X" , "Ctrl-C" , "Ctrl-V" ] ,
104+ var _specialCommands = [ Commands . EDIT_UNDO , Commands . EDIT_REDO , Commands . EDIT_SELECT_ALL ,
105+ Commands . EDIT_CUT , Commands . EDIT_COPY , Commands . EDIT_PASTE ] ,
106+ _reservedShortcuts = [ "Ctrl-Z" , "Ctrl-Y" , "Ctrl-A" , "Ctrl-X" , "Ctrl-C" , "Ctrl-V" ] ,
100107 _macReservedShortcuts = [ "Cmd-," , "Cmd-H" , "Cmd-Alt-H" , "Cmd-M" , "Cmd-Shift-Z" , "Cmd-Q" ] ,
101- _keyNames = [ "Up" , "Down" , "Left" , "Right" , "Backspace" , "Enter" , "Space" , "Tab" ] ;
108+ _keyNames = [ "Up" , "Down" , "Left" , "Right" , "Backspace" , "Enter" , "Space" , "Tab" ] ;
102109
103110 /**
104111 * @private
@@ -124,6 +131,13 @@ define(function (require, exports, module) {
124131 * @type {Array.<function(Event): boolean> }
125132 */
126133 var _globalKeydownHooks = [ ] ;
134+
135+ /**
136+ * @private
137+ * Forward declaration for JSLint.
138+ * @type {Function }
139+ */
140+ var _loadUserKeyMap ;
127141
128142 /**
129143 * @private
@@ -429,6 +443,29 @@ define(function (require, exports, module) {
429443 }
430444 }
431445
446+ /**
447+ * @private
448+ *
449+ * Updates _allCommands array and _defaultKeyMap with the new key binding
450+ * if it is not yet in the _allCommands array. _allCommands array is initialized
451+ * only in extensionsLoaded event. So any new commands or key bindings added after
452+ * that will be updated here.
453+ *
454+ * @param {{commandID: string, key: string, displayKey:string, explicitPlatform: string} } newBinding
455+ */
456+ function _updateCommandAndKeyMaps ( newBinding ) {
457+ if ( _allCommands . length === 0 ) {
458+ return ;
459+ }
460+
461+ if ( newBinding && newBinding . commandID && _allCommands . indexOf ( newBinding . commandID ) === - 1 ) {
462+ _defaultKeyMap [ newBinding . commandID ] = _ . cloneDeep ( newBinding ) ;
463+
464+ // Process user key map again to catch any reassignment to all new key bindings added from extensions.
465+ _loadUserKeyMap ( ) ;
466+ }
467+ }
468+
432469 /**
433470 * @private
434471 *
@@ -437,11 +474,12 @@ define(function (require, exports, module) {
437474 * @param {?string } platform
438475 * - "all" indicates all platforms, not overridable
439476 * - undefined indicates all platforms, overridden by platform-specific binding
477+ * @param {boolean= } userBindings true if adding a user key binding or undefined otherwise.
440478 * @return {?{key: string, displayKey:String} } Returns a record for valid key bindings.
441479 * Returns null when key binding platform does not match, binding does not normalize,
442480 * or is already assigned.
443481 */
444- function _addBinding ( commandID , keyBinding , platform ) {
482+ function _addBinding ( commandID , keyBinding , platform , userBindings ) {
445483 var key ,
446484 result = null ,
447485 normalized ,
@@ -585,6 +623,10 @@ define(function (require, exports, module) {
585623 explicitPlatform : explicitPlatform
586624 } ;
587625
626+ if ( ! userBindings ) {
627+ _updateCommandAndKeyMaps ( _keyMap [ normalized ] ) ;
628+ }
629+
588630 // notify listeners
589631 command = CommandManager . get ( commandID ) ;
590632
@@ -1007,7 +1049,7 @@ define(function (require, exports, module) {
10071049 var keybinding = { key : normalizedKey } ;
10081050
10091051 keybinding . displayKey = _getDisplayKey ( normalizedKey ) ;
1010- addBinding ( commandID , keybinding . displayKey ? keybinding : normalizedKey , brackets . platform ) ;
1052+ _addBinding ( commandID , keybinding . displayKey ? keybinding : normalizedKey , brackets . platform , true ) ;
10111053 remappedCommands . push ( commandID ) ;
10121054 } else {
10131055 multipleKeys . push ( commandID ) ;
@@ -1158,18 +1200,27 @@ define(function (require, exports, module) {
11581200 * binding by removing the existing one assigned to each key and adding
11591201 * new one for the specified command id. Shows errors and opens the user
11601202 * key map file if it cannot be parsed.
1203+ *
1204+ * This function is wrapped with debounce so that its execution is always delayed
1205+ * by 200 ms. The delay is required because when this function is called some
1206+ * extensions may still be adding some commands and their key bindings asychronously.
11611207 */
1162- function _loadUserKeyMap ( ) {
1208+ _loadUserKeyMap = _ . debounce ( function ( ) {
11631209 _readUserKeyMap ( )
11641210 . then ( function ( keyMap ) {
1211+ // Some extensions may add a new command without any key binding. So
1212+ // we always have to get all commands again to ensure that we also have
1213+ // those from any extensions installed during the current session.
1214+ _allCommands = CommandManager . getAll ( ) ;
1215+
11651216 _customKeyMapCache = _ . cloneDeep ( _customKeyMap ) ;
11661217 _customKeyMap = keyMap ;
11671218 _undoPriorUserKeyBindings ( ) ;
11681219 _applyUserKeyBindings ( ) ;
11691220 } , function ( err ) {
11701221 _showErrorsAndOpenKeyMap ( err ) ;
11711222 } ) ;
1172- }
1223+ } , 200 ) ;
11731224
11741225 /**
11751226 * @private
@@ -1214,8 +1265,6 @@ define(function (require, exports, module) {
12141265 *
12151266 * Initializes _allCommands array and _defaultKeyMap so that we can use them for
12161267 * detecting non-existent commands and restoring the original key binding.
1217- *
1218- * @param {string } fullPath file path to the user key map file.
12191268 */
12201269 function _initCommandAndKeyMaps ( ) {
12211270 _allCommands = CommandManager . getAll ( ) ;
@@ -1241,7 +1290,7 @@ define(function (require, exports, module) {
12411290 if ( params . get ( "reloadWithoutUserExts" ) === "true" ) {
12421291 _showErrors = false ;
12431292 }
1244-
1293+
12451294 _initCommandAndKeyMaps ( ) ;
12461295 _loadUserKeyMap ( ) ;
12471296 } ) ;
0 commit comments