Skip to content

Commit

Permalink
Make arguments to engine optional (#2477)
Browse files Browse the repository at this point in the history
## 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>
  • Loading branch information
AndreasArvidsson and pokey committed Jul 12, 2024
1 parent 4387672 commit 4d68be9
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 139 deletions.
2 changes: 1 addition & 1 deletion packages/cursorless-engine/src/CommandHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class CommandHistory implements CommandRunnerDecorator {
constructor(
private ide: IDE,
private storage: CommandHistoryStorage,
private commandServerApi: CommandServerApi | null,
private commandServerApi: CommandServerApi | undefined,
) {}

wrapCommandRunner(
Expand Down
93 changes: 6 additions & 87 deletions packages/cursorless-engine/src/core/Debug.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import { Disposable, TextEditorSelectionChangeEvent } from "@cursorless/common";
import type { SyntaxNode, TreeCursor } from "web-tree-sitter";
import { ide } from "../singletons/ide.singleton";
import { TreeSitter } from "../typings/TreeSitter";
import type { Disposable, IDE } from "@cursorless/common";

/**
* Debug logger
*/
export class Debug {
private disposableConfiguration?: Disposable;
private disposableSelection?: Disposable;
active: boolean;

constructor(private treeSitter: TreeSitter) {
ide().disposeOnExit(this);
constructor(private ide: IDE) {
ide.disposeOnExit(this);

this.evaluateSetting = this.evaluateSetting.bind(this);
this.logBranchTypes = this.logBranchTypes.bind(this);
this.active = true;

switch (ide().runMode) {
switch (ide.runMode) {
// Development mode. Always enable.
case "development":
this.enableDebugLog();
Expand All @@ -31,7 +26,7 @@ export class Debug {
case "production":
this.evaluateSetting();
this.disposableConfiguration =
ide().configuration.onDidChangeConfiguration(this.evaluateSetting);
ide.configuration.onDidChangeConfiguration(this.evaluateSetting);
break;
}
}
Expand All @@ -46,98 +41,22 @@ export class Debug {
if (this.disposableConfiguration) {
this.disposableConfiguration.dispose();
}
if (this.disposableSelection) {
this.disposableSelection.dispose();
}
}

private enableDebugLog() {
this.active = true;
this.disposableSelection = ide().onDidChangeTextEditorSelection(
this.logBranchTypes,
);
}

private disableDebugLog() {
this.active = false;
if (this.disposableSelection) {
this.disposableSelection.dispose();
this.disposableSelection = undefined;
}
}

private evaluateSetting() {
const debugEnabled = ide().configuration.getOwnConfiguration("debug");
const debugEnabled = this.ide.configuration.getOwnConfiguration("debug");
if (debugEnabled) {
this.enableDebugLog();
} else {
this.disableDebugLog();
}
}

private logBranchTypes(event: TextEditorSelectionChangeEvent) {
let node: SyntaxNode;
try {
node = this.treeSitter.getNodeAtLocation(
ide().activeTextEditor!.document,
event.selections[0],
);
} catch (error) {
return;
}

const ancestors: SyntaxNode[] = [node];
while (node.parent != null) {
ancestors.unshift(node.parent);
node = node.parent;
}

const cursor = node.tree.walk();
this.printCursorLocationInfo(ancestors, cursor, 0);
}

private printCursorLocationInfo(
nodes: SyntaxNode[],
cursor: TreeCursor,
index: number,
) {
const field = cursor.currentFieldName;
const fieldText = field != null ? `${field}: ` : "";
const indent = " ".repeat(index);
const nodeIsLast = index === nodes.length - 1;
const { nodeIsNamed } = cursor;
let text = `${indent}${fieldText}`;

if (nodeIsNamed) {
text += `(${cursor.nodeType}`;
if (nodeIsLast) {
text += ")";
}
} else {
text += `"${cursor.nodeType}"`;
}

console.log(text);

if (
!nodeIsLast &&
this.cursorGoToChildWithId(cursor, nodes[index + 1].id)
) {
this.printCursorLocationInfo(nodes, cursor, index + 1);
}

if (nodeIsNamed && !nodeIsLast) {
console.log(`${indent})`);
}
}

private cursorGoToChildWithId(cursor: TreeCursor, id: number): boolean {
cursor.gotoFirstChild();
while (cursor.currentNode.id !== id) {
if (!cursor.gotoNextSibling()) {
return false;
}
}
return true;
}
}
19 changes: 8 additions & 11 deletions packages/cursorless-engine/src/core/HatTokenMapImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class HatTokenMapImpl implements HatTokenMap {
rangeUpdater: RangeUpdater,
private debug: Debug,
hats: Hats,
private commandServerApi: CommandServerApi | null,
private commandServerApi: CommandServerApi,
) {
ide().disposeOnExit(this);
this.activeMap = new IndividualHatMap(rangeUpdater);
Expand Down Expand Up @@ -130,18 +130,15 @@ export class HatTokenMapImpl implements HatTokenMap {
}

private async maybeTakePrePhraseSnapshot() {
const phraseStartSignal = this.commandServerApi?.signals?.prePhrase;
const newSignalVersion =
await this.commandServerApi.signals.prePhrase.getVersion();

if (phraseStartSignal != null) {
const newSignalVersion = await phraseStartSignal.getVersion();
if (newSignalVersion !== this.lastSignalVersion) {
this.debug.log("taking snapshot");
this.lastSignalVersion = newSignalVersion;

if (newSignalVersion !== this.lastSignalVersion) {
this.debug.log("taking snapshot");
this.lastSignalVersion = newSignalVersion;

if (newSignalVersion != null) {
this.takePrePhraseSnapshot();
}
if (newSignalVersion != null) {
this.takePrePhraseSnapshot();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class CommandRunnerImpl implements CommandRunner {
private noAutomaticTokenExpansion: boolean | undefined;

constructor(
private commandServerApi: CommandServerApi | null,
private commandServerApi: CommandServerApi,
private debug: Debug,
private storedTargets: StoredTargetMap,
private pipelineRunner: TargetPipelineRunner,
Expand Down
4 changes: 2 additions & 2 deletions packages/cursorless-engine/src/core/getCommandFallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import {
import type { ActionReturnValue } from "../actions/actions.types";

export async function getCommandFallback(
commandServerApi: CommandServerApi | null,
commandServerApi: CommandServerApi,
runAction: (actionDescriptor: ActionDescriptor) => Promise<ActionReturnValue>,
command: CommandComplete,
): Promise<Fallback | null> {
const focusedElementType = await commandServerApi?.getFocusedElementType();
const focusedElementType = await commandServerApi.getFocusedElementType();

if (focusedElementType == null || focusedElementType === "textEditor") {
return null;
Expand Down
58 changes: 32 additions & 26 deletions packages/cursorless-engine/src/cursorlessEngine.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {
Command,
CommandServerApi,
FileSystem,
Hats,
IDE,
ScopeProvider,
ensureCommandShape,
type FileSystem,
} from "@cursorless/common";
import { KeyboardTargetUpdater } from "./KeyboardTargetUpdater";
import {
Expand All @@ -17,6 +17,8 @@ import { HatTokenMapImpl } from "./core/HatTokenMapImpl";
import type { Snippets } from "./core/Snippets";
import { StoredTargetMap } from "./core/StoredTargets";
import { RangeUpdater } from "./core/updateSelections/RangeUpdater";
import { DisabledCommandServerApi } from "./disabledComponents/DisabledCommandServerApi";
import { DisabledHatTokenMap } from "./disabledComponents/DisabledHatTokenMap";
import { DisabledSnippets } from "./disabledComponents/DisabledSnippets";
import { DisabledTalonSpokenForms } from "./disabledComponents/DisabledTalonSpokenForms";
import { CustomSpokenFormGeneratorImpl } from "./generateSpokenForm/CustomSpokenFormGeneratorImpl";
Expand All @@ -34,40 +36,44 @@ import { type TalonSpokenForms } from "./scopeProviders/TalonSpokenForms";
import { injectIde } from "./singletons/ide.singleton";
import { TreeSitter } from "./typings/TreeSitter";

export async function createCursorlessEngine(
treeSitter: TreeSitter,
ide: IDE,
hats: Hats,
commandServerApi: CommandServerApi | null,
fileSystem: FileSystem,
talonSpokenForms: TalonSpokenForms | undefined,
snippets: Snippets = new DisabledSnippets(),
): Promise<CursorlessEngine> {
injectIde(ide);
interface Props {
ide: IDE;
hats?: Hats;
treeSitter: TreeSitter;
fileSystem: FileSystem;
commandServerApi?: CommandServerApi;
talonSpokenForms?: TalonSpokenForms;
snippets?: Snippets;
}

const debug = new Debug(treeSitter);
export async function createCursorlessEngine({
ide,
hats,
treeSitter,
fileSystem,
commandServerApi = new DisabledCommandServerApi(),
talonSpokenForms = new DisabledTalonSpokenForms(),
snippets = new DisabledSnippets(),
}: Props): Promise<CursorlessEngine> {
injectIde(ide);

const debug = new Debug(ide);
const rangeUpdater = new RangeUpdater();

const hatTokenMap = new HatTokenMapImpl(
rangeUpdater,
debug,
hats,
commandServerApi,
);
hatTokenMap.allocateHats();

const storedTargets = new StoredTargetMap();

const keyboardTargetUpdater = new KeyboardTargetUpdater(storedTargets);
const customSpokenFormGenerator = new CustomSpokenFormGeneratorImpl(
talonSpokenForms,
);

const hatTokenMap =
hats != null
? new HatTokenMapImpl(rangeUpdater, debug, hats, commandServerApi)
: new DisabledHatTokenMap();
void hatTokenMap.allocateHats();

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

const customSpokenFormGenerator = new CustomSpokenFormGeneratorImpl(
talonSpokenForms ?? new DisabledTalonSpokenForms(),
);

ide.disposeOnExit(
rangeUpdater,
languageDefinitions,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { CommandServerApi } from "@cursorless/common";

export class DisabledCommandServerApi implements CommandServerApi {
getFocusedElementType() {
return Promise.resolve(undefined);
}

readonly signals = {
prePhrase: {
getVersion() {
return Promise.resolve(null);
},
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { HatTokenMap } from "@cursorless/common";

export class DisabledHatTokenMap implements HatTokenMap {
async allocateHats() {
// Do nothing
}

async getReadableMap() {
return {
getEntries() {
return [];
},
getToken() {
throw new Error("Hat map is disabled");
},
};
}

dispose() {
// Do nothing
}
}
4 changes: 2 additions & 2 deletions packages/cursorless-engine/src/runCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { ScopeHandlerFactoryImpl } from "./processTargets/modifiers/scopeHandler
*/
export async function runCommand(
treeSitter: TreeSitter,
commandServerApi: CommandServerApi | null,
commandServerApi: CommandServerApi,
debug: Debug,
hatTokenMap: HatTokenMap,
snippets: Snippets,
Expand Down Expand Up @@ -90,7 +90,7 @@ async function unwrapLegacyCommandResponse(

function createCommandRunner(
treeSitter: TreeSitter,
commandServerApi: CommandServerApi | null,
commandServerApi: CommandServerApi,
languageDefinitions: LanguageDefinitions,
debug: Debug,
storedTargets: StoredTargetMap,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,11 @@ export class CustomSpokenForms {
this.needsInitialTalonUpdate_ = true;
} else {
console.error("Error loading custom spoken forms", err);
const msg = (err as Error).message.replace(/\.$/, "");
showError(
ide().messages,
"CustomSpokenForms.updateSpokenFormMaps",
`Error loading custom spoken forms: ${
(err as Error).message
}}}. Falling back to default spoken forms.`,
`Error loading custom spoken forms: ${msg}. Falling back to default spoken forms.`,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class TestCaseRecorder {
private spokenFormGenerator = new SpokenFormGenerator(defaultSpokenFormMap);

constructor(
private commandServerApi: CommandServerApi | null,
private commandServerApi: CommandServerApi | undefined,
private hatTokenMap: HatTokenMap,
private storedTargets: StoredTargetMap,
) {
Expand Down
Loading

0 comments on commit 4d68be9

Please sign in to comment.