diff --git a/CHANGELOG.md b/CHANGELOG.md index d1e00dcd..212f6329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to the Keyboard Macro Bata extension will be documented in t - Added Visual Studio Keymap support. (See [Keymap Wrappers](keymap-wrapper/README.md)) [#24](https://github.com/tshino/vscode-kb-macro/pull/24) - Added emacs-style prefix-arguments support through the keymap wrapper for Awesome Emacs Keymap. (See [Keymap Wrappers](keymap-wrapper/README.md)) [#25](https://github.com/tshino/vscode-kb-macro/pull/25) - Added new `kb-macro.abortPlayback` command. [#26](https://github.com/tshino/vscode-kb-macro/pull/26) + - Added new `kb-macro.playing` 'when'-clause context, which evaluates true when the macro playback is ongoing. [#27](https://github.com/tshino/vscode-kb-macro/pull/27) - Update - (Internal) Added colors to warnings and errors on the console output of generator scripts. diff --git a/src/extension.js b/src/extension.js index 6daa0ac1..e297a84d 100644 --- a/src/extension.js +++ b/src/extension.js @@ -67,6 +67,17 @@ function activate(context) { } } ); + addEventListener( + keyboardMacro.onChangePlaybackState, + function({ playing, reason }) { + const contextName = ContextPrefix + 'playing'; + vscode.commands.executeCommand('setContext', contextName, playing); + + if (playing === false && reason === keyboardMacro.PlaybackStateReason.Abort) { + vscode.window.setStatusBarMessage('Playback aborted!', 3000); + } + } + ); addEventListener( helperContext.onChangeContext, function({ name, value }) { diff --git a/src/keyboard_macro.js b/src/keyboard_macro.js index 413849e2..7719716c 100644 --- a/src/keyboard_macro.js +++ b/src/keyboard_macro.js @@ -8,8 +8,14 @@ const KeyboardMacro = function({ awaitController }) { Cancel: 1, Finish: 2 }; + const PlaybackStateReason = { + Start: 0, + Abort: 1, + Finish: 2 + }; let onChangeRecordingStateCallback = null; + let onChangePlaybackStateCallback = null; let onBeginWrappedCommandCallback = null; let onEndWrappedCommandCallback = null; let recording = false; @@ -56,11 +62,21 @@ const KeyboardMacro = function({ awaitController }) { const onChangeRecordingState = function(callback) { onChangeRecordingStateCallback = callback; }; - const notifyNewState = function(reason) { + const changeRecordingState = function(newState, reason) { + recording = newState; if (onChangeRecordingStateCallback) { onChangeRecordingStateCallback({ recording, reason }); } }; + const onChangePlaybackState = function(callback) { + onChangePlaybackStateCallback = callback; + }; + const changePlaybackState = function(newState, reason) { + playing = newState; + if (onChangePlaybackStateCallback) { + onChangePlaybackStateCallback({ playing, reason }); + } + }; const onBeginWrappedCommand = function(callback) { onBeginWrappedCommandCallback = callback; }; @@ -75,22 +91,19 @@ const KeyboardMacro = function({ awaitController }) { const startRecording = makeGuardedCommandSync(function() { if (!recording) { sequence.clear(); - recording = true; - notifyNewState(RecordingStateReason.Start); + changeRecordingState(true, RecordingStateReason.Start); } }); const cancelRecording = makeGuardedCommandSync(function() { if (recording) { sequence.clear(); - recording = false; - notifyNewState(RecordingStateReason.Cancel); + changeRecordingState(false, RecordingStateReason.Cancel); } }); const finishRecording = makeGuardedCommandSync(function() { if (recording) { sequence.optimize(); - recording = false; - notifyNewState(RecordingStateReason.Finish); + changeRecordingState(false, RecordingStateReason.Finish); } }); @@ -128,7 +141,7 @@ const KeyboardMacro = function({ awaitController }) { const playback = makeGuardedCommand(async function(args) { if (!recording) { - playing = true; + changePlaybackState(true, PlaybackStateReason.Start); shouldAbortPlayback = false; args = (args && typeof(args) === 'object') ? args : {}; const repeat = typeof(args.repeat) === 'number' ? args.repeat : 1; @@ -144,8 +157,12 @@ const KeyboardMacro = function({ awaitController }) { } } }, function teardown() { - playing = false; - shouldAbortPlayback = false; + if (shouldAbortPlayback) { + changePlaybackState(false, PlaybackStateReason.Abort); + shouldAbortPlayback = false; + } else { + changePlaybackState(false, PlaybackStateReason.Finish); + } }); const abortPlayback = async function() { @@ -191,7 +208,9 @@ const KeyboardMacro = function({ awaitController }) { return { RecordingStateReason, + PlaybackStateReason, onChangeRecordingState, + onChangePlaybackState, onBeginWrappedCommand, onEndWrappedCommand, registerInternalCommand, diff --git a/test/suite/keyboard_macro.test.js b/test/suite/keyboard_macro.test.js index e21a004e..53c9dfd9 100644 --- a/test/suite/keyboard_macro.test.js +++ b/test/suite/keyboard_macro.test.js @@ -36,6 +36,36 @@ describe('KeybaordMacro', () => { ]); }); }); + describe('onChangePlaybackState', () => { + beforeEach(async () => { + keyboardMacro.cancelRecording(); + }); + it('should set callback function', async () => { + const logs = []; + keyboardMacro.onChangePlaybackState((event) => { + logs.push(event); + }); + keyboardMacro.registerInternalCommand('internal:delay', async () => { + await TestUtil.sleep(100); + }); + + keyboardMacro.startRecording(); + keyboardMacro.push({ command: 'internal:delay' }); + keyboardMacro.finishRecording(); + + await keyboardMacro.playback(); + const promise = keyboardMacro.playback(); + keyboardMacro.abortPlayback(); + await promise; + + assert.deepStrictEqual(logs, [ + { playing: true, reason: keyboardMacro.PlaybackStateReason.Start }, + { playing: false, reason: keyboardMacro.PlaybackStateReason.Finish }, + { playing: true, reason: keyboardMacro.PlaybackStateReason.Start }, + { playing: false, reason: keyboardMacro.PlaybackStateReason.Abort } + ]); + }); + }); describe('onBeginWrappedCommand, onEndWrappedCommand', () => { const logs = []; beforeEach(async () => {