1
1
import { createHighlighter } from "./createHighlighter" ;
2
2
import type { BundledLanguage } from "shiki" ;
3
- import type { Lang , StepNameType , ExtendedTestCaseSnapshot , DataFixture } from "./types" ;
4
- import type { Command , CommandLatest , TestCaseFixture } from "@cursorless/common" ;
3
+ import type { StepNameType , ExtendedTestCaseSnapshot , DataFixture } from "./types" ;
5
4
6
5
import { createDecorations } from "./helpers" ;
7
6
@@ -12,143 +11,118 @@ import { createDecorations } from "./helpers";
12
11
* @returns {Promise<{ before: string; during: string; after: string }> } A promise that resolves to the generated HTML content for each step.
13
12
*/
14
13
export async function generateHtml ( data : DataFixture ) {
15
- return new HTMLGenerator ( data ) . generateAll ( )
14
+ return createHtmlGenerator ( data ) . generateAll ( ) ;
16
15
}
17
16
18
17
const highlighter = createHighlighter ( ) ;
19
18
20
- class HTMLGenerator {
21
- private testCaseStates : {
22
- before : ExtendedTestCaseSnapshot | undefined ;
23
- during : ExtendedTestCaseSnapshot | undefined ;
24
- after : ExtendedTestCaseSnapshot | undefined ;
25
- }
26
- private lang : Lang ;
27
- private command ?: CommandLatest | Command ;
28
- private raw : TestCaseFixture ;
29
-
30
- constructor ( data : DataFixture ) {
31
- const { languageId, command } = data ;
32
- this . lang = languageId as BundledLanguage ;
33
- this . command = command ; // Optional command parameter
34
- this . raw = data
35
- this . testCaseStates = {
36
- before : data . initialState ,
37
- during : {
38
- ...(
39
- /**
40
- * Spread the document state with more lines (finalState vs initialState),
41
- * so Shiki decorations stay in bounds and don't go out of range.
42
- */
43
- data . finalState &&
44
- ( data . finalState . documentContents ?. split ( "\n" ) . length > data . initialState . documentContents ?. split ( "\n" ) . length )
45
- ? data . finalState
46
- : data . initialState
47
- ) ,
48
- ...data . ide ,
49
- finalStateMarkHelpers : {
50
- thatMark : data ?. finalState ?. thatMark ,
51
- sourceMark : data ?. finalState ?. sourceMark
52
- }
53
- } ,
54
- after : data . finalState
55
- }
56
- }
57
-
58
- async generate ( stepName : StepNameType ) {
59
- const state = this . testCaseStates [ stepName ]
19
+ function createHtmlGenerator ( data : DataFixture ) {
20
+ const lang = data . languageId as BundledLanguage ;
21
+ const command = data . command ;
22
+ const raw = data ;
23
+ const testCaseStates = {
24
+ before : data . initialState ,
25
+ during : {
26
+ ...(
27
+ /**
28
+ * Spread the document state with more lines (finalState vs initialState),
29
+ * so Shiki decorations stay in bounds and don't go out of range.
30
+ */
31
+ data . finalState &&
32
+ ( data . finalState . documentContents ?. split ( "\n" ) . length > data . initialState . documentContents ?. split ( "\n" ) . length )
33
+ ? data . finalState
34
+ : data . initialState
35
+ ) ,
36
+ ...data . ide ,
37
+ finalStateMarkHelpers : {
38
+ thatMark : data ?. finalState ?. thatMark ,
39
+ sourceMark : data ?. finalState ?. sourceMark
40
+ }
41
+ } ,
42
+ after : data . finalState
43
+ } ;
60
44
45
+ async function generate ( stepName : StepNameType ) {
46
+ const state = testCaseStates [ stepName ] ;
61
47
if ( ! state ) {
62
- console . error ( `Error in ${ stepName } ${ this . raw . command . spokenForm } ` )
63
- return "Error"
48
+ console . error ( `Error in ${ stepName } ${ raw . command . spokenForm } ` ) ;
49
+ return "Error" ;
64
50
}
65
-
66
- const decorations = await this . getDecorations ( state ) ;
67
-
68
- const { documentContents } = state
69
-
70
- const htmlArray : string [ ] = [ ]
51
+ const decorations = await getDecorations ( state ) ;
52
+ const { documentContents } = state ;
53
+ const htmlArray : string [ ] = [ ] ;
71
54
let codeBody ;
72
-
73
55
const errorLevels = [
74
56
"excludes thatMarks sourceMarks selectionRanges ideFlashes" ,
75
57
"excludes thatMarks sourceMarks selectionRanges" ,
76
58
"excludes thatMarks sourceMarks" ,
77
59
"excludes thatMarks" ,
78
60
"success" ,
79
- ]
80
-
81
- let errorLevel = errorLevels . length - 1
82
-
61
+ ] ;
62
+ let errorLevel = errorLevels . length - 1 ;
83
63
for ( let i = decorations . length - 1 ; i >= 0 ; i -- ) {
84
64
const fallbackDecoration = decorations . slice ( 0 , i ) . flat ( ) ;
85
- errorLevel = i
65
+ errorLevel = i ;
86
66
try {
87
67
const marker = await highlighter ;
88
68
const options = {
89
69
theme : "css-variables" ,
90
- lang : this . lang ,
70
+ lang,
91
71
decorations : fallbackDecoration
92
72
} ;
93
73
codeBody = marker . codeToHtml ( documentContents , options ) ;
94
- htmlArray . push ( codeBody )
95
- break ; // Exit loop if successful
74
+ htmlArray . push ( codeBody ) ;
75
+ break ;
96
76
} catch ( error ) {
97
- console . warn ( `"Failed with decorations level ${ i } :"` , this . command ) ;
77
+ console . warn ( `"Failed with decorations level ${ i } :"` , command ) ;
98
78
console . warn ( fallbackDecoration , error ) ;
99
- // Continue to the next fallback level
100
79
}
101
80
}
102
-
103
81
if ( ! codeBody ) {
104
82
console . error ( "All fallback levels failed. Unable to generate code body." ) ;
105
- codeBody = "" ; // Provide a default empty string or handle as needed
83
+ codeBody = "" ;
106
84
}
107
-
108
- let clipboardRendered = ""
85
+ let clipboardRendered = "" ;
109
86
if ( state . clipboard ) {
110
- clipboardRendered = `<pre><code>clipboard: ${ state . clipboard } </pre></code>`
87
+ clipboardRendered = `<pre><code>clipboard: ${ state . clipboard } </pre></code>` ;
111
88
if ( clipboardRendered !== "" ) {
112
- htmlArray . push ( clipboardRendered )
89
+ htmlArray . push ( clipboardRendered ) ;
113
90
}
114
91
}
115
-
116
- let error = ""
92
+ let error = "" ;
117
93
if ( errorLevel !== errorLevels . length - 1 ) {
118
- error = errorLevels [ errorLevel ]
119
- const errorRendered = `<pre><code>Omitted due to errors: ${ error } </pre></code>`
120
- htmlArray . push ( errorRendered )
94
+ error = errorLevels [ errorLevel ] ;
95
+ const errorRendered = `<pre><code>Omitted due to errors: ${ error } </pre></code>` ;
96
+ htmlArray . push ( errorRendered ) ;
121
97
}
122
- return { html : htmlArray . join ( "" ) , data : [ decorations ] }
98
+ return { html : htmlArray . join ( "" ) , data : [ decorations ] } ;
123
99
}
124
100
125
- async generateAll ( ) {
126
-
127
- const output = {
128
- before : await this . generate ( "before" ) ,
129
- during : await this . generate ( "during" ) ,
130
- after : await this . generate ( "after" ) ,
131
- }
132
- return output
101
+ async function generateAll ( ) {
102
+ return {
103
+ before : await generate ( "before" ) ,
104
+ during : await generate ( "during" ) ,
105
+ after : await generate ( "after" ) ,
106
+ } ;
133
107
}
134
108
135
- async getDecorations ( testCaseState : ExtendedTestCaseSnapshot ) {
136
- const { messages, flashes, highlights, finalStateMarkHelpers } = testCaseState
137
-
138
- const potentialMarks = testCaseState . marks || { }
139
- const lines = testCaseState . documentContents . split ( "\n" )
109
+ async function getDecorations ( testCaseState : ExtendedTestCaseSnapshot ) {
110
+ const { messages, flashes, highlights, finalStateMarkHelpers } = testCaseState ;
111
+ const potentialMarks = testCaseState . marks || { } ;
112
+ const lines = testCaseState . documentContents . split ( "\n" ) ;
140
113
const obj = {
141
114
marks : potentialMarks ,
142
115
ide : { messages, flashes, highlights } ,
143
- command : this . command ,
116
+ command,
144
117
lines,
145
118
selections : testCaseState . selections ,
146
119
thatMark : testCaseState . thatMark ,
147
120
sourceMark : testCaseState . sourceMark ,
148
121
finalStateMarkHelpers
149
- }
150
-
151
- const decorations = createDecorations ( obj )
152
- return decorations
122
+ } ;
123
+ const decorations = createDecorations ( obj ) ;
124
+ return decorations ;
153
125
}
126
+
127
+ return { generate, generateAll, getDecorations } ;
154
128
}
0 commit comments