@@ -6,19 +6,18 @@ import which from 'which';
6
6
7
7
import * as vscode from 'vscode' ;
8
8
import { Logger } from '../services/logging' ;
9
- import { FortranDocumentSelector , resolveVariables } from '../lib/tools' ;
10
- import * as fg from 'fast-glob' ;
11
- import { glob } from 'glob' ;
9
+ import { EXTENSION_ID , FortranDocumentSelector , resolveVariables } from '../lib/tools' ;
12
10
import { arraysEqual } from '../lib/helper' ;
13
11
import { RescanLint } from './commands' ;
12
+ import { GlobPaths } from '../lib/glob-paths' ;
14
13
15
14
export class FortranLintingProvider {
16
15
constructor ( private logger : Logger = new Logger ( ) ) { }
17
16
18
17
private diagnosticCollection : vscode . DiagnosticCollection ;
19
18
private compiler : string ;
20
19
private compilerPath : string ;
21
- private cache = { includePaths : [ '' ] , globIncPaths : [ '' ] } ;
20
+ private pathCache = new Map < string , GlobPaths > ( ) ;
22
21
23
22
public provideCodeActions (
24
23
document : vscode . TextDocument ,
@@ -128,7 +127,10 @@ export class FortranLintingProvider {
128
127
...this . getLinterExtraArgs ( this . compiler ) ,
129
128
...this . getModOutputDir ( this . compiler ) ,
130
129
] ;
131
- const includePaths = this . getIncludePaths ( ) ;
130
+ const opt = 'linter.includePaths' ;
131
+ const includePaths = this . getGlobPathsFromSettings ( opt ) ;
132
+ this . logger . debug ( `[lint] glob paths:` , this . pathCache . get ( opt ) . globs ) ;
133
+ this . logger . debug ( `[lint] resolved paths:` , this . pathCache . get ( opt ) . paths ) ;
132
134
133
135
const extensionIndex = textDocument . fileName . lastIndexOf ( '.' ) ;
134
136
const fileNameWithoutExtension = textDocument . fileName . substring ( 0 , extensionIndex ) ;
@@ -179,61 +181,38 @@ export class FortranLintingProvider {
179
181
* for the `linter.includePaths` option. The results are stored in a cache
180
182
* to improve performance
181
183
*
184
+ * @param opt String representing a VS Code setting e.g. `linter.includePaths`
185
+ *
182
186
* @returns String Array of directories
183
187
*/
184
- private getIncludePaths ( ) : string [ ] {
185
- const config = vscode . workspace . getConfiguration ( 'fortran' ) ;
186
- let includePaths : string [ ] = config . get ( 'linter.includePaths' , [ ] ) ;
187
-
188
- // Check if we can use the cached results for the include directories no
189
- // need to evaluate the glob patterns everytime we call the linter
190
- // TODO: register command that forces re-linting
191
- // Not sure what the best approach for this one is?
192
- // Should I add a watcher to all the files under globIncPaths?
193
- // Should I add a watcher on the files under the workspace?
194
- if ( arraysEqual ( includePaths , this . cache [ 'includePaths' ] ) ) {
195
- return this . cache [ 'globIncPaths' ] ;
196
- }
197
-
198
- // Update our cache input
199
- this . cache [ 'includePaths' ] = includePaths ;
200
- // Output the original include paths
201
- if ( includePaths . length > 0 ) this . logger . debug ( `[lint] include:` , includePaths ) ;
202
- // Resolve internal variables and expand glob patterns
203
- const resIncludePaths = includePaths . map ( e => resolveVariables ( e ) ) ;
204
- // fast-glob cannot work with Windows paths
205
- includePaths = includePaths . map ( e => e . replace ( '/\\/g' , '/' ) ) ;
206
- // This needs to be after the resolvevariables since {} are used in globs
207
- try {
208
- const globIncPaths : string [ ] = fg . sync ( resIncludePaths , {
209
- onlyDirectories : true ,
210
- suppressErrors : false ,
211
- } ) ;
212
- // Update values in cache
213
- this . cache [ 'globIncPaths' ] = globIncPaths ;
214
- return globIncPaths ;
215
- // Try to recover from fast-glob failing due to EACCES using slower more
216
- // robust glob.
217
- } catch ( eacces ) {
218
- this . logger . warn ( `[lint] You lack read permissions for an include directory
219
- or more likely a glob match from the input 'includePaths' list. This can happen when
220
- using overly broad root level glob patters e.g. /usr/lib/** .
221
- No reason to worry. I will attempt to recover.
222
- You should consider adjusting your 'includePaths' if linting performance is slow.` ) ;
223
- this . logger . warn ( `[lint] ${ eacces . message } ` ) ;
188
+ private getGlobPathsFromSettings ( opt : string ) : string [ ] {
189
+ const config = vscode . workspace . getConfiguration ( EXTENSION_ID ) ;
190
+ const globPaths : string [ ] = config . get ( opt ) ;
191
+ // Initialise cache key and value if vscode option is not present
192
+ if ( ! this . pathCache . has ( opt ) ) {
193
+ this . logger . debug ( `[lint] Initialising cache for ${ opt } ` ) ;
224
194
try {
225
- const globIncPaths : string [ ] = [ ] ;
226
- for ( const i of resIncludePaths ) {
227
- // use '/' to match only directories and not files
228
- globIncPaths . push ( ...glob . sync ( i + '/' , { strict : false } ) ) ;
229
- }
230
- this . cache [ 'globIncPaths' ] = globIncPaths ;
231
- return globIncPaths ;
232
- // if we failed again then our includes are somehow wrong. Abort
195
+ this . pathCache . set ( opt , new GlobPaths ( globPaths ) ) ;
233
196
} catch ( error ) {
234
- this . logger . error ( `[lint] Include path glob resolution failed to recover: ${ error } ` ) ;
197
+ const msg = `[lint] Error initialising cache for ${ opt } ` ;
198
+ this . logger . error ( msg , error ) ;
199
+ vscode . window . showErrorMessage ( `${ msg } : ${ error } ` ) ;
235
200
}
236
201
}
202
+ // Check if cache is valid, and if so return cached value
203
+ if ( arraysEqual ( globPaths , this . pathCache . get ( opt ) . globs ) ) {
204
+ return this . pathCache . get ( opt ) . paths ;
205
+ }
206
+ // Update cache and return new values
207
+ try {
208
+ this . pathCache . get ( opt ) . update ( globPaths ) ;
209
+ } catch ( error ) {
210
+ const msg = `[lint] Error initialising cache for ${ opt } ` ;
211
+ this . logger . error ( msg , error ) ;
212
+ vscode . window . showErrorMessage ( `${ msg } : ${ error } ` ) ;
213
+ }
214
+ this . logger . debug ( `[lint] ${ opt } changed, updating cache` ) ;
215
+ return this . pathCache . get ( opt ) . paths ;
237
216
}
238
217
239
218
/**
@@ -543,10 +522,12 @@ export class FortranLintingProvider {
543
522
* Regenerate the cache for the include files paths of the linter
544
523
*/
545
524
private rescanLinter ( ) {
525
+ const opt = 'linter.includePaths' ;
546
526
this . logger . debug ( `[lint] Resetting linter include paths cache` ) ;
547
- this . logger . debug ( `[lint] Current linter include paths cache:` , this . cache [ 'includePaths' ] ) ;
548
- this . cache [ 'includePaths' ] = [ ] ;
549
- this . getIncludePaths ( ) ;
550
- this . logger . debug ( `[lint] New linter include paths cache:` , this . cache [ 'includePaths' ] ) ;
527
+ this . logger . debug ( `[lint] Current linter include paths cache:` , this . pathCache . get ( opt ) . globs ) ;
528
+ this . pathCache . set ( opt , new GlobPaths ( ) ) ;
529
+ this . getGlobPathsFromSettings ( opt ) ;
530
+ this . logger . debug ( `[lint] glob paths:` , this . pathCache . get ( opt ) . globs ) ;
531
+ this . logger . debug ( `[lint] resolved paths:` , this . pathCache . get ( opt ) . paths ) ;
551
532
}
552
533
}
0 commit comments