diff --git a/generator/gen_keymap_wrapper.js b/generator/gen_keymap_wrapper.js index e5bf1cba..302cb3ad 100644 --- a/generator/gen_keymap_wrapper.js +++ b/generator/gen_keymap_wrapper.js @@ -78,6 +78,9 @@ async function makeKeymapWrapper(configPath, commonConfig) { } genWrapperUtil.checkAwaitOptions(awaitOptions); + const recordOptions = new Map(commonConfig['recordOptions'] || []); + genWrapperUtil.checkRecordOptions(recordOptions); + const wrappers = baseKeybindings.filter( keybinding => !ignore.has(keybinding.command) ).flatMap( @@ -91,7 +94,8 @@ async function makeKeymapWrapper(configPath, commonConfig) { } else { // make a wrapper keybinding (indirect call) to enable recording of the command const awaitOption = awaitOptions.get(keybinding.command) || ''; - const wrappers = genWrapperUtil.makeWrapper(keybinding, awaitOption); + const recordOption = recordOptions.get(keybinding.command); + const wrappers = genWrapperUtil.makeWrapper(keybinding, awaitOption, recordOption); return wrappers; } } diff --git a/generator/gen_wrapper.js b/generator/gen_wrapper.js index fdcea246..926048c7 100644 --- a/generator/gen_wrapper.js +++ b/generator/gen_wrapper.js @@ -22,6 +22,8 @@ async function main() { const exclusion = new Set(config['exclusion'] || []); const awaitOptions = new Map(config['awaitOptions'] || []); genWrapperUtil.checkAwaitOptions(awaitOptions); + const recordOptions = new Map(config['recordOptions'] || []); + genWrapperUtil.checkRecordOptions(recordOptions); const baseKeybindings = await defaultKeybindingsLoader.loadBaseKeybindings(config['baseKeybindings'] || []); const commands = new Set(baseKeybindings.flatMap(item => item.keybindings).map(keybinding => keybinding.command)); @@ -39,7 +41,8 @@ async function main() { } else { // make a wrapper keybinding (indirect call) to enable recording of the command const awaitOption = awaitOptions.get(keybinding.command) || ''; - const wrappers = genWrapperUtil.makeWrapper(keybinding, awaitOption); + const recordOption = recordOptions.get(keybinding.command); + const wrappers = genWrapperUtil.makeWrapper(keybinding, awaitOption, recordOption); return wrappers; } } diff --git a/generator/gen_wrapper_util.js b/generator/gen_wrapper_util.js index 645b9223..66d566f0 100644 --- a/generator/gen_wrapper_util.js +++ b/generator/gen_wrapper_util.js @@ -175,10 +175,27 @@ function isValidAwaitOption(awaitOption) { ); } +function isValidRecordOption(recordOption) { + if (typeof recordOption !== 'string') { + return false; + } + return ( + recordOption === 'command' || recordOption === 'side-effect' + ); +} + function checkAwaitOptions(awaitOptions) { for (const awaitOption of awaitOptions.values()) { if (!isValidAwaitOption(awaitOption)) { - throw `Invalid awaitOption found: ${JSON.stringify(awaitOption)}`; + throw `Invalid await option found: ${JSON.stringify(awaitOption)}`; + } + } +} + +function checkRecordOptions(recordOptions) { + for (const recordOption of recordOptions.values()) { + if (!isValidRecordOption(recordOption)) { + throw `Invalid record option found: ${JSON.stringify(recordOption)}`; } } } @@ -240,7 +257,7 @@ function makeWrapperWhen(keybinding) { return addWhenContext(keybinding.when, 'kb-macro.recording'); } -function makeWrapper(keybinding, awaitOption) { +function makeWrapper(keybinding, awaitOption, recordOption = '') { const awaitList = decomposeAwaitOption(awaitOption); const wrappers = awaitList.map(awaitItem => { const when = addWhenContext(keybinding.when, awaitItem.context); @@ -257,6 +274,9 @@ function makeWrapper(keybinding, awaitOption) { if (awaitItem['await']) { wrapped.args['await'] = awaitItem['await']; } + if (recordOption) { + wrapped.args['record'] = recordOption; + } return wrapped; }); return wrappers; @@ -276,7 +296,9 @@ module.exports = { keybindingsContains, extractOSSpecificKeys, isValidAwaitOption, + isValidRecordOption, checkAwaitOptions, + checkRecordOptions, parseAwaitOption, decomposeAwaitOption, makeWrapperWhen, diff --git a/generator/verify_wrapper.js b/generator/verify_wrapper.js index 4caacec6..91ff3d86 100644 --- a/generator/verify_wrapper.js +++ b/generator/verify_wrapper.js @@ -183,6 +183,7 @@ async function verifyWrapper() { const exclusion = new Set(config['exclusion'] || []); const awaitOptions = new Map(config['awaitOptions'] || []); + const recordOptions = new Map(config['recordOptions'] || []); const baseKeybindings = await defaultKeybindingsLoader.loadBaseKeybindings(config['baseKeybindings'] || []); @@ -272,6 +273,19 @@ async function verifyWrapper() { 'a command that is not included in the awaitOptions list should not have await option' ); } + if (recordOptions.has(wrapper.args.command)) { + assert.deepStrictEqual( + wrapper.args.record, + recordOptions.get(wrapper.args.command), + 'a command included in the recordOptions list should have the record option specified in the list' + ); + } else { + assert.strictEqual( + 'record' in wrapper.args, + false, + 'a command that is not included in the recordOptions list should not have record option' + ); + } } else { assert.strictEqual( exclusion.has(wrapper.command), diff --git a/test/suite/gen_wrapper_util.test.js b/test/suite/gen_wrapper_util.test.js index 68739a23..e8226765 100644 --- a/test/suite/gen_wrapper_util.test.js +++ b/test/suite/gen_wrapper_util.test.js @@ -228,6 +228,22 @@ describe('gen_wrapper_util', () => { assert.strictEqual(isValidAwaitOption('[condition]document selection'), true); }); }); + describe('isValidRecordOption', () => { + const isValidRecordOption = genWrapperUtil.isValidRecordOption; + it('should return true if passed string is a valid record option for a wrapper', () => { + assert.strictEqual(isValidRecordOption('side-effect'), true); + assert.strictEqual(isValidRecordOption('command'), true); + }); + it('should return false on string with invalid record target', () => { + assert.strictEqual(isValidRecordOption('hello'), false); + assert.strictEqual(isValidRecordOption(''), false); + }); + it('should return false on any value of types other than string', () => { + assert.strictEqual(isValidRecordOption(null), false); + assert.strictEqual(isValidRecordOption(), false); + assert.strictEqual(isValidRecordOption([]), false); + }); + }); describe('checkAwaitOptions', () => { const checkAwaitOptions = genWrapperUtil.checkAwaitOptions; it('should not throw if all the values in the map are valid await option', () => { @@ -249,7 +265,33 @@ describe('gen_wrapper_util', () => { ])); }, err => { - assert.strictEqual(err, 'Invalid awaitOption found: "123"'); + assert.strictEqual(err, 'Invalid await option found: "123"'); + return true; + } + ); + }); + }); + describe('checkRecordOptions', () => { + const checkRecordOptions = genWrapperUtil.checkRecordOptions; + it('should not throw if all the values in the map are valid record option', () => { + assert.doesNotThrow( + () => { + checkRecordOptions(new Map([ + [ 'command1', 'command' ], + [ 'command2', 'side-effect' ] + ])); + } + ); + }); + it('should throw if the map contains invalid record option', () => { + assert.throws( + () => { + checkRecordOptions(new Map([ + [ 'command1', '123' ] + ])); + }, + err => { + assert.strictEqual(err, 'Invalid record option found: "123"'); return true; } ); @@ -474,5 +516,24 @@ describe('gen_wrapper_util', () => { ]; assert.deepStrictEqual(makeWrapper(input, awaitOption), expected); }); + it('should make wrapper keybinding (8) (with recordOption)', () => { + const input = { + key: 'key1', + command: 'command1', + when: 'context1' + }; + const awaitOption = ''; + const recordOption = 'side-effect'; + const expected = [ { + key: 'key1', + command: 'kb-macro.wrap', + args: { + command: 'command1', + record: 'side-effect' + }, + when: 'kb-macro.recording && context1' + } ]; + assert.deepStrictEqual(makeWrapper(input, awaitOption, recordOption), expected); + }); }); });