Skip to content

Commit

Permalink
Big refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
pokey committed Jul 12, 2024
1 parent 371e1dd commit 27a1b5e
Show file tree
Hide file tree
Showing 15 changed files with 341 additions and 210 deletions.
6 changes: 3 additions & 3 deletions data/fixtures/recorded/tutorial/unit-1-basics/script.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"steps": [
"Say {step:takeCap.yml}",
"Well done! 🙌 You just used the code word for 'c', {grapheme:c}, to refer to the word with a gray hat over the 'c'.\nWhen a hat is not gray, we say its color: say {step:takeBlueSun.yml}",
"Selecting a single token is great, but oftentimes we need something bigger. Say {step:takeHarpPastDrum.yml} to select a range.",
"Despite its name, one of the most powerful aspects of cursorless is the ability to use more than one cursor. Let's try that: {step:takeNearAndSun.yml}",
"Selecting a single token is great, but oftentimes we need something bigger.\nSay {step:takeHarpPastDrum.yml} to select a range.",
"Despite its name, one of the most powerful aspects of cursorless is the ability to use more than one cursor.\nLet's try that: {step:takeNearAndSun.yml}",
"But let's show that cursorless can live up to its name: we can say {step:chuckTrap.yml} to delete a word without ever moving our cursor.",
"Tokens are great, but they're just one way to think of a document. Let's try working with lines: {step:chuckLineOdd.yml}",
"Tokens are great, but they're just one way to think of a document.\nLet's try working with lines: {step:chuckLineOdd.yml}",
"We can also use {scopeType:line} to refer to the line containing our cursor: {step:takeLine.yml}",
"You now know how to select and delete; let's give you a couple more actions to play with: say {action:pre} to place the cursor before a target, as in {step:preUrge.yml}",
"Say {action:post} to place the cursor after a target: {step:postAir.yml}",
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/types/tutorial.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ interface ActiveTutorialState extends BaseTutorialInfo {

export interface ActiveTutorialNoErrorsState extends ActiveTutorialState {
hasErrors: false;
stepContent: TutorialStepFragment[];
stepContent: TutorialStepFragment[][];
stepCount: number;
}

Expand Down
5 changes: 3 additions & 2 deletions packages/cursorless-engine/src/api/Tutorial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ export type TutorialStepTrigger =

export interface TutorialStep {
/**
* The text content of the current step
* The content of the current step. Each element in the array represents a
* paragraph in the tutorial step.
*/
content: TutorialStepFragment[];
content: TutorialStepFragment[][];

/**
* The path to the yaml file that should be used to setup the current step (if
Expand Down
42 changes: 42 additions & 0 deletions packages/cursorless-engine/src/core/ActionComponentHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ActionType } from "@cursorless/common";
import { invertBy } from "lodash";

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / test-docs-build

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, stable)

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, stable)

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, stable)

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / test-docs-build

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest, stable)

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, stable)

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest, stable)

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, legacy)

Cannot find module 'lodash' or its corresponding type declarations.

Check failure on line 2 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, legacy)

Cannot find module 'lodash' or its corresponding type declarations.
import { CustomSpokenFormGeneratorImpl } from "../generateSpokenForm/CustomSpokenFormGeneratorImpl";
import { defaultSpokenFormMap } from "../spokenForms/defaultSpokenFormMap";
import { StepComponent, StepComponentParser } from "./StepComponent";

export class ActionComponentHandler implements StepComponentParser {
private actionMap: Record<string, ActionType[]> = invertBy(
defaultSpokenFormMap.action,
(val) => val.spokenForms[0],

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / test-docs-build

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, stable)

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, stable)

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (macos-latest, stable)

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / test-docs-build

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest, stable)

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, stable)

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (windows-latest, stable)

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, legacy)

Parameter 'val' implicitly has an 'any' type.

Check failure on line 10 in packages/cursorless-engine/src/core/ActionComponentHandler.ts

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, legacy)

Parameter 'val' implicitly has an 'any' type.
) as Record<string, ActionType[]>;

constructor(
private customSpokenFormGenerator: CustomSpokenFormGeneratorImpl,
) {}

async parse(arg: string): Promise<StepComponent> {
return {
content: {
type: "term",
value: this.getActionSpokenForm(this.parseActionId(arg)),
},
};
}

private getActionSpokenForm(actionId: ActionType) {
const spokenForm =
this.customSpokenFormGenerator.actionIdToSpokenForm(actionId);

return spokenForm.spokenForms[0];
}

private parseActionId(arg: string): ActionType {
const actionIds = this.actionMap[arg];

if (actionIds == null || actionIds.length === 0) {
throw new Error(`Unknown action: ${arg}`);
}

return actionIds[0];
}
}
52 changes: 52 additions & 0 deletions packages/cursorless-engine/src/core/CursorlessCommandHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { CommandComplete, TutorialId, loadFixture } from "@cursorless/common";
import path from "path";
import { CustomSpokenFormGeneratorImpl } from "../generateSpokenForm/CustomSpokenFormGeneratorImpl";
import { canonicalizeAndValidateCommand } from "./commandVersionUpgrades/canonicalizeAndValidateCommand";
import { StepComponent, StepComponentParser } from "./StepComponent";
import { TutorialError } from "./TutorialError";

export class CursorlessCommandHandler implements StepComponentParser {
constructor(
private tutorialRootDir: string,
private tutorialId: TutorialId,
private customSpokenFormGenerator: CustomSpokenFormGeneratorImpl,
) {}

async parse(arg: string): Promise<StepComponent> {
const fixture = await loadFixture(
path.join(this.tutorialRootDir, this.tutorialId, arg),
);
const command = canonicalizeAndValidateCommand(fixture.command);

return {
initialState: fixture.initialState,
languageId: fixture.languageId,
trigger: {
type: "command",
command,
},
content: {
type: "command",
value: this.getCommandSpokenForm(command),
},
};
}

/**
* Handle the argument of a "{step:cloneStateInk.yml}""
*/
private getCommandSpokenForm(command: CommandComplete) {
// command to be said for moving to the next step
const spokenForm =
this.customSpokenFormGenerator.commandToSpokenForm(command);

if (spokenForm.type === "error") {
throw new TutorialError(
`Error while processing spoken form for command: ${spokenForm.reason}`,
{ requiresTalonUpdate: spokenForm.requiresTalonUpdate },
);
}

return spokenForm.spokenForms[0];
}
}
24 changes: 24 additions & 0 deletions packages/cursorless-engine/src/core/GraphemeComponentHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { CustomSpokenFormGeneratorImpl } from "../generateSpokenForm/CustomSpokenFormGeneratorImpl";
import { StepComponent, StepComponentParser } from "./StepComponent";

export class GraphemeComponentHandler implements StepComponentParser {
constructor(
private customSpokenFormGenerator: CustomSpokenFormGeneratorImpl,
) {}

async parse(arg: string): Promise<StepComponent> {
return {
content: {
type: "term",
value: this.getGraphemeSpokenForm(arg),
},
};
}

private getGraphemeSpokenForm(grapheme: string) {
const spokenForm =
this.customSpokenFormGenerator.graphemeToSpokenForm(grapheme);

return spokenForm.spokenForms[0];
}
}
13 changes: 13 additions & 0 deletions packages/cursorless-engine/src/core/StepComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { TestCaseSnapshot, TutorialStepFragment } from "@cursorless/common";
import { TutorialStepTrigger } from "../api/Tutorial";

export interface StepComponent {
initialState?: TestCaseSnapshot;
languageId?: string;
trigger?: TutorialStepTrigger;
content: TutorialStepFragment;
}

export interface StepComponentParser {
parse(arg: string): Promise<StepComponent>;
}
12 changes: 12 additions & 0 deletions packages/cursorless-engine/src/core/TutorialError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export class TutorialError extends Error {
public readonly requiresTalonUpdate: boolean;

constructor(
message: string,
{ requiresTalonUpdate }: { requiresTalonUpdate: boolean },
) {
super(message);

this.requiresTalonUpdate = requiresTalonUpdate;
}
}
3 changes: 2 additions & 1 deletion packages/cursorless-engine/src/core/TutorialImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import { Tutorial, TutorialContent, TutorialStep } from "../api/Tutorial";
import { CustomSpokenFormGeneratorImpl } from "../generateSpokenForm/CustomSpokenFormGeneratorImpl";
import { ide } from "../singletons/ide.singleton";
import { Debouncer } from "./Debouncer";
import { TutorialError, TutorialScriptParser } from "./TutorialScriptParser";
import { TutorialError } from "./TutorialError";
import { TutorialScriptParser } from "./TutorialScriptParser";
import { loadTutorialScript } from "./loadTutorialScript";

const HIGHLIGHT_COLOR = "highlight0";
Expand Down
Loading

0 comments on commit 27a1b5e

Please sign in to comment.