Skip to content

Commit d80f28e

Browse files
committed
Rename file
1 parent ab9315f commit d80f28e

File tree

5 files changed

+112
-62
lines changed

5 files changed

+112
-62
lines changed

packages/cursorless-engine/src/SpokenFormMap.ts

100755100644
File mode changed.

packages/cursorless-engine/src/generateSpokenForm/GeneratorSpokenFormMap.ts

-48
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { SpokenFormMapEntry, SpokenFormType } from "../SpokenFormMap";
2+
3+
/**
4+
* A component of a spoken form used internally during spoken form generation.
5+
* This is a recursive type, so it can contain other spoken form components.
6+
* During the final step of spoken form generation, it is flattened.
7+
*
8+
* FIXME: In the future, we want to replace `string` with something like
9+
* `LiteralSpokenFormComponent` and `SpokenFormComponent[]` with something like
10+
* `SequenceSpokenFormComponent`. We'd also like to avoid throwing
11+
* `NoSpokenFormError` and instead return a `SpokenFormComponent` that
12+
* represents an error. This would allow us to localize errors and still render
13+
* the remainder of the spoken form component.
14+
*/
15+
export type SpokenFormComponent =
16+
| CustomizableSpokenFormComponent
17+
| string
18+
| SpokenFormComponent[];
19+
20+
/**
21+
* A customizable spoken form component. This is a spoken form component that
22+
* can be customized by the user. It is used internally during spoken form
23+
* generation.
24+
*/
25+
export interface CustomizableSpokenFormComponent {
26+
type: "customizable";
27+
spokenForms: SpokenFormMapEntry;
28+
spokenFormType: SpokenFormType;
29+
id: string;
30+
}

packages/cursorless-engine/src/generateSpokenForm/generateSpokenForm.ts

+32-14
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ import { getRangeConnective } from "./getRangeConnective";
1919
import { SpokenFormMap } from "../SpokenFormMap";
2020
import { PrimitiveTargetSpokenFormGenerator } from "./primitiveTargetToSpokenForm";
2121
import {
22-
GeneratorSpokenFormMap,
23-
SpokenFormComponent,
24-
getGeneratorSpokenForms,
25-
} from "./GeneratorSpokenFormMap";
22+
SpokenFormComponentMap,
23+
getSpokenFormComponentMap,
24+
} from "./getSpokenFormComponentMap";
25+
import { SpokenFormComponent } from "./SpokenFormComponent";
2626
import { SpokenForm } from "@cursorless/common";
2727

