1
1
import {
2
2
CommandComplete ,
3
+ CommandLatest ,
3
4
getKey ,
4
5
Hats ,
6
+ HatStyleMap ,
5
7
splitKey ,
8
+ TestCaseSnapshot ,
6
9
TutorialContentProvider ,
7
10
TutorialId ,
8
11
} from "@cursorless/common" ;
9
12
import {
10
- CustomSpokenFormGenerator ,
11
13
canonicalizeAndValidateCommand ,
14
+ CustomSpokenFormGenerator ,
12
15
getPartialTargetDescriptors ,
13
16
transformPartialPrimitiveTargets ,
14
17
} from "@cursorless/cursorless-engine" ;
15
18
import { TutorialError } from "../TutorialError" ;
16
19
import { StepComponent , StepComponentParser } from "../types/StepComponent" ;
17
20
import { cloneDeep , mapKeys } from "lodash-es" ;
21
+ import { produce } from "immer" ;
18
22
19
23
/**
20
24
* Parses components of the form `{command:takeNear.yml}`. The argument
@@ -33,43 +37,15 @@ export class CursorlessCommandComponentParser implements StepComponentParser {
33
37
this . tutorialId ,
34
38
arg ,
35
39
) ;
36
- const command = cloneDeep ( canonicalizeAndValidateCommand ( fixture . command ) ) ;
37
-
38
- transformPartialPrimitiveTargets (
39
- getPartialTargetDescriptors ( command . action ) ,
40
- ( target ) => {
41
- if ( target . mark ?. type !== "decoratedSymbol" ) {
42
- return target ;
43
- }
44
-
45
- const color = target . mark . symbolColor ;
46
-
47
- if ( this . hats . enabledHatStyles [ color ] === undefined ) {
48
- target . mark . symbolColor = Object . keys ( this . hats . enabledHatStyles ) [ 0 ] ;
49
- }
50
40
51
- return target ;
52
- } ,
41
+ const { command, initialState } = substituteMissingHats (
42
+ this . hats . enabledHatStyles ,
43
+ canonicalizeAndValidateCommand ( fixture . command ) ,
44
+ fixture . initialState ,
53
45
) ;
54
46
55
- if ( fixture . initialState . marks != null ) {
56
- fixture . initialState . marks = mapKeys (
57
- fixture . initialState . marks ,
58
- ( _value , key ) => {
59
- const { hatStyle, character } = splitKey ( key ) ;
60
- if ( this . hats . enabledHatStyles [ hatStyle ] === undefined ) {
61
- return getKey (
62
- Object . keys ( this . hats . enabledHatStyles ) [ 0 ] ,
63
- character ,
64
- ) ;
65
- }
66
- return key ;
67
- } ,
68
- ) ;
69
- }
70
-
71
47
return {
72
- initialState : fixture . initialState ,
48
+ initialState,
73
49
languageId : fixture . languageId ,
74
50
trigger : {
75
51
type : "command" ,
@@ -96,3 +72,60 @@ export class CursorlessCommandComponentParser implements StepComponentParser {
96
72
return spokenForm . spokenForms [ 0 ] ;
97
73
}
98
74
}
75
+
76
+ /**
77
+ * If the user has particular hats disabled, substitute them with hats that the
78
+ * user actually has enabled.
79
+ *
80
+ * We just pick the first hat in the list of available hats, but it would
81
+ * probably be better to pick a similar hat, eg if the hat is a colored hat,
82
+ * pick a different color.
83
+ *
84
+ * @param hats The IDE hats
85
+ * @param command The command to substitute hats in
86
+ * @param initialState The initial state snapshot to substitute hats in
87
+ * @returns A new command and initial state snapshot with hats substituted
88
+ */
89
+ function substituteMissingHats (
90
+ enabledHatStyles : HatStyleMap ,
91
+ command : CommandLatest ,
92
+ initialState : TestCaseSnapshot ,
93
+ ) {
94
+ command = cloneDeep ( command ) ;
95
+
96
+ // Update the hats in the command
97
+ transformPartialPrimitiveTargets (
98
+ getPartialTargetDescriptors ( command . action ) ,
99
+ ( target ) => {
100
+ if ( target . mark ?. type !== "decoratedSymbol" ) {
101
+ return target ;
102
+ }
103
+
104
+ const color = target . mark . symbolColor ;
105
+
106
+ if ( enabledHatStyles [ color ] === undefined ) {
107
+ target . mark . symbolColor = Object . keys ( enabledHatStyles ) [ 0 ] ;
108
+ }
109
+
110
+ return target ;
111
+ } ,
112
+ ) ;
113
+
114
+ // Update the hats in the initial state snapshot
115
+ if ( initialState . marks != null ) {
116
+ initialState = produce ( initialState , ( draft ) => {
117
+ draft . marks = mapKeys ( draft . marks , ( _value , key ) => {
118
+ const { hatStyle, character } = splitKey ( key ) ;
119
+ if ( enabledHatStyles [ hatStyle ] === undefined ) {
120
+ return getKey ( Object . keys ( enabledHatStyles ) [ 0 ] , character ) ;
121
+ }
122
+ return key ;
123
+ } ) ;
124
+ } ) ;
125
+ }
126
+
127
+ return {
128
+ command,
129
+ initialState,
130
+ } ;
131
+ }
0 commit comments