@@ -96,6 +96,7 @@ export interface FolderInfo {
9696}
9797
9898interface SourceRootInfo extends FolderInfo {
99+ isValid : ( ) => boolean ;
99100 fileWatcher : FileWatcher ;
100101 fileGroups : ProjectFileGroup [ ] ;
101102 incList : string [ ] ;
@@ -383,6 +384,7 @@ class SourceRootList implements SourceProvider {
383384 this . project = _project ;
384385 this . _event = new events . EventEmitter ( ) ;
385386 this . srcFolderMaps = new Map ( ) ;
387+ FileWatcher . on ( 'rename' , f => this . onFolderRenamed ( this . getSourceRootKeyByAbspath ( f . path ) , f ) ) ;
386388 }
387389
388390 isAutoSearchObjectFile ( ) : boolean {
@@ -400,13 +402,7 @@ class SourceRootList implements SourceProvider {
400402 const srcFolders = this . project . GetConfiguration ( ) . config . srcDirs ;
401403 srcFolders . forEach ( ( path ) => {
402404 const f = new File ( path ) ;
403- if ( f . IsDir ( ) ) {
404- const key : string = this . getRelativePath ( path ) ;
405- const watcher = platform . createSafetyFileWatcher ( f , true ) . Watch ( ) ;
406- watcher . on ( 'error' , ( err ) => GlobalEvent . emit ( 'msg' , ExceptionToMessage ( err , 'Hidden' ) ) ) ;
407- watcher . OnRename = ( file ) => this . onFolderRenamed ( key , file ) ;
408- this . srcFolderMaps . set ( key , this . newSourceInfo ( key , watcher ) ) ;
409- }
405+ this . _add ( f ) ;
410406 } ) ;
411407
412408 // update all
@@ -417,23 +413,24 @@ class SourceRootList implements SourceProvider {
417413 if ( ! notEmitEvt ) { this . emit ( 'dataChanged' , 'dataChanged' ) ; }
418414 }
419415
416+ private _add ( dir : File ) : SourceRootInfo {
417+ const key : string = this . getSourceRootKeyByAbspath ( dir . path ) ;
418+ const watcher = platform . createSafetyFileWatcher ( dir , true ) ;
419+ watcher . on ( 'error' , ( err ) => GlobalEvent . emit ( 'globalLog' , ExceptionToMessage ( err , 'Warning' ) ) ) ;
420+ const sourceInfo = this . newSourceInfo ( key , watcher ) ;
421+ this . srcFolderMaps . set ( key , sourceInfo ) ;
422+ return sourceInfo ;
423+ }
424+
420425 add ( absPath : string ) : boolean {
421- const f = new File ( absPath ) ;
422- if ( f . IsDir ( ) ) {
423- const key : string = this . getRelativePath ( absPath ) ;
424- const watcher = platform . createSafetyFileWatcher ( f , true ) . Watch ( ) ;
425- watcher . on ( 'error' , ( err ) => GlobalEvent . emit ( 'msg' , ExceptionToMessage ( err , 'Hidden' ) ) ) ;
426- watcher . OnRename = ( file ) => this . onFolderRenamed ( key , file ) ;
427- const sourceInfo = this . newSourceInfo ( key , watcher ) ;
428- this . srcFolderMaps . set ( key , sourceInfo ) ;
429- this . updateFolder ( sourceInfo ) ;
430- return true ;
431- }
432- return false ;
426+ const dir = new File ( absPath ) ;
427+ const sourceInfo = this . _add ( dir ) ;
428+ this . updateFolder ( sourceInfo ) ;
429+ return true ;
433430 }
434431
435432 remove ( absPath : string ) : boolean {
436- const key = this . getRelativePath ( absPath ) ;
433+ const key = this . getSourceRootKeyByAbspath ( absPath ) ;
437434 return this . removeByKey ( key ) ;
438435 }
439436
@@ -470,7 +467,7 @@ class SourceRootList implements SourceProvider {
470467 if ( rootSrcUpdateList . length > 0 ) {
471468
472469 for ( const rootInfo of rootSrcUpdateList ) {
473- if ( rootInfo . fileWatcher . file . IsDir ( ) ) {
470+ if ( rootInfo . isValid ( ) ) {
474471 this . updateFolder ( rootInfo , [ targetDir ] ) ;
475472 }
476473 }
@@ -527,6 +524,26 @@ class SourceRootList implements SourceProvider {
527524 return res ;
528525 }
529526
527+ isIncludes ( abspath : string ) : boolean {
528+
529+ if ( ! File . isAbsolute ( abspath ) ) {
530+ abspath = this . project . toAbsolutePath ( abspath ) ;
531+ }
532+
533+ const unixPath = File . ToUnixPath ( abspath ) ;
534+
535+ for ( const rootInfo of this . srcFolderMaps . values ( ) ) {
536+ const unixRootPath = File . ToUnixPath ( rootInfo . fileWatcher . file . path ) ;
537+ const unixRootRealPath = File . ToUnixPath ( platform . realpathSync ( rootInfo . fileWatcher . file . path ) ) ;
538+ if ( unixPath . startsWith ( unixRootPath ) ||
539+ unixPath . startsWith ( unixRootRealPath ) ) {
540+ return true ;
541+ }
542+ }
543+
544+ return false ;
545+ }
546+
530547 forceUpdateAllFolders ( ) {
531548 for ( const info of this . srcFolderMaps . values ( ) ) {
532549 this . updateFolder ( info ) ;
@@ -537,13 +554,8 @@ class SourceRootList implements SourceProvider {
537554 forceUpdateFolder ( rePath : string ) {
538555 const rootInfo = this . srcFolderMaps . get ( rePath ) ;
539556 if ( rootInfo ) {
540- if ( rootInfo . fileWatcher . file . IsDir ( ) ) {
541- this . updateFolder ( rootInfo ) ;
542- this . emit ( 'dataChanged' , 'folderChanged' ) ;
543- } else {
544- this . removeByKey ( rePath ) ;
545- this . emit ( 'dataChanged' , 'dataChanged' ) ;
546- }
557+ this . updateFolder ( rootInfo ) ;
558+ this . emit ( 'dataChanged' , 'folderChanged' ) ;
547559 }
548560 }
549561
@@ -554,42 +566,51 @@ class SourceRootList implements SourceProvider {
554566 this . _event . emit ( event , arg ) ;
555567 }
556568
557- private getRelativePath ( abspath : string ) : string {
569+ private getSourceRootKeyByAbspath ( abspath : string ) : string {
558570 return this . project . toRelativePath ( abspath ) ;
559571 }
560572
561573 private newSourceInfo ( displayName : string , watcher : FileWatcher ) : SourceRootInfo {
562574 return {
563575 displayName : displayName ,
564576 fileWatcher : watcher ,
577+ isValid : ( ) => watcher . file . IsDir ( ) ,
565578 needUpdate : false ,
566579 fileGroups : [ ] ,
567580 incList : [ ]
568581 } ;
569582 }
570583
571- private removeByKey ( key : string ) : boolean {
584+ private disposeWatcher ( key : string ) : void {
572585 this . srcFolderMaps . get ( key ) ?. fileWatcher . Close ( ) ;
586+ }
587+
588+ private removeByKey ( key : string ) : boolean {
589+ this . disposeWatcher ( key ) ;
573590 return this . srcFolderMaps . delete ( key ) ;
574591 }
575592
576593 private onFolderRenamed ( folderKey : string , targetFile : File ) {
577594 const rootInfo = this . srcFolderMaps . get ( folderKey ) ;
578595 if ( rootInfo ) {
579- if ( targetFile . path === rootInfo . fileWatcher . file . path ) { // root folder has been renamed
580- if ( this . removeByKey ( folderKey ) ) { this . emit ( 'dataChanged' , 'dataChanged' ) ; }
596+
597+ // folder self has been renamed ?
598+ // - if true, this folder's file watcher is invalid, dispose it
599+ if ( targetFile . path == rootInfo . fileWatcher . file . path ) {
600+ this . disposeWatcher ( folderKey ) ;
601+ this . emit ( 'dataChanged' , 'folderStatusChanged' ) ;
602+ }
603+
604+ if ( rootInfo . refreshTimeout ) {
605+ rootInfo . refreshTimeout . refresh ( ) ;
581606 } else {
582- if ( rootInfo . refreshTimeout ) {
583- rootInfo . refreshTimeout . refresh ( ) ;
584- } else {
585- rootInfo . refreshTimeout = setTimeout ( ( folderInfo : SourceRootInfo ) => {
586- if ( folderInfo . refreshTimeout ) {
587- folderInfo . refreshTimeout = undefined ;
588- this . updateFolder ( folderInfo ) ;
589- this . emit ( 'dataChanged' , 'folderChanged' ) ;
590- }
591- } , 100 , rootInfo ) ;
592- }
607+ rootInfo . refreshTimeout = setTimeout ( ( folderInfo : SourceRootInfo ) => {
608+ if ( folderInfo . refreshTimeout ) {
609+ folderInfo . refreshTimeout = undefined ;
610+ this . updateFolder ( folderInfo ) ;
611+ this . emit ( 'dataChanged' , 'folderChanged' ) ;
612+ }
613+ } , 200 , rootInfo ) ;
593614 }
594615 }
595616 }
@@ -619,6 +640,9 @@ class SourceRootList implements SourceProvider {
619640 rootFolderInfo . incList = [ ] ;
620641 rootFolderInfo . fileGroups = [ ] ;
621642 folderStack . push ( rootFolder ) ;
643+ // if source root have no watcher, watch it !
644+ if ( rootFolderInfo . isValid ( ) && ! rootFolderInfo . fileWatcher . IsWatched ( ) )
645+ rootFolderInfo . fileWatcher . Watch ( ) ;
622646 }
623647
624648 rootFolderInfo . needUpdate = false ;
@@ -629,9 +653,14 @@ class SourceRootList implements SourceProvider {
629653
630654 const cFolder = < File > folderStack . pop ( ) ;
631655 const isSourceRoot = cFolder . path === rootFolder . path ;
632- if ( cFolder . name . startsWith ( '.' ) && ! isSourceRoot ) continue ; // skip '.xxx' folders, not root folder
633- const fileList = cFolder . GetList ( fileFilter , File . EXCLUDE_ALL_FILTER ) ;
634656
657+ if ( ! cFolder . IsDir ( ) )
658+ continue ; // skip not-existed folder
659+
660+ if ( cFolder . name . startsWith ( '.' ) && ! isSourceRoot )
661+ continue ; // skip sub '.xxx' folders, but not root folder
662+
663+ const fileList = cFolder . GetList ( fileFilter , File . EXCLUDE_ALL_FILTER ) ;
635664 if ( fileList . length > 0 ) {
636665
637666 // filter source file and add to file group
@@ -679,7 +708,7 @@ class SourceRootList implements SourceProvider {
679708
680709 } catch ( error ) {
681710 rootFolderInfo . needUpdate = true ; // set need update flag
682- GlobalEvent . emit ( 'msg ' , ExceptionToMessage ( error , 'Hidden ' ) ) ;
711+ GlobalEvent . emit ( 'globalLog ' , ExceptionToMessage ( error , 'Warning ' ) ) ;
683712 }
684713 }
685714}
@@ -724,7 +753,7 @@ export abstract class AbstractProject implements CustomConfigurationProvider, Pr
724753 static readonly excludeDirFilter : RegExp = / ^ \. / ;
725754
726755 // to show output files
727- static readonly buildOutputMatcher : RegExp = / \. (?: e l f | a x f | o u t | a | l i b | h e x | i h x | b i n | s 1 9 | s 3 7 | s c t | i c f | l d [ s ] ? | m a p | m a p \. v i e w ) $ / i;
756+ static readonly buildOutputMatcher : RegExp = / \. (?: e l f | a x f | o u t | a | l i b | h e x | i h x | b i n | s 1 9 | s 3 7 | s c t | i c f | l d [ s ] ? | m a p | m a p \. v i e w | l s t ) $ / i;
728757
729758 //-------
730759
@@ -1125,7 +1154,7 @@ export abstract class AbstractProject implements CustomConfigurationProvider, Pr
11251154
11261155 replacePathEnv ( path : string ) : string {
11271156
1128- for ( let cnt = 0 ; cnt < 5 ; cnt ++ ) {
1157+ for ( let cnt = 0 ; cnt < 3 ; cnt ++ ) {
11291158
11301159 if ( ! File . isEnvPath ( path ) )
11311160 break ; // not have any env var, end
@@ -2367,6 +2396,12 @@ class EIDEProject extends AbstractProject {
23672396 return this . srcRefMap . get ( file . path ) || [ ] ;
23682397 }
23692398
2399+ public getSourceRefsAll ( ) : string [ ] {
2400+ const allHeaders : string [ ] = [ ] ;
2401+ this . srcRefMap . forEach ( v => v . forEach ( f => allHeaders . push ( f . path ) ) ) ;
2402+ return ArrayDelRepetition ( allHeaders ) ;
2403+ }
2404+
23702405 private whitespaceMatcher = / (?< ! [ \\ : ] ) / ;
23712406
23722407 private gnu_parseRefLines ( lines : string [ ] ) : string [ ] {
@@ -2668,6 +2703,7 @@ class EIDEProject extends AbstractProject {
26682703
26692704 const fileAssCfg : any = {
26702705 ".eideignore" : "ignore" ,
2706+ "*.a51" : "a51" ,
26712707 "*.h" : "c" ,
26722708 "*.c" : "c" ,
26732709 "*.hxx" : "cpp" ,
@@ -2856,20 +2892,6 @@ class EIDEProject extends AbstractProject {
28562892 //
28572893 }
28582894 }
2859-
2860- /* const cppConfig = this.GetCppConfig();
2861- const cppConfigItem = cppConfig.getConfig();
2862- if (cppConfigItem.configurationProvider) {
2863- const newCfg: CppConfigItem = {
2864- name: os.platform(),
2865- includePath: <any>undefined,
2866- defines: <any>undefined,
2867- intelliSenseMode: "${default}",
2868- configurationProvider: this.extensionId
2869- };
2870- cppConfig.setConfig(newCfg);
2871- cppConfig.saveToFile();
2872- } */
28732895 }
28742896
28752897 // show warnings if we have
@@ -3107,14 +3129,30 @@ class EIDEProject extends AbstractProject {
31073129 }
31083130
31093131 canProvideConfiguration ( uri : vscode . Uri , token ?: vscode . CancellationToken | undefined ) : Thenable < boolean > {
3132+
31103133 return new Promise ( ( resolve ) => {
3111- const filePath = platform . realpathSync ( uri . fsPath ) ;
3134+
3135+ const realPath = platform . realpathSync ( uri . fsPath ) ;
3136+ const lowcasePath = uri . fsPath . toLowerCase ( ) ;
31123137 const prjRoot = platform . realpathSync ( this . GetRootDir ( ) . path ) ;
3113- resolve (
3114- AbstractProject . headerFilter . test ( filePath ) ||
3115- filePath . startsWith ( prjRoot ) ||
3116- this . vSourceList . has ( filePath )
3117- ) ;
3138+ const allIncPaths = this . cppToolsConfig . includePath . map ( p => File . ToLocalPath ( p . toLowerCase ( ) ) ) ;
3139+
3140+ // filter source files that can provide
3141+ let result : boolean =
3142+ realPath . startsWith ( prjRoot ) || // All source files in current workspace
3143+ allIncPaths . some ( p => lowcasePath . startsWith ( p ) ) || // All files in IncludePaths
3144+ this . vSourceList . has ( realPath ) || // All virtual source files
3145+ this . sourceRoots . isIncludes ( realPath ) ; // All source files in linked source folders
3146+
3147+ // other .h files
3148+ if ( ! result && AbstractProject . headerFilter . test ( lowcasePath ) ) {
3149+ const allHeaders = this . getSourceRefsAll ( ) . map ( p => File . ToLocalPath ( p . toLowerCase ( ) ) ) ;
3150+ result = result ||
3151+ allHeaders . some ( p => p == lowcasePath ) || // All .h files for this project
3152+ lowcasePath . startsWith ( this . getToolchain ( ) . getToolchainDir ( ) . path . toLowerCase ( ) ) ; // All .h files in toolchain dir
3153+ }
3154+
3155+ resolve ( result ) ;
31183156 } ) ;
31193157 }
31203158
@@ -3123,6 +3161,7 @@ class EIDEProject extends AbstractProject {
31233161 provideConfigurations ( uris : vscode . Uri [ ] , token ?: vscode . CancellationToken | undefined ) : Thenable < SourceFileConfigurationItem [ ] > {
31243162
31253163 return new Promise ( ( resolve ) => {
3164+
31263165 resolve ( uris . map ( ( uri ) => {
31273166
31283167 let fileArgs : string [ ] | undefined ;
0 commit comments