Skip to content

Commit 3981ac9

Browse files
bjaspanBarry Jaspanpre-commit-ci-lite[bot]pokey
authored
Use dependency injection for TestCaseRecorder (#2002)
Use dependency injection for getting TestCaseRecorder into CursorlessEngine. A future PR should perhaps move TestCaseRecorder into a new package, @cursorless/cursorless-dev or similar, to isolate developer-only dependencies that are needed in production code. This is an alternate approach to #2001 requested in a comment. It is also the most TypeScript I've written to date, so I probably did some things stylistically wrong. Class `TestCaseRecorderCommandRunnerDecorator` in particular feels very C++-like, not very TS-like, to me. --------- Co-authored-by: Barry Jaspan <[email protected]> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Pokey Rule <[email protected]>
1 parent 117af66 commit 3981ac9

File tree

5 files changed

+43
-17
lines changed

5 files changed

+43
-17
lines changed

packages/cursorless-engine/src/api/CursorlessEngineApi.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
import { Command, HatTokenMap, IDE } from "@cursorless/common";
22
import { Snippets } from "../core/Snippets";
33
import { StoredTargetMap } from "../core/StoredTargets";
4-
import { TestCaseRecorder } from "../testCaseRecorder/TestCaseRecorder";
54
import { ScopeProvider } from "@cursorless/common";
5+
import { CommandRunner } from "../CommandRunner";
6+
import { ReadOnlyHatMap } from "@cursorless/common";
67

78
export interface CursorlessEngine {
89
commandApi: CommandApi;
910
scopeProvider: ScopeProvider;
1011
customSpokenFormGenerator: CustomSpokenFormGenerator;
11-
testCaseRecorder: TestCaseRecorder;
1212
storedTargets: StoredTargetMap;
1313
hatTokenMap: HatTokenMap;
1414
snippets: Snippets;
1515
injectIde: (ide: IDE | undefined) => void;
1616
runIntegrationTests: () => Promise<void>;
17+
addCommandRunnerDecorator: (
18+
commandRunnerDecorator: CommandRunnerDecorator,
19+
) => void;
1720
}
1821

1922
export interface CustomSpokenFormGenerator {
@@ -39,3 +42,16 @@ export interface CommandApi {
3942
*/
4043
runCommandSafe(...args: unknown[]): Promise<unknown>;
4144
}
45+
46+
export interface CommandRunnerDecorator {
47+
/**
48+
* @param commandRunner: A CommandRunner.
49+
* @param readableHatMap: A ReadOnlyHatMap.
50+
* @returns A new CommandRunner that invokes the provided CommandRunner in
51+
* addition to performing some other work.
52+
*/
53+
wrapCommandRunner: (
54+
readableHatMap: ReadOnlyHatMap,
55+
commandRunner: CommandRunner,
56+
) => CommandRunner;
57+
}

packages/cursorless-engine/src/cursorlessEngine.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import {
66
IDE,
77
ScopeProvider,
88
} from "@cursorless/common";
9-
import { StoredTargetMap, TestCaseRecorder, TreeSitter } from ".";
10-
import { CursorlessEngine } from "./api/CursorlessEngineApi";
9+
import { StoredTargetMap, TreeSitter } from ".";
10+
import {
11+
CommandRunnerDecorator,
12+
CursorlessEngine,
13+
} from "./api/CursorlessEngineApi";
1114
import { Debug } from "./core/Debug";
1215
import { HatTokenMapImpl } from "./core/HatTokenMapImpl";
1316
import { Snippets } from "./core/Snippets";
@@ -53,8 +56,6 @@ export function createCursorlessEngine(
5356

5457
const storedTargets = new StoredTargetMap();
5558

56-
const testCaseRecorder = new TestCaseRecorder(hatTokenMap, storedTargets);
57-
5859
const languageDefinitions = new LanguageDefinitions(fileSystem, treeSitter);
5960

6061
const talonSpokenForms = new TalonSpokenFormsJsonReader(fileSystem);
@@ -65,18 +66,20 @@ export function createCursorlessEngine(
6566

6667
ide.disposeOnExit(rangeUpdater, languageDefinitions, hatTokenMap, debug);
6768

69+
const commandRunnerDecorators: CommandRunnerDecorator[] = [];
70+
6871
return {
6972
commandApi: {
7073
runCommand(command: Command) {
7174
return runCommand(
7275
treeSitter,
7376
debug,
7477
hatTokenMap,
75-
testCaseRecorder,
7678
snippets,
7779
storedTargets,
7880
languageDefinitions,
7981
rangeUpdater,
82+
commandRunnerDecorators,
8083
command,
8184
);
8285
},
@@ -86,11 +89,11 @@ export function createCursorlessEngine(
8689
treeSitter,
8790
debug,
8891
hatTokenMap,
89-
testCaseRecorder,
9092
snippets,
9193
storedTargets,
9294
languageDefinitions,
9395
rangeUpdater,
96+
commandRunnerDecorators,
9497
ensureCommandShape(args),
9598
);
9699
},
@@ -101,13 +104,15 @@ export function createCursorlessEngine(
101104
customSpokenFormGenerator,
102105
),
103106
customSpokenFormGenerator,
104-
testCaseRecorder,
105107
storedTargets,
106108
hatTokenMap,
107109
snippets,
108110
injectIde,
109111
runIntegrationTests: () =>
110112
runIntegrationTests(treeSitter, languageDefinitions),
113+
addCommandRunnerDecorator: (decorator: CommandRunnerDecorator) => {
114+
commandRunnerDecorators.push(decorator);
115+
},
111116
};
112117
}
113118

packages/cursorless-engine/src/runCommand.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { Snippets } from "./core/Snippets";
66
import { CommandRunnerImpl } from "./core/commandRunner/CommandRunnerImpl";
77
import { canonicalizeAndValidateCommand } from "./core/commandVersionUpgrades/canonicalizeAndValidateCommand";
88
import { RangeUpdater } from "./core/updateSelections/RangeUpdater";
9-
import { StoredTargetMap, TestCaseRecorder, TreeSitter } from "./index";
9+
import { StoredTargetMap, TreeSitter } from "./index";
1010
import { LanguageDefinitions } from "./languages/LanguageDefinitions";
1111
import { TargetPipelineRunner } from "./processTargets";
1212
import { MarkStageFactoryImpl } from "./processTargets/MarkStageFactoryImpl";
1313
import { ModifierStageFactoryImpl } from "./processTargets/ModifierStageFactoryImpl";
1414
import { ScopeHandlerFactoryImpl } from "./processTargets/modifiers/scopeHandlers";
15+
import { CommandRunnerDecorator } from "./api/CursorlessEngineApi";
1516

1617
/**
1718
* Entry point for Cursorless commands. We proceed as follows:
@@ -29,11 +30,11 @@ export async function runCommand(
2930
treeSitter: TreeSitter,
3031
debug: Debug,
3132
hatTokenMap: HatTokenMap,
32-
testCaseRecorder: TestCaseRecorder,
3333
snippets: Snippets,
3434
storedTargets: StoredTargetMap,
3535
languageDefinitions: LanguageDefinitions,
3636
rangeUpdater: RangeUpdater,
37+
commandRunnerDecorators: CommandRunnerDecorator[],
3738
command: Command,
3839
): Promise<unknown> {
3940
if (debug.active) {
@@ -57,11 +58,8 @@ export async function runCommand(
5758
rangeUpdater,
5859
);
5960

60-
if (testCaseRecorder.isActive()) {
61-
commandRunner = testCaseRecorder.wrapCommandRunner(
62-
readableHatMap,
63-
commandRunner,
64-
);
61+
for (const decorator of commandRunnerDecorators) {
62+
commandRunner = decorator.wrapCommandRunner(readableHatMap, commandRunner);
6563
}
6664

6765
return await commandRunner.run(commandComplete);

packages/cursorless-engine/src/testCaseRecorder/TestCaseRecorder.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,9 @@ export class TestCaseRecorder {
459459
readableHatMap: ReadOnlyHatMap,
460460
runner: CommandRunner,
461461
): CommandRunner {
462+
if (!this.isActive()) {
463+
return runner;
464+
}
462465
return {
463466
run: async (commandComplete: CommandComplete) => {
464467
try {

packages/cursorless-vscode/src/extension.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
import { StatusBarItem } from "./StatusBarItem";
4949
import { vscodeApi } from "./vscodeApi";
5050
import { mkdir } from "fs/promises";
51+
import { TestCaseRecorder } from "@cursorless/cursorless-engine";
5152

5253
/**
5354
* Extension entrypoint called by VSCode on Cursorless startup.
@@ -82,13 +83,13 @@ export async function activate(
8283

8384
const {
8485
commandApi,
85-
testCaseRecorder,
8686
storedTargets,
8787
hatTokenMap,
8888
scopeProvider,
8989
snippets,
9090
injectIde,
9191
runIntegrationTests,
92+
addCommandRunnerDecorator,
9293
customSpokenFormGenerator,
9394
} = createCursorlessEngine(
9495
treeSitter,
@@ -98,6 +99,9 @@ export async function activate(
9899
fileSystem,
99100
);
100101

102+
const testCaseRecorder = new TestCaseRecorder(hatTokenMap, storedTargets);
103+
addCommandRunnerDecorator(testCaseRecorder);
104+
101105
const statusBarItem = StatusBarItem.create("cursorless.showQuickPick");
102106
const keyboardCommands = KeyboardCommands.create(context, statusBarItem);
103107
const scopeVisualizer = createScopeVisualizer(normalizedIde, scopeProvider);

0 commit comments

Comments
 (0)