@@ -10,6 +10,7 @@ import * as path from 'path'
10
10
import { globDirs , isUntitledScheme , normalizeVSCodeUri } from '../utilities/vsCodeUtils'
11
11
import { Settings } from '../settings'
12
12
import { once } from '../utilities/functionUtils'
13
+ import { Timeout } from '../utilities/timeoutUtils'
13
14
14
15
/**
15
16
* Prevent `findFiles()` from recursing into these directories.
@@ -60,12 +61,18 @@ const getExcludePatternOnce = once(getExcludePattern)
60
61
* for CFN templates among other things. WatchedFiles holds a list of pairs of
61
62
* the absolute path to the file or "untitled:" URI along with a transform of it that is useful for
62
63
* where it is used. For example, for templates, it parses the template and stores it.
64
+ *
65
+ * Initialize the registry by adding watch patterns and excluded patterns via
66
+ * `addWatchPatterns`, `watchUntitledFiles`, and `addExcludedPattern` and then
67
+ * calling the `rebuild` function to begin registering files.
63
68
*/
64
69
export abstract class WatchedFiles < T > implements vscode . Disposable {
70
+ private isWatching : boolean = false
65
71
private readonly disposables : vscode . Disposable [ ] = [ ]
66
72
private _isDisposed : boolean = false
67
73
private readonly globs : vscode . GlobPattern [ ] = [ ]
68
74
private readonly excludedFilePatterns : RegExp [ ] = [ ]
75
+ private watchingUntitledFiles : boolean = false
69
76
private readonly registryData : Map < string , T > = new Map < string , T > ( )
70
77
71
78
/**
@@ -93,7 +100,7 @@ export abstract class WatchedFiles<T> implements vscode.Disposable {
93
100
* Creates watchers for each glob across all opened workspace folders (or see below to
94
101
* watch _outside_ the workspace).
95
102
*
96
- * Fails if the watcher is disposed, or if globs have already been set ;
103
+ * Fails if the watcher is disposed, or if the watcher has been initialized through the `rebuild` function ;
97
104
* enforce setting once to reduce rebuilds looping through all existing globs
98
105
*
99
106
* (since vscode 1.64):
@@ -120,12 +127,12 @@ export abstract class WatchedFiles<T> implements vscode.Disposable {
120
127
*
121
128
* @param globs Patterns to match against (across all opened workspace folders)
122
129
*/
123
- public async addWatchPatterns ( globs : vscode . GlobPattern [ ] ) : Promise < void > {
130
+ public addWatchPatterns ( globs : vscode . GlobPattern [ ] ) {
124
131
if ( this . _isDisposed ) {
125
132
throw new Error ( `${ this . name } : manager has already been disposed!` )
126
133
}
127
- if ( this . globs . length > 0 ) {
128
- throw new Error ( `${ this . name } : watch patterns have already been established ` )
134
+ if ( this . isWatching ) {
135
+ throw new Error ( `${ this . name } : cannot add watch patterns after watcher has begun watching ` )
129
136
}
130
137
for ( const glob of globs ) {
131
138
if ( typeof glob === 'string' && ! vscode . workspace . workspaceFolders ?. [ 0 ] ) {
@@ -136,15 +143,14 @@ export abstract class WatchedFiles<T> implements vscode.Disposable {
136
143
const watcher = vscode . workspace . createFileSystemWatcher ( glob )
137
144
this . addWatcher ( watcher )
138
145
}
139
-
140
- await this . rebuild ( )
141
146
}
142
147
143
148
/**
144
149
* Create a special watcher that operates only on untitled files.
145
150
* To "watch" the in-memory contents of an untitled:/ file we just subscribe to `onDidChangeTextDocument`
146
151
*/
147
- public async watchUntitledFiles ( ) {
152
+ public watchUntitledFiles ( ) {
153
+ this . watchingUntitledFiles = true
148
154
this . disposables . push (
149
155
vscode . workspace . onDidChangeTextDocument ( ( event : vscode . TextDocumentChangeEvent ) => {
150
156
if ( isUntitledScheme ( event . document . uri ) ) {
@@ -162,13 +168,14 @@ export abstract class WatchedFiles<T> implements vscode.Disposable {
162
168
/**
163
169
* Adds a regex pattern to ignore paths containing the pattern
164
170
*/
165
- public async addExcludedPattern ( pattern : RegExp ) : Promise < void > {
171
+ public addExcludedPattern ( pattern : RegExp ) {
166
172
if ( this . _isDisposed ) {
167
173
throw new Error ( `${ this . name } : manager has already been disposed!` )
168
174
}
175
+ if ( this . isWatching ) {
176
+ throw new Error ( `${ this . name } : cannot add excluded patterns after watcher has begun watching` )
177
+ }
169
178
this . excludedFilePatterns . push ( pattern )
170
-
171
- await this . rebuild ( )
172
179
}
173
180
174
181
/**
@@ -275,26 +282,37 @@ export abstract class WatchedFiles<T> implements vscode.Disposable {
275
282
}
276
283
277
284
/**
278
- * Rebuilds registry using current glob and exclusion patterns.
279
- * All functionality is currently internal to class, but can be made public if we want a manual "refresh" button
285
+ * Builds/rebuilds registry using current glob and exclusion patterns. ***Necessary to init registry***.
286
+ *
287
+ * @param cancellationTimeout Optional timeout that can trigger canceling additional loading on completion (manual or timed)
280
288
*/
281
- public async rebuild ( ) : Promise < void > {
289
+ public async rebuild ( cancellationTimeout ?: Timeout ) : Promise < void > {
290
+ let skips = 0
291
+ this . isWatching = true
282
292
this . reset ( )
283
293
284
294
const exclude = getExcludePatternOnce ( )
285
- for ( const glob of this . globs ) {
295
+ getLogger ( ) . info ( `${ this . name } : Building registry with the following criteria: ${ this . outputPatterns ( ) } ` )
296
+ for ( let i = 0 ; i < this . globs . length && ! cancellationTimeout ?. completed ; i ++ ) {
297
+ const glob = this . globs [ i ]
286
298
try {
287
299
const found = await vscode . workspace . findFiles ( glob , exclude )
288
- for ( const item of found ) {
289
- await this . addItem ( item , true )
300
+ for ( let j = 0 ; j < found . length && ! cancellationTimeout ?. completed ; j ++ ) {
301
+ await this . addItem ( found [ j ] , true )
290
302
}
291
303
} catch ( e ) {
304
+ // file not processable
305
+ skips ++
292
306
const err = e as Error
293
- if ( err . name !== 'Canceled' ) {
294
- getLogger ( ) . error ( 'watchedFiles: findFiles("%s", "%s"): %s' , glob , exclude , err . message )
295
- }
307
+ getLogger ( ) . error ( `${ this . name } : watchedFiles: findFiles("%s", "%s"): %s` , glob , exclude , err . message )
296
308
}
297
309
}
310
+ getLogger ( ) . info (
311
+ `${ this . name } : Registered %s items%s%s` ,
312
+ this . registryData . size ,
313
+ cancellationTimeout ?. completed ? ' (cancelled)' : '' ,
314
+ skips > 0 ? `, skipped ${ skips } entries` : ''
315
+ )
298
316
}
299
317
300
318
/**
@@ -340,6 +358,18 @@ export abstract class WatchedFiles<T> implements vscode.Disposable {
340
358
throw new Error ( `FileRegistry: path is relative when it should be absolute: ${ pathAsString } ` )
341
359
}
342
360
}
361
+
362
+ private outputPatterns ( ) : string {
363
+ const watch = this . globs . map ( cur => cur . toString ( ) )
364
+ if ( this . watchingUntitledFiles ) {
365
+ watch . push ( 'Untitled Files' )
366
+ }
367
+ const exclude = this . excludedFilePatterns . map ( cur => cur . toString ( ) )
368
+
369
+ return `${ watch . length > 0 ? `Watching ${ watch . join ( ', ' ) } ` : '' } ${
370
+ exclude . length > 0 ? `, Excluding ${ exclude . join ( ', ' ) } ` : ''
371
+ } `
372
+ }
343
373
}
344
374
345
375
export class NoopWatcher extends WatchedFiles < any > {
0 commit comments