2828
export class SpokenFormGenerator {
2929
private primitiveGenerator: PrimitiveTargetSpokenFormGenerator;
30-
private spokenFormMap: GeneratorSpokenFormMap;
30+
private spokenFormMap: SpokenFormComponentMap;
3131

3232
constructor(spokenFormMap: SpokenFormMap) {
33-
this.spokenFormMap = getGeneratorSpokenForms(spokenFormMap);
33+
this.spokenFormMap = getSpokenFormComponentMap(spokenFormMap);
3434

3535
this.primitiveGenerator = new PrimitiveTargetSpokenFormGenerator(
3636
this.spokenFormMap,
@@ -40,25 +40,41 @@ export class SpokenFormGenerator {
4040
/**
4141
* Given a command, generates its spoken form.
4242
* @param command The command to generate a spoken form for
43-
* @returns The spoken form of the command, or null if the command has no spoken
44-
* form
43+
* @returns The spoken form of the command
4544
*/
46-
command(command: CommandComplete): SpokenForm {
45+
processCommand(command: CommandComplete): SpokenForm {
4746
return this.componentsToSpokenForm(() => this.handleAction(command.action));
4847
}
4948

5049
/**
51-
* Given a command, generates its spoken form.
52-
* @param command The command to generate a spoken form for
53-
* @returns The spoken form of the command, or null if the command has no spoken
54-
* form
50+
* Given a scope type, generates its spoken form.
51+
* @param scopeType The scope type to generate a spoken form for
52+
* @returns The spoken form of the scope type
5553
*/
56-
scopeType(scopeType: ScopeType): SpokenForm {
54+
processScopeType(scopeType: ScopeType): SpokenForm {
5755
return this.componentsToSpokenForm(() => [
5856
this.primitiveGenerator.handleScopeType(scopeType),
5957
]);
6058
}
6159

60+
/**
61+
* Given a function that returns a spoken form component, generates a spoken
62+
* form for that component by flattening the component and performing a
63+
* cartesian product over any elements that have multiple ways to be spoken.
64+
* Note that this spoken form object can correspond to multiple actual spoken
65+
* forms, consisting of a preferred spoken form and a list of alternative
66+
* spoken forms.
67+
*
68+
* Note that today, we arbitrarily choose the first spoken form as the
69+
* preferred spoken form, and the rest as alternative spoken forms.
70+
*
71+
* If the function throws a {@link NoSpokenFormError}, returns an error spoken
72+
* form object instead.
73+
*
74+
* @param getComponents A function that returns the components to generate a
75+
* spoken form for
76+
* @returns A spoken form for the given components
77+
*/
6278
private componentsToSpokenForm(
6379
getComponents: () => SpokenFormComponent,
6480
): SpokenForm {
@@ -256,9 +272,11 @@ function constructSpokenForms(component: SpokenFormComponent): string[] {
256272
const componentInfo = `${camelCaseToAllDown(
257273
component.spokenFormType,
258274
)} with id ${component.id}`;
275+
259276
const helpInfo = component.spokenForms.isSecret
260277
? "this is a secret spoken form currently only for internal experimentation"
261278
: "please see https://www.cursorless.org/docs/user/customization/ for more information";
279+
262280
throw new NoSpokenFormError(
263281
`${componentInfo}; ${helpInfo}`,
264282
component.spokenForms.requiresTalonUpdate,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {
2+
PartialSpokenFormTypes,
3+
SpokenFormMap,
4+
SpokenFormMapKeyTypes,
5+
} from "../SpokenFormMap";
6+
import { CustomizableSpokenFormComponent } from "./SpokenFormComponent";
7+
8+
/**
9+
* A spoken form component map is a map of spoken form types to a map of IDs to
10+
* spoken form components. It is used to generate spoken forms. It mirrors the
11+
* structure of a {@link SpokenFormMap}, but instead of containing spoken form
12+
* map entries, it contains spoken form components for use in spoken form
13+
* generation.
14+
*/
15+
export type SpokenFormComponentMap = {
16+
readonly [K in keyof SpokenFormMapKeyTypes]: K extends PartialSpokenFormTypes
17+
? Partial<Record<SpokenFormMapKeyTypes[K], CustomizableSpokenFormComponent>>
18+
: Record<SpokenFormMapKeyTypes[K], CustomizableSpokenFormComponent>;
19+
};
20+
21+
/**
22+
* Converts a spoken form map to a spoken form component map for use in spoken
23+
* form generation.
24+
* @param spokenFormMap The spoken form map to convert to a spoken form
25+
* component map
26+
* @returns A spoken form component map that can be used to generate spoken
27+
* forms
28+
*/
29+
export function getSpokenFormComponentMap(
30+
spokenFormMap: SpokenFormMap,
31+
): SpokenFormComponentMap {
32+
return Object.fromEntries(
33+
Object.entries(spokenFormMap).map(([spokenFormType, map]) => [
34+
spokenFormType,
35+
Object.fromEntries(
36+
Object.entries(map).map(([id, spokenForms]) => [
37+
id,
38+
{
39+
type: "customizable",
40+
spokenForms,
41+
spokenFormType,
42+
id,
43+
},
44+
]),
45+
),
46+
]),
47+
// FIXME: Don't cast here; need to make our own mapValues with stronger typing
48+
// using tricks from our object.d.ts
49+
) as SpokenFormComponentMap;
50+
}

0 commit comments

Comments
 (0)