Skip to content

Commit 4d68be9

Browse files
Make arguments to engine optional (#2477)
## Checklist - [/] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [/] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [/] I have not broken the cheatsheet --------- Co-authored-by: Pokey Rule <755842+pokey@users.noreply.github.com>
1 parent 4387672 commit 4d68be9

File tree

13 files changed

+97
-139
lines changed

13 files changed

+97
-139
lines changed

packages/cursorless-engine/src/CommandHistory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export class CommandHistory implements CommandRunnerDecorator {
2727
constructor(
2828
private ide: IDE,
2929
private storage: CommandHistoryStorage,
30-
private commandServerApi: CommandServerApi | null,
30+
private commandServerApi: CommandServerApi | undefined,
3131
) {}
3232

3333
wrapCommandRunner(
Lines changed: 6 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
1-
import { Disposable, TextEditorSelectionChangeEvent } from "@cursorless/common";
2-
import type { SyntaxNode, TreeCursor } from "web-tree-sitter";
3-
import { ide } from "../singletons/ide.singleton";
4-
import { TreeSitter } from "../typings/TreeSitter";
1+
import type { Disposable, IDE } from "@cursorless/common";
52

63
/**
74
* Debug logger
85
*/
96
export class Debug {
107
private disposableConfiguration?: Disposable;
11-
private disposableSelection?: Disposable;
128
active: boolean;
139

14-
constructor(private treeSitter: TreeSitter) {
15-
ide().disposeOnExit(this);
10+
constructor(private ide: IDE) {
11+
ide.disposeOnExit(this);
1612

1713
this.evaluateSetting = this.evaluateSetting.bind(this);
18-
this.logBranchTypes = this.logBranchTypes.bind(this);
1914
this.active = true;
2015

21-
switch (ide().runMode) {
16+
switch (ide.runMode) {
2217
// Development mode. Always enable.
2318
case "development":
2419
this.enableDebugLog();
@@ -31,7 +26,7 @@ export class Debug {
3126
case "production":
3227
this.evaluateSetting();
3328
this.disposableConfiguration =
34-
ide().configuration.onDidChangeConfiguration(this.evaluateSetting);
29+
ide.configuration.onDidChangeConfiguration(this.evaluateSetting);
3530
break;
3631
}
3732
}
@@ -46,98 +41,22 @@ export class Debug {
4641
if (this.disposableConfiguration) {
4742
this.disposableConfiguration.dispose();
4843
}
49-
if (this.disposableSelection) {
50-
this.disposableSelection.dispose();
51-
}
5244
}
5345

5446
private enableDebugLog() {
5547
this.active = true;
56-
this.disposableSelection = ide().onDidChangeTextEditorSelection(
57-
this.logBranchTypes,
58-
);
5948
}
6049

6150
private disableDebugLog() {
6251
this.active = false;
63-
if (this.disposableSelection) {
64-
this.disposableSelection.dispose();
65-
this.disposableSelection = undefined;
66-
}
6752
}
6853

6954
private evaluateSetting() {
70-
const debugEnabled = ide().configuration.getOwnConfiguration("debug");
55+
const debugEnabled = this.ide.configuration.getOwnConfiguration("debug");
7156
if (debugEnabled) {
7257
this.enableDebugLog();
7358
} else {
7459
this.disableDebugLog();
7560
}
7661
}
77-
78-
private logBranchTypes(event: TextEditorSelectionChangeEvent) {
79-
let node: SyntaxNode;
80-
try {
81-
node = this.treeSitter.getNodeAtLocation(
82-
ide().activeTextEditor!.document,
83-
event.selections[0],
84-
);
85-
} catch (error) {
86-
return;
87-
}
88-
89-
const ancestors: SyntaxNode[] = [node];
90-
while (node.parent != null) {
91-
ancestors.unshift(node.parent);
92-
node = node.parent;
93-
}
94-
95-
const cursor = node.tree.walk();
96-
this.printCursorLocationInfo(ancestors, cursor, 0);
97-
}
98-
99-
private printCursorLocationInfo(
100-
nodes: SyntaxNode[],
101-
cursor: TreeCursor,
102-
index: number,
103-
) {
104-
const field = cursor.currentFieldName;
105-
const fieldText = field != null ? `${field}: ` : "";
106-
const indent = " ".repeat(index);
107-
const nodeIsLast = index === nodes.length - 1;
108-
const { nodeIsNamed } = cursor;
109-
let text = `${indent}${fieldText}`;
110-
111-
if (nodeIsNamed) {
112-
text += `(${cursor.nodeType}`;
113-
if (nodeIsLast) {
114-
text += ")";
115-
}
116-
} else {
117-
text += `"${cursor.nodeType}"`;
118-
}
119-
120-
console.log(text);
121-
122-
if (
123-
!nodeIsLast &&
124-
this.cursorGoToChildWithId(cursor, nodes[index + 1].id)
125-
) {
126-
this.printCursorLocationInfo(nodes, cursor, index + 1);
127-
}
128-
129-
if (nodeIsNamed && !nodeIsLast) {
130-
console.log(`${indent})`);
131-
}
132-
}
133-
134-
private cursorGoToChildWithId(cursor: TreeCursor, id: number): boolean {
135-
cursor.gotoFirstChild();
136-
while (cursor.currentNode.id !== id) {
137-
if (!cursor.gotoNextSibling()) {
138-
return false;
139-
}
140-
}
141-
return true;
142-
}
14362
}

packages/cursorless-engine/src/core/HatTokenMapImpl.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class HatTokenMapImpl implements HatTokenMap {
4343
rangeUpdater: RangeUpdater,
4444
private debug: Debug,
4545
hats: Hats,
46-
private commandServerApi: CommandServerApi | null,
46+
private commandServerApi: CommandServerApi,
4747
) {
4848
ide().disposeOnExit(this);
4949
this.activeMap = new IndividualHatMap(rangeUpdater);
@@ -130,18 +130,15 @@ export class HatTokenMapImpl implements HatTokenMap {
130130
}
131131

132132
private async maybeTakePrePhraseSnapshot() {
133-
const phraseStartSignal = this.commandServerApi?.signals?.prePhrase;
133+
const newSignalVersion =
134+
await this.commandServerApi.signals.prePhrase.getVersion();
134135

135-
if (phraseStartSignal != null) {
136-
const newSignalVersion = await phraseStartSignal.getVersion();
136+
if (newSignalVersion !== this.lastSignalVersion) {
137+
this.debug.log("taking snapshot");
138+
this.lastSignalVersion = newSignalVersion;
137139

138-
if (newSignalVersion !== this.lastSignalVersion) {
139-
this.debug.log("taking snapshot");
140-
this.lastSignalVersion = newSignalVersion;
141-
142-
if (newSignalVersion != null) {
143-
this.takePrePhraseSnapshot();
144-
}
140+
if (newSignalVersion != null) {
141+
this.takePrePhraseSnapshot();
145142
}
146143
}
147144
}

packages/cursorless-engine/src/core/commandRunner/CommandRunnerImpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class CommandRunnerImpl implements CommandRunner {
2626
private noAutomaticTokenExpansion: boolean | undefined;
2727

2828
constructor(
29-
private commandServerApi: CommandServerApi | null,
29+
private commandServerApi: CommandServerApi,
3030
private debug: Debug,
3131
private storedTargets: StoredTargetMap,
3232
private pipelineRunner: TargetPipelineRunner,

packages/cursorless-engine/src/core/getCommandFallback.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import {
1010
import type { ActionReturnValue } from "../actions/actions.types";
1111

1212
export async function getCommandFallback(
13-
commandServerApi: CommandServerApi | null,
13+
commandServerApi: CommandServerApi,
1414
runAction: (actionDescriptor: ActionDescriptor) => Promise<ActionReturnValue>,
1515
command: CommandComplete,
1616
): Promise<Fallback | null> {
17-
const focusedElementType = await commandServerApi?.getFocusedElementType();
17+
const focusedElementType = await commandServerApi.getFocusedElementType();
1818

1919
if (focusedElementType == null || focusedElementType === "textEditor") {
2020
return null;

packages/cursorless-engine/src/cursorlessEngine.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import {
22
Command,
33
CommandServerApi,
4-
FileSystem,
54
Hats,
65
IDE,
76
ScopeProvider,
87
ensureCommandShape,
8+
type FileSystem,
99
} from "@cursorless/common";
1010
import { KeyboardTargetUpdater } from "./KeyboardTargetUpdater";
1111
import {
@@ -17,6 +17,8 @@ import { HatTokenMapImpl } from "./core/HatTokenMapImpl";
1717
import type { Snippets } from "./core/Snippets";
1818
import { StoredTargetMap } from "./core/StoredTargets";
1919
import { RangeUpdater } from "./core/updateSelections/RangeUpdater";
20+
import { DisabledCommandServerApi } from "./disabledComponents/DisabledCommandServerApi";
21+
import { DisabledHatTokenMap } from "./disabledComponents/DisabledHatTokenMap";
2022
import { DisabledSnippets } from "./disabledComponents/DisabledSnippets";
2123
import { DisabledTalonSpokenForms } from "./disabledComponents/DisabledTalonSpokenForms";
2224
import { CustomSpokenFormGeneratorImpl } from "./generateSpokenForm/CustomSpokenFormGeneratorImpl";
@@ -34,40 +36,44 @@ import { type TalonSpokenForms } from "./scopeProviders/TalonSpokenForms";
3436
import { injectIde } from "./singletons/ide.singleton";
3537
import { TreeSitter } from "./typings/TreeSitter";
3638

37-
export async function createCursorlessEngine(
38-
treeSitter: TreeSitter,
39-
ide: IDE,
40-
hats: Hats,
41-
commandServerApi: CommandServerApi | null,
42-
fileSystem: FileSystem,
43-
talonSpokenForms: TalonSpokenForms | undefined,
44-
snippets: Snippets = new DisabledSnippets(),
45-
): Promise<CursorlessEngine> {
46-
injectIde(ide);
39+
interface Props {
40+
ide: IDE;
41+
hats?: Hats;
42+
treeSitter: TreeSitter;
43+
fileSystem: FileSystem;
44+
commandServerApi?: CommandServerApi;
45+
talonSpokenForms?: TalonSpokenForms;
46+
snippets?: Snippets;
47+
}
4748

48-
const debug = new Debug(treeSitter);
49+
export async function createCursorlessEngine({
50+
ide,
51+
hats,
52+
treeSitter,
53+
fileSystem,
54+
commandServerApi = new DisabledCommandServerApi(),
55+
talonSpokenForms = new DisabledTalonSpokenForms(),
56+
snippets = new DisabledSnippets(),
57+
}: Props): Promise<CursorlessEngine> {
58+
injectIde(ide);
4959

60+
const debug = new Debug(ide);
5061
const rangeUpdater = new RangeUpdater();
51-
52-
const hatTokenMap = new HatTokenMapImpl(
53-
rangeUpdater,
54-
debug,
55-
hats,
56-
commandServerApi,
57-
);
58-
hatTokenMap.allocateHats();
59-
6062
const storedTargets = new StoredTargetMap();
61-
6263
const keyboardTargetUpdater = new KeyboardTargetUpdater(storedTargets);
64+
const customSpokenFormGenerator = new CustomSpokenFormGeneratorImpl(
65+
talonSpokenForms,
66+
);
67+
68+
const hatTokenMap =
69+
hats != null
70+
? new HatTokenMapImpl(rangeUpdater, debug, hats, commandServerApi)
71+
: new DisabledHatTokenMap();
72+
void hatTokenMap.allocateHats();
6373

6474
const languageDefinitions = new LanguageDefinitions(fileSystem, treeSitter);
6575
await languageDefinitions.init();
6676

67-
const customSpokenFormGenerator = new CustomSpokenFormGeneratorImpl(
68-
talonSpokenForms ?? new DisabledTalonSpokenForms(),
69-
);
70-
7177
ide.disposeOnExit(
7278
rangeUpdater,
7379
languageDefinitions,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { CommandServerApi } from "@cursorless/common";
2+
3+
export class DisabledCommandServerApi implements CommandServerApi {
4+
getFocusedElementType() {
5+
return Promise.resolve(undefined);
6+
}
7+
8+
readonly signals = {
9+
prePhrase: {
10+
getVersion() {
11+
return Promise.resolve(null);
12+
},
13+
},
14+
};
15+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { HatTokenMap } from "@cursorless/common";
2+
3+
export class DisabledHatTokenMap implements HatTokenMap {
4+
async allocateHats() {
5+
// Do nothing
6+
}
7+
8+
async getReadableMap() {
9+
return {
10+
getEntries() {
11+
return [];
12+
},
13+
getToken() {
14+
throw new Error("Hat map is disabled");
15+
},
16+
};
17+
}
18+
19+
dispose() {
20+
// Do nothing
21+
}
22+
}

packages/cursorless-engine/src/runCommand.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { ScopeHandlerFactoryImpl } from "./processTargets/modifiers/scopeHandler
3434
*/
3535
export async function runCommand(
3636
treeSitter: TreeSitter,
37-
commandServerApi: CommandServerApi | null,
37+
commandServerApi: CommandServerApi,
3838
debug: Debug,
3939
hatTokenMap: HatTokenMap,
4040
snippets: Snippets,
@@ -90,7 +90,7 @@ async function unwrapLegacyCommandResponse(
9090

9191
function createCommandRunner(
9292
treeSitter: TreeSitter,
93-
commandServerApi: CommandServerApi | null,
93+
commandServerApi: CommandServerApi,
9494
languageDefinitions: LanguageDefinitions,
9595
debug: Debug,
9696
storedTargets: StoredTargetMap,

packages/cursorless-engine/src/spokenForms/CustomSpokenForms.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,11 @@ export class CustomSpokenForms {
8484
this.needsInitialTalonUpdate_ = true;
8585
} else {
8686
console.error("Error loading custom spoken forms", err);
87+
const msg = (err as Error).message.replace(/\.$/, "");
8788
showError(
8889
ide().messages,
8990
"CustomSpokenForms.updateSpokenFormMaps",
90-
`Error loading custom spoken forms: ${
91-
(err as Error).message
92-
}}}. Falling back to default spoken forms.`,
91+
`Error loading custom spoken forms: ${msg}. Falling back to default spoken forms.`,
9392
);
9493
}
9594

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class TestCaseRecorder {
6565
private spokenFormGenerator = new SpokenFormGenerator(defaultSpokenFormMap);
6666

6767
constructor(
68-
private commandServerApi: CommandServerApi | null,
68+
private commandServerApi: CommandServerApi | undefined,
6969
private hatTokenMap: HatTokenMap,
7070
private storedTargets: StoredTargetMap,
7171
) {

0 commit comments

Comments
 (0)