Skip to content

Commit

Permalink
Merge pull request #195 from tshino/playback-optimize
Browse files Browse the repository at this point in the history
Optimize input sequence in playback command
  • Loading branch information
tshino authored Jan 13, 2023
2 parents 369d440 + 7a30cd6 commit 3297c2f
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
All notable changes to the Keyboard Macro Bata extension will be documented in this file.

### [Unreleased]
- Feature:
- Added optimization of the input sequence to the playback command. [#195](https://github.com/tshino/vscode-kb-macro/pull/195)
- This optimization can improve playback performance, especially in a sequence containing a long typing.
- Update
- Changed the activatation context of wrapper keybindings from `kb-macro.recording` to `kb-macro.active`. [#133](https://github.com/tshino/vscode-kb-macro/issues/133)
- This change does not require any actions for existing users unless they want to use the extra feature Background Recording API.
Expand Down
10 changes: 7 additions & 3 deletions src/command_sequence.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ const CommandSequence = function({ maxLength = null } = {}) {
groupSize1 === 1 &&
characterDelta1 < 0 &&
characterDelta1 + deleteRight2 === 0) {
sequence[i + 1].args.deleteLeft = deleteLeft2 + deleteRight2;
delete sequence[i + 1].args.deleteRight;
const args = JSON.parse(JSON.stringify(sequence[i + 1].args));
args.deleteLeft = deleteLeft2 + deleteRight2;
delete args.deleteRight;
sequence[i + 1] = { command: '$type', args };
sequence.splice(i, 1);
i--;
continue;
Expand All @@ -76,7 +78,9 @@ const CommandSequence = function({ maxLength = null } = {}) {
if (text1.length >= deleteLeft2 &&
deleteRight2 === 0) {
const text = text1.substr(0, text1.length - deleteLeft2) + text2;
sequence[i - 1].args.text = text;
const args = JSON.parse(JSON.stringify(sequence[i - 1].args));
args.text = text;
sequence[i - 1] = { command: '$type', args };
sequence.splice(i, 1);
i--;
continue;
Expand Down
10 changes: 9 additions & 1 deletion src/keyboard_macro.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,19 @@ const KeyboardMacro = function({ awaitController }) {
}
return validArgs;
};
const optimizeSequence = function(sequence) {
const s = CommandSequence();
for (const command of sequence) {
s.push(command);
}
s.optimize();
return s.get();
};

const playbackImpl = async function(args, { tillEndOfFile = false } = {}) {
args = validatePlaybackArgs(args);
const repeat = 'repeat' in args ? args.repeat : 1;
const commands = 'sequence' in args ? args.sequence : sequence.get();
const commands = 'sequence' in args ? optimizeSequence(args.sequence) : sequence.get();
const wrapMode = active ? 'command' : null;
if (recording) {
if (!('sequence' in args)) {
Expand Down
36 changes: 36 additions & 0 deletions test/suite/command_sequence.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ describe('CommandSequence', () => {
seq.optimize();
assert.deepStrictEqual(seq.get(), [ TYPE123 ]);
});
it('should not modify input objects (1: consucutive typing)', () => {
const TYPE1 = { command: '$type', args: { text: 'A' } };
const TYPE2 = { command: '$type', args: { text: 'B' } };
const seq = CommandSequence();
seq.push(TYPE1);
seq.push(TYPE2);
seq.optimize();
assert.deepStrictEqual(seq.get(), [ { command: '$type', args: { text: 'AB' } } ]);
assert.deepStrictEqual(TYPE1, { command: '$type', args: { text: 'A' } });
assert.deepStrictEqual(TYPE2, { command: '$type', args: { text: 'B' } });
});
it('should not concatenate direct typing commands with deleting (1)', () => {
const TYPE1 = {
command: '$type',
Expand Down Expand Up @@ -188,6 +199,17 @@ describe('CommandSequence', () => {
seq.optimize();
assert.deepStrictEqual(seq.get(), []);
});
it('should not modify input objects (2: pair of cursor motion)', () => {
const MOVE1 = { command: '$moveCursor', args: { characterDelta: -3 } };
const MOVE2 = { command: '$moveCursor', args: { characterDelta: 3 } };
const seq = CommandSequence();
seq.push(MOVE1);
seq.push(MOVE2);
seq.optimize();
assert.deepStrictEqual(seq.get(), []);
assert.deepStrictEqual(MOVE1, { command: '$moveCursor', args: { characterDelta: -3 } });
assert.deepStrictEqual(MOVE2, { command: '$moveCursor', args: { characterDelta: 3 } });
});
it('should retain consecutive cursor motions that have vertical motion', () => {
const MOVE1 = {
command: '$moveCursor',
Expand Down Expand Up @@ -269,6 +291,20 @@ describe('CommandSequence', () => {
seq.optimize();
assert.deepStrictEqual(seq.get(), [ EXPECTED ]);
});
it('should not modify input objects (3: cursor motion followed by deleting and typing)', () => {
const INPUT = [
{ command: '$moveCursor', args: { characterDelta: -1 } },
{ command: '$type', args: { deleteRight: 1, text: 'a' } }
];
const EXPECTED = { command: '$type', args: { deleteLeft: 1, text: 'a' } };
const seq = CommandSequence();
seq.push(INPUT[0]);
seq.push(INPUT[1]);
seq.optimize();
assert.deepStrictEqual(seq.get(), [ EXPECTED ]);
assert.deepStrictEqual(INPUT[0], { command: '$moveCursor', args: { characterDelta: -1 } });
assert.deepStrictEqual(INPUT[1], { command: '$type', args: { deleteRight: 1, text: 'a' } });
});
it('should shrink three commands into one', () => {
const INPUT = [
{
Expand Down
19 changes: 18 additions & 1 deletion test/suite/keyboard_macro.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ describe('KeybaordMacro', () => {
{ command: 'internal:log', args: 'hello' }
]);
});
it('should record the commands specified times if repeat option specified', async () => {
it('should record the commands multiple times if repeat option specified', async () => {
const sequence = [
{ command: 'internal:log', args: 'hello' }
];
Expand All @@ -654,6 +654,23 @@ describe('KeybaordMacro', () => {
{ command: 'internal:log', args: 'hello' }
]);
});
it('should optimize the specified sequence before executing and recording', async () => {
keyboardMacro.registerInternalCommand('$type', async (args) => {
logs.push(`$type:${args.text}`);
});
const sequence = [
{ command: '$type', args: { text: 'A' } },
{ command: '$type', args: { text: 'B' } }
];
keyboardMacro.startRecording();
await keyboardMacro.playback({ sequence });
keyboardMacro.finishRecording();

assert.deepStrictEqual(logs, [ '$type:AB' ]);
assert.deepStrictEqual(keyboardMacro.getCurrentSequence(), [
{ command: '$type', args: { text: 'AB' } }
]);
});
});
describe('wrap with playback with sequence option', () => {
const logs = [];
Expand Down

0 comments on commit 3297c2f

Please sign in to comment.