1
1
import { readFile , stat } from "fs/promises" ;
2
2
import { cloneDeep , max , merge } from "lodash" ;
3
3
import { join } from "path" ;
4
- import { workspace } from "vscode" ;
4
+ import { window , workspace } from "vscode" ;
5
5
import { walkFiles } from "../testUtil/walkAsync" ;
6
6
import { Snippet , SnippetMap } from "../typings/snippet" ;
7
7
import { Graph } from "../typings/Types" ;
8
8
import { mergeStrict } from "../util/object" ;
9
+ import { CURSORLESS_SNIPPETS_SUFFIX } from "./constants" ;
9
10
10
11
const SNIPPET_DIR_REFRESH_INTERVAL_MS = 1000 ;
11
12
@@ -34,6 +35,8 @@ export class Snippets {
34
35
*/
35
36
private maxSnippetMtimeMs : number = - 1 ;
36
37
38
+ private shownErrorMessageForDir : string | null | undefined = null ;
39
+
37
40
constructor ( private graph : Graph ) {
38
41
this . updateUserSnippetsPath ( ) ;
39
42
@@ -63,7 +66,7 @@ export class Snippets {
63
66
async init ( ) {
64
67
const extensionPath = this . graph . extensionContext . extensionPath ;
65
68
const snippetsDir = join ( extensionPath , "cursorless-snippets" ) ;
66
- const snippetFiles = await walkFiles ( snippetsDir ) ;
69
+ const snippetFiles = await getSnippetPaths ( snippetsDir ) ;
67
70
this . coreSnippets = mergeStrict (
68
71
...( await Promise . all (
69
72
snippetFiles . map ( async ( path ) =>
@@ -98,9 +101,25 @@ export class Snippets {
98
101
}
99
102
100
103
async updateUserSnippets ( ) {
101
- const snippetFiles = this . userSnippetsDir
102
- ? await walkFiles ( this . userSnippetsDir )
103
- : [ ] ;
104
+ let snippetFiles : string [ ] ;
105
+ try {
106
+ snippetFiles = this . userSnippetsDir
107
+ ? await getSnippetPaths ( this . userSnippetsDir )
108
+ : [ ] ;
109
+ } catch ( err ) {
110
+ if ( this . shownErrorMessageForDir !== this . userSnippetsDir ) {
111
+ window . showErrorMessage (
112
+ `Error with cursorless snippets dir "${ this . userSnippetsDir } ": ${
113
+ ( err as Error ) . message
114
+ } `
115
+ ) ;
116
+ }
117
+
118
+ this . shownErrorMessageForDir = this . userSnippetsDir ;
119
+ return ;
120
+ }
121
+
122
+ this . shownErrorMessageForDir = null ;
104
123
105
124
const maxSnippetMtime =
106
125
max (
@@ -117,9 +136,24 @@ export class Snippets {
117
136
118
137
this . userSnippets = mergeStrict (
119
138
...( await Promise . all (
120
- snippetFiles . map ( async ( path ) =>
121
- JSON . parse ( await readFile ( path , "utf8" ) )
122
- )
139
+ snippetFiles . map ( async ( path ) => {
140
+ try {
141
+ const content = await readFile ( path , "utf8" ) ;
142
+
143
+ if ( content . length === 0 ) {
144
+ return { } ;
145
+ }
146
+
147
+ return JSON . parse ( content ) ;
148
+ } catch ( err ) {
149
+ window . showErrorMessage (
150
+ `Error with cursorless snippets file "${ path } ": ${
151
+ ( err as Error ) . message
152
+ } `
153
+ ) ;
154
+ return { } ;
155
+ }
156
+ } )
123
157
) )
124
158
) ;
125
159
@@ -185,3 +219,9 @@ export class Snippets {
185
219
return this . mergedSnippets [ snippetName ] ;
186
220
}
187
221
}
222
+
223
+ async function getSnippetPaths ( snippetsDir : string ) {
224
+ return ( await walkFiles ( snippetsDir ) ) . filter ( ( path ) =>
225
+ path . endsWith ( CURSORLESS_SNIPPETS_SUFFIX )
226
+ ) ;
227
+ }
0 commit comments