@@ -108,6 +108,7 @@ const commandKeymapCompartment = new Compartment();
108108 * run: (view?: EditorView | null) => boolean | void;
109109 * requiresView?: boolean;
110110 * defaultDescription?: string;
111+ * defaultKey?: string | null;
111112 * key?: string | null;
112113 * }} CommandEntry
113114 */
@@ -118,6 +119,11 @@ const commandMap = new Map();
118119/** @type {Record<string, any> } */
119120let resolvedKeyBindings = keyBindings ;
120121
122+ /** @type {Record<string, any> } */
123+ let cachedResolvedKeyBindings = { } ;
124+
125+ let resolvedKeyBindingsVersion = 0 ;
126+
121127/** @type {import("@codemirror/view").KeyBinding[] } */
122128let cachedKeymap = [ ] ;
123129
@@ -1177,6 +1183,7 @@ function addCommand(entry) {
11771183 const command = {
11781184 ...entry ,
11791185 defaultDescription : entry . description || entry . name ,
1186+ defaultKey : entry . key ?? null ,
11801187 key : entry . key ?? null ,
11811188 } ;
11821189 commandMap . set ( entry . name , command ) ;
@@ -1314,6 +1321,39 @@ function parseKeyString(keyString) {
13141321 . filter ( Boolean ) ;
13151322}
13161323
1324+ function hasOwnBindingOverride ( name ) {
1325+ return Object . prototype . hasOwnProperty . call ( resolvedKeyBindings ?? { } , name ) ;
1326+ }
1327+
1328+ function resolveBindingInfo ( name ) {
1329+ const baseBinding = keyBindings [ name ] ?? null ;
1330+ if ( ! hasOwnBindingOverride ( name ) ) return baseBinding ;
1331+
1332+ const override = resolvedKeyBindings ?. [ name ] ;
1333+ if ( override === null ) {
1334+ return baseBinding ? { ...baseBinding , key : null } : { key : null } ;
1335+ }
1336+
1337+ if ( ! override || typeof override !== "object" ) {
1338+ return baseBinding ;
1339+ }
1340+
1341+ return baseBinding ? { ...baseBinding , ...override } : override ;
1342+ }
1343+
1344+ function buildResolvedKeyBindingsSnapshot ( ) {
1345+ const bindingNames = new Set ( [
1346+ ...Object . keys ( keyBindings ) ,
1347+ ...Object . keys ( resolvedKeyBindings ?? { } ) ,
1348+ ] ) ;
1349+
1350+ return Object . fromEntries (
1351+ Array . from ( bindingNames , ( name ) => [ name , resolveBindingInfo ( name ) ] ) . filter (
1352+ ( [ , binding ] ) => binding ,
1353+ ) ,
1354+ ) ;
1355+ }
1356+
13171357function toCodeMirrorKey ( combo ) {
13181358 if ( ! combo ) return null ;
13191359 const parts = combo
@@ -1355,11 +1395,15 @@ function toCodeMirrorKey(combo) {
13551395
13561396function rebuildKeymap ( ) {
13571397 const bindings = [ ] ;
1398+ cachedResolvedKeyBindings = buildResolvedKeyBindingsSnapshot ( ) ;
13581399 commandMap . forEach ( ( command , name ) => {
1359- const bindingInfo = resolvedKeyBindings ?. [ name ] ;
1400+ const bindingInfo = resolveBindingInfo ( name ) ;
13601401 command . description =
13611402 bindingInfo ?. description || command . defaultDescription ;
1362- const keySource = bindingInfo ?. key ?? command . key ?? null ;
1403+ const keySource =
1404+ bindingInfo && Object . prototype . hasOwnProperty . call ( bindingInfo , "key" )
1405+ ? bindingInfo . key
1406+ : ( command . defaultKey ?? null ) ;
13631407 command . key = keySource ;
13641408 const combos = parseKeyString ( keySource ) ;
13651409 combos . forEach ( ( combo ) => {
@@ -1373,6 +1417,7 @@ function rebuildKeymap() {
13731417 } ) ;
13741418 } ) ;
13751419 cachedKeymap = bindings ;
1420+ resolvedKeyBindingsVersion += 1 ;
13761421 return bindings ;
13771422}
13781423
@@ -1410,6 +1455,14 @@ export function getRegisteredCommands() {
14101455 } ) ) ;
14111456}
14121457
1458+ export function getResolvedKeyBindings ( ) {
1459+ return cachedResolvedKeyBindings ;
1460+ }
1461+
1462+ export function getResolvedKeyBindingsVersion ( ) {
1463+ return resolvedKeyBindingsVersion ;
1464+ }
1465+
14131466export function getCommandKeymapExtension ( ) {
14141467 return commandKeymapCompartment . of ( keymap . of ( cachedKeymap ) ) ;
14151468}
0 commit comments