7
7
} from "@cursorless/common" ;
8
8
import { VscodeApi } from "@cursorless/vscode-common" ;
9
9
import { cloneDeep , isEqual } from "lodash" ;
10
- import * as fs from "node:fs " ;
10
+ import * as fs from "fs/promises " ;
11
11
import * as path from "node:path" ;
12
12
import * as vscode from "vscode" ;
13
13
import { vscodeGetConfigurationString } from "../VscodeConfiguration" ;
@@ -24,6 +24,7 @@ import {
24
24
defaultShapeAdjustments ,
25
25
} from "./shapeAdjustments" ;
26
26
import { performPr1868ShapeUpdateInit } from "./performPr1868ShapeUpdateInit" ;
27
+ import { TextDecoder } from "util" ;
27
28
28
29
const CURSORLESS_HAT_SHAPES_SUFFIX = ".svg" ;
29
30
@@ -65,7 +66,8 @@ export default class VscodeHatRenderer {
65
66
private notifier : Notifier < [ ] > = new Notifier ( ) ;
66
67
private lastSeenEnabledHatStyles : ExtendedHatStyleMap = { } ;
67
68
private hatsDirWatcherDisposable ?: vscode . Disposable ;
68
- private hatShapeOverrides : Record < string , string > = { } ;
69
+ private hatShapeOverrides : Record < string , vscode . Uri > = { } ;
70
+ private decoder : TextDecoder = new TextDecoder ( "utf-8" ) ;
69
71
70
72
constructor (
71
73
private vscodeApi : VscodeApi ,
@@ -133,10 +135,13 @@ export default class VscodeHatRenderer {
133
135
if ( hatsDir ) {
134
136
await this . updateShapeOverrides ( hatsDir ) ;
135
137
136
- if ( fs . existsSync ( hatsDir ) ) {
138
+ try {
139
+ await fs . access ( hatsDir ) ;
137
140
this . hatsDirWatcherDisposable = watchDir ( hatsDir , ( ) =>
138
141
this . updateShapeOverrides ( hatsDir ) ,
139
142
) ;
143
+ } catch ( e ) {
144
+ console . error ( "cannot watch hatsDir" , hatsDir , e ) ;
140
145
}
141
146
} else {
142
147
this . hatShapeOverrides = { } ;
@@ -150,7 +155,10 @@ export default class VscodeHatRenderer {
150
155
151
156
for ( const file of files ) {
152
157
const name = path . basename ( file , CURSORLESS_HAT_SHAPES_SUFFIX ) ;
153
- this . hatShapeOverrides [ name ] = file ;
158
+ this . hatShapeOverrides [ name ] = vscode . Uri . from ( {
159
+ scheme : "file" ,
160
+ path : file ,
161
+ } ) ;
154
162
}
155
163
156
164
await this . recomputeDecorations ( ) ;
@@ -207,35 +215,41 @@ export default class VscodeHatRenderer {
207
215
) ;
208
216
209
217
const hatSvgMap = Object . fromEntries (
210
- HAT_SHAPES . map ( ( shape ) => {
211
- const { sizeAdjustment = 0 , verticalOffset = 0 } =
212
- defaultShapeAdjustments [ shape ] ;
213
-
214
- const {
215
- sizeAdjustment : userIndividualSizeAdjustment = 0 ,
216
- verticalOffset : userIndividualVerticalOffset = 0 ,
217
- } = userIndividualAdjustments [ shape ] ?? { } ;
218
-
219
- const scaleFactor =
220
- 1 +
221
- ( sizeAdjustment + userSizeAdjustment + userIndividualSizeAdjustment ) /
218
+ await Promise . all (
219
+ HAT_SHAPES . map ( async ( shape ) => {
220
+ const { sizeAdjustment = 0 , verticalOffset = 0 } =
221
+ defaultShapeAdjustments [ shape ] ;
222
+
223
+ const {
224
+ sizeAdjustment : userIndividualSizeAdjustment = 0 ,
225
+ verticalOffset : userIndividualVerticalOffset = 0 ,
226
+ } = userIndividualAdjustments [ shape ] ?? { } ;
227
+
228
+ const scaleFactor =
229
+ 1 +
230
+ ( sizeAdjustment +
231
+ userSizeAdjustment +
232
+ userIndividualSizeAdjustment ) /
233
+ 100 ;
234
+
235
+ const finalVerticalOffsetEm =
236
+ ( verticalOffset +
237
+ userVerticalOffset +
238
+ userIndividualVerticalOffset ) /
222
239
100 ;
223
240
224
- const finalVerticalOffsetEm =
225
- ( verticalOffset + userVerticalOffset + userIndividualVerticalOffset ) /
226
- 100 ;
227
-
228
- return [
229
- shape ,
230
- this . processSvg (
231
- this . fontMeasurements ,
241
+ return [
232
242
shape ,
233
- scaleFactor ,
234
- defaultShapeAdjustments [ shape ] . strokeFactor ?? 1 ,
235
- finalVerticalOffsetEm ,
236
- ) ,
237
- ] ;
238
- } ) ,
243
+ await this . processSvg (
244
+ this . fontMeasurements ,
245
+ shape ,
246
+ scaleFactor ,
247
+ defaultShapeAdjustments [ shape ] . strokeFactor ?? 1 ,
248
+ finalVerticalOffsetEm ,
249
+ ) ,
250
+ ] ;
251
+ } ) ,
252
+ ) ,
239
253
) ;
240
254
241
255
this . decorationMap = Object . fromEntries (
@@ -373,22 +387,24 @@ export default class VscodeHatRenderer {
373
387
* @param hatVerticalOffsetEm How far off top of characters should hats be
374
388
* @returns An object with the new SVG and its measurements
375
389
*/
376
- private processSvg (
390
+ private async processSvg (
377
391
fontMeasurements : FontMeasurements ,
378
392
shape : HatShape ,
379
393
scaleFactor : number ,
380
394
strokeFactor : number ,
381
395
hatVerticalOffsetEm : number ,
382
- ) : SvgInfo | null {
396
+ ) : Promise < SvgInfo | null > {
383
397
const iconPath =
384
398
this . hatShapeOverrides [ shape ] ??
385
- path . join (
386
- this . extensionContext . extensionPath ,
399
+ vscode . Uri . joinPath (
400
+ this . extensionContext . extensionUri ,
387
401
"images" ,
388
402
"hats" ,
389
403
`${ shape } .svg` ,
390
404
) ;
391
- const rawSvg = fs . readFileSync ( iconPath , "utf8" ) ;
405
+ const rawSvg = this . decoder . decode (
406
+ await vscode . workspace . fs . readFile ( iconPath ) ,
407
+ ) ;
392
408
const { characterWidth, characterHeight, fontSize } = fontMeasurements ;
393
409
394
410
if ( ! this . checkSvg ( shape , rawSvg ) ) {
0 commit comments