Skip to content

Commit 1760f2e

Browse files
committed
feat: custom shortcut preset registration infra for eg. vscode shortcuts
1 parent e23e9c1 commit 1760f2e

File tree

10 files changed

+304
-51
lines changed

10 files changed

+304
-51
lines changed

src/brackets.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ define(function (require, exports, module) {
115115
* Global notification UI Widgets.
116116
*/
117117
window.NotificationUI = NotificationUI;
118+
Phoenix.globalAPI.NotificationUI = NotificationUI;
119+
Phoenix.globalAPI.PreferencesManager = PreferencesManager;
118120

119121
// load modules for later use
120122
require("utils/Global");

src/command/KeyBindingManager.js

Lines changed: 173 additions & 25 deletions
Large diffs are not rendered by default.

src/command/Menus.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ define(function (require, exports, module) {
4444
require("utils/Global");
4545

4646
const KEY = Keys.KEY;
47+
const allMenuCommands = new Set();
4748
/**
4849
* Brackets Application Menu Constants
4950
* @enum {string}
@@ -171,6 +172,14 @@ define(function (require, exports, module) {
171172
return menuMap[id];
172173
}
173174

175+
/**
176+
* retruns a set containing all commands that has a menu item registered
177+
* @returns {Set<string>}
178+
*/
179+
function getAllMenuItemCommands() {
180+
return new Set(allMenuCommands);
181+
}
182+
174183
/**
175184
* Retrieves the map of all Menu objects.
176185
* @return {Object.<string, Menu>}
@@ -573,10 +582,16 @@ define(function (require, exports, module) {
573582
return null;
574583
}
575584
name = command.getName();
585+
if(!allMenuCommands.has(commandID)){
586+
allMenuCommands.add(commandID);
587+
}
576588
}
577589
} else {
578590
commandID = command.getID();
579591
name = command.getName();
592+
if(!allMenuCommands.has(commandID)){
593+
allMenuCommands.add(commandID);
594+
}
580595
}
581596

582597
// Internal id is the a composite of the parent menu id and the command id.
@@ -1647,6 +1662,7 @@ define(function (require, exports, module) {
16471662
exports.getOpenMenu = getOpenMenu;
16481663
exports.registerContextMenu = registerContextMenu;
16491664
exports.closeAll = closeAll;
1665+
exports.getAllMenuItemCommands = getAllMenuItemCommands;
16501666
exports.Menu = Menu;
16511667
exports.MenuItem = MenuItem;
16521668
exports.ContextMenu = ContextMenu;

src/extensionsIntegrated/DisplayShortcuts/main.js

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ define(function (require, exports, module) {
3939
Metrics = require("utils/Metrics"),
4040
WorkspaceManager = require("view/WorkspaceManager"),
4141
AppInit = require("utils/AppInit"),
42+
DropdownButton = require("widgets/DropdownButton").DropdownButton,
4243
Strings = require("strings");
4344

45+
require("./vscode.js");
46+
4447
const panelHtml = require("text!./templates/bottom-panel.html"),
4548
shortcutsHtml = require("text!./templates/shortcut-table.html"),
4649
TOGGLE_SHORTCUTS_ID = Commands.HELP_TOGGLE_SHORTCUTS_PANEL;
@@ -49,6 +52,7 @@ define(function (require, exports, module) {
4952
$shortcutsPanel,
5053
$filterField,
5154
currentFilter,
55+
presetPicker,
5256
_updateKeyBindings;
5357

5458
let sortByBase = 1,
@@ -102,11 +106,15 @@ define(function (require, exports, module) {
102106
return string;
103107
}
104108

105-
function _getOriginFromCommandId(cmdID) {
109+
function _getOriginFromCommandId(cmdID, keyBinding) {
106110
// According to CommandManager.register() documentation:
107111
// Core commands in Brackets use a simple command title as an id, for example "open.file".
108112
// Extensions should use the following format: "author.myextension.mycommandname".
109113
// For example, "lschmitt.csswizard.format.css".
114+
const customOrigin = KeyBindingManager.getCustomShortcutOrigin(keyBinding);
115+
if(customOrigin){
116+
return customOrigin;
117+
}
110118
let idArray = cmdID.split(".");
111119
const defaultCommands = Object.values(Commands);
112120

@@ -138,36 +146,39 @@ define(function (require, exports, module) {
138146
// CodeMirror and Brackets key maps have different formats, so collect
139147
// keys into a normalized array
140148
function _getkeyList() {
141-
let i,
149+
let keyBinding,
142150
base,
143151
command,
144152
key;
153+
const allCommandsWithShortcuts = new Set();
154+
const menuCommands = Menus.getAllMenuItemCommands();
155+
const knownBindableCommands = KeyBindingManager._getKnownBindableCommands();
156+
const allCommandsToList = new Set([...menuCommands, ...knownBindableCommands]);
145157

146158
// Brackets keymap
147159
let bracketsKeymap = KeyBindingManager.getKeymap();
148160
if (bracketsKeymap) {
149-
for (i in bracketsKeymap) {
150-
if (bracketsKeymap.hasOwnProperty(i)) {
151-
key = bracketsKeymap[i];
161+
for (keyBinding in bracketsKeymap) {
162+
if (bracketsKeymap.hasOwnProperty(keyBinding)) {
163+
key = bracketsKeymap[keyBinding];
152164
if (key) {
153-
base = _getBaseKey(i);
165+
base = _getBaseKey(keyBinding);
154166
command = CommandManager.get(key.commandID);
155167
if (!command) {
156168
continue;
157169
}
158170

159-
// Listen for keybinding changes
160-
command.on("keyBindingAdded.bds keyBindingRemoved.bds", _updateKeyBindings);
161-
171+
allCommandsWithShortcuts.add(key.commandID);
162172
keyList.push({
163173
keyBase: KeyBindingManager.formatKeyDescriptor(base),
164-
keyBinding: i,
165-
keyBindingDisplay: KeyBindingManager.formatKeyDescriptor(i),
174+
keyBinding: keyBinding,
175+
keyBindingDisplay: KeyBindingManager.formatKeyDescriptor(keyBinding),
166176
command: command,
167177
commandID: key.commandID,
168178
commandName: command.getName(),
169-
origin: _getOriginFromCommandId(key.commandID),
170-
filter: command.getName().toLowerCase() + _filterFromKeyBinding(i)
179+
origin: _getOriginFromCommandId(key.commandID, keyBinding),
180+
filter: command.getName().toLowerCase() + _filterFromKeyBinding(keyBinding)
181+
+ _getOriginFromCommandId(key.commandID, keyBinding).toLowerCase()
171182
});
172183
}
173184
}
@@ -178,27 +189,44 @@ define(function (require, exports, module) {
178189
if (CodeMirror.keyMap) {
179190
let cmKeymap = (brackets.platform === "mac") ? CodeMirror.keyMap.macDefault : CodeMirror.keyMap.pcDefault;
180191
if (cmKeymap) {
181-
for (i in cmKeymap) {
192+
for (keyBinding in cmKeymap) {
182193
// Note that we only ignore CodeMirror duplicates, but
183194
// we want to see Brackets & Extensions duplicates
184-
if (cmKeymap.hasOwnProperty(i) &&
185-
(i !== "fallthrough") &&
186-
(_findKeyBinding(keyList, i) === -1)) {
187-
base = _getBaseKey(i);
195+
if (cmKeymap.hasOwnProperty(keyBinding) &&
196+
(keyBinding !== "fallthrough") &&
197+
(_findKeyBinding(keyList, keyBinding) === -1)) {
198+
base = _getBaseKey(keyBinding);
199+
allCommandsWithShortcuts.add(cmKeymap[keyBinding]);
188200
keyList.push({
189201
keyBase: KeyBindingManager.formatKeyDescriptor(base),
190-
keyBinding: i,
191-
keyBindingDisplay: KeyBindingManager.formatKeyDescriptor(i),
192-
commandID: cmKeymap[i],
193-
commandName: cmKeymap[i],
194-
origin: origCodeMirror,
195-
filter: cmKeymap[i].toLowerCase() + _filterFromKeyBinding(i)
202+
keyBinding: keyBinding,
203+
keyBindingDisplay: KeyBindingManager.formatKeyDescriptor(keyBinding),
204+
commandID: cmKeymap[keyBinding],
205+
commandName: cmKeymap[keyBinding],
206+
origin: window.debugMode ? origCodeMirror : origBrackets,
207+
filter: cmKeymap[keyBinding].toLowerCase() + _filterFromKeyBinding(keyBinding) +
208+
origCodeMirror.toLowerCase()
196209
});
197210
}
198211
}
199212
}
200213
}
201-
214+
215+
for(let commandID of allCommandsToList){
216+
if(allCommandsWithShortcuts.has(commandID)){
217+
continue;
218+
}
219+
keyList.push({
220+
keyBase: "",
221+
keyBinding: "",
222+
keyBindingDisplay: "",
223+
commandID: commandID,
224+
commandName: commandID,
225+
origin: _getOriginFromCommandId(commandID, keyBinding),
226+
filter: commandID.toLowerCase() + _getOriginFromCommandId(commandID, keyBinding).toLowerCase()
227+
});
228+
}
229+
202230
return keyList;
203231
}
204232

@@ -402,6 +430,15 @@ define(function (require, exports, module) {
402430
}
403431
}
404432

433+
function _presetRenderer(item) {
434+
var html = "<span class='stylesheet-name'>" + _.escape(item.name);
435+
if (item.subDirStr) {
436+
html += "<span class='stylesheet-dir'> — " + _.escape(item.subDirStr) + "</span>";
437+
}
438+
html += "</span>";
439+
return html;
440+
}
441+
405442
AppInit.appReady(function() {
406443
let s, file_menu;
407444

@@ -424,6 +461,11 @@ define(function (require, exports, module) {
424461

425462
$shortcutsPanel = $("#shortcuts-panel");
426463

464+
presetPicker = new DropdownButton("Select Shortcut Presets", [], _presetRenderer, {
465+
cssClasses: "presetPicker"
466+
});
467+
$shortcutsPanel.find(".presetPickerContainer").append(presetPicker.$button);
468+
427469
// Events
428470
$shortcutsPanel.on("dblclick", function (e) {
429471
var $rowEl = $(e.target).closest("tr");
@@ -466,5 +508,7 @@ define(function (require, exports, module) {
466508
}
467509
_showCommandIdsInPanelIfNeeded();
468510
});
511+
KeyBindingManager.on(KeyBindingManager.EVENT_KEY_BINDING_ADDED, _updateKeyBindings);
512+
KeyBindingManager.on(KeyBindingManager.EVENT_KEY_BINDING_REMOVED, _updateKeyBindings);
469513
});
470514
});

src/extensionsIntegrated/DisplayShortcuts/templates/bottom-panel.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<a href="#" class="close">&times;</a>
55
<button class="btn reset-to-default" title="{{KEYBOARD_SHORTCUT_PANEL_RESET_DEFAULT}}">{{{KEYBOARD_SHORTCUT_PANEL_RESET}}}</button>
66
<input class="filter" type="search" placeholder="{{{KEYBOARD_SHORTCUT_PANEL_FILTER}}}">
7+
<span class="presetPickerContainer" title="{{KEYBOARD_SHORTCUT_PRESET_TOOLTIP}}"></span>
78
</div>
89
<div class="resizable-content"></div>
910
</div>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* GNU AGPL-3.0 License
3+
*
4+
* Copyright (c) 2021 - present core.ai . All rights reserved.
5+
* Original work Copyright (c) 2018 - 2021 Adobe Systems Incorporated. All rights reserved.
6+
*
7+
* This program is free software: you can redistribute it and/or modify it
8+
* under the terms of the GNU Affero General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
15+
* for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public License
18+
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
19+
*
20+
*/
21+
22+
define(function (require, exports, module) {
23+
const KeyBindingManager = require("command/KeyBindingManager"),
24+
vscodeKeyMap = JSON.parse(require("text!./vscode.json"));
25+
26+
const VSCODE_PACK_ID = "vscode";
27+
28+
KeyBindingManager.registerCustomKeymapPack(VSCODE_PACK_ID, "Visual Studio Code", vscodeKeyMap);
29+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{
2+
}

src/nls/root/strings.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,11 +370,14 @@ define({
370370
"KEYBOARD_SHORTCUT_ORIG_EXTENSION": "Extension",
371371
//Bottom panel
372372
"KEYBOARD_SHORTCUT_PANEL_TITLE": "Keyboard Shortcuts",
373+
"KEYBOARD_SHORTCUT_PRESET_TOOLTIP": "Use keyboard shortcuts from editors like VSCode, WebStorm, or Sublime Text",
373374
"KEYBOARD_SHORTCUT_PANEL_FILTER": "Filter&hellip;",
374375
"KEYBOARD_SHORTCUT_PANEL_RESET": "Reset\u2026",
375376
"KEYBOARD_SHORTCUT_PANEL_RESET_DEFAULT": "Reset To Default Shortcuts\u2026",
376377
"KEYBOARD_SHORTCUT_RESET_DIALOG_TITLE": "Reset Keyboard Shortcuts",
377378
"KEYBOARD_SHORTCUT_RESET_DIALOG_MESSAGE": "Reset all custom shortcuts to default? This cannot be undone.",
379+
"KEYBOARD_SHORTCUT_SRC_USER": "User Defined",
380+
"KEYBOARD_SHORTCUT_SRC_PRESET": "{0} Preset",
378381

379382
/**
380383
* StatusBar strings

src/phoenix/shell.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ Phoenix.libs = {
103103
picomatch: fs.utils.picomatch
104104
};
105105

106+
// global API is only usable/stable after App init
107+
Phoenix.globalAPI = {};
108+
106109
Phoenix.app = {
107110
getNodeState: function (cbfn){
108111
cbfn(new Error('Node cannot be run in phoenix browser mode'));

src/styles/Extn-DisplayShortcuts.less

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
overflow-y: scroll;
2929
}
3030

31+
#phoenix-keyboard-shortcuts-table {
32+
margin-bottom: 50px;
33+
}
34+
3135
#shortcuts-panel table td {
3236
line-height: 14px;
3337
padding: 4px 10px;
@@ -107,9 +111,10 @@
107111
}
108112

109113
#shortcuts-panel .toolbar button.reset-to-default,
114+
#shortcuts-panel .toolbar button.presetPicker,
110115
#shortcuts-panel .toolbar .filter {
111116
float: right;
112-
margin: -2px 10px;
117+
margin: 4px 10px;
113118
padding-top: 2px;
114119
padding-bottom: 2px;
115120
}

0 commit comments

Comments
 (0)