@@ -170,6 +170,7 @@ func NewConfiguredProject(configFileName string, configFilePath tspath.Path, hos
170
170
project .configFileName = configFileName
171
171
project .configFilePath = configFilePath
172
172
project .initialLoadPending = true
173
+ project .pendingReload = PendingReloadFull
173
174
client := host .Client ()
174
175
if host .IsWatchEnabled () && client != nil {
175
176
project .rootFilesWatch = newWatchedFiles (project , lsproto .WatchKindChange | lsproto .WatchKindCreate | lsproto .WatchKindDelete , core .Identity , "root files" )
@@ -361,6 +362,16 @@ func (p *Project) updateWatchers(ctx context.Context) {
361
362
p .affectingLocationsWatch .update (ctx , affectingLocationGlobs )
362
363
}
363
364
365
+ func (p * Project ) tryInvokeWildCardDirectories (fileName string , path tspath.Path ) bool {
366
+ if p .kind == KindConfigured {
367
+ if p .rootFileNames .Has (path ) || p .parsedCommandLine .MatchesFileName (fileName ) {
368
+ p .SetPendingReload (PendingReloadFileNames )
369
+ return true
370
+ }
371
+ }
372
+ return false
373
+ }
374
+
364
375
// onWatchEventForNilScriptInfo is fired for watch events that are not the
365
376
// project tsconfig, and do not have a ScriptInfo for the associated file.
366
377
// This could be a case of one of the following:
@@ -370,14 +381,9 @@ func (p *Project) updateWatchers(ctx context.Context) {
370
381
// part of the project, e.g., a .js file in a project without --allowJs.
371
382
func (p * Project ) onWatchEventForNilScriptInfo (fileName string ) {
372
383
path := p .toPath (fileName )
373
- if p .kind == KindConfigured {
374
- if p .rootFileNames .Has (path ) || p .parsedCommandLine .MatchesFileName (fileName ) {
375
- p .pendingReload = PendingReloadFileNames
376
- p .markAsDirty ()
377
- return
378
- }
384
+ if p .tryInvokeWildCardDirectories (fileName , path ) {
385
+ return
379
386
}
380
-
381
387
if _ , ok := p .failedLookupsWatch .data [path ]; ok {
382
388
p .markAsDirty ()
383
389
} else if _ , ok := p .affectingLocationsWatch .data [path ]; ok {
@@ -429,6 +435,15 @@ func (p *Project) MarkFileAsDirty(path tspath.Path) {
429
435
}
430
436
}
431
437
438
+ func (p * Project ) SetPendingReload (level PendingReload ) {
439
+ p .mu .Lock ()
440
+ defer p .mu .Unlock ()
441
+ if level > p .pendingReload {
442
+ p .pendingReload = level
443
+ p .markAsDirtyLocked ()
444
+ }
445
+ }
446
+
432
447
func (p * Project ) markAsDirty () {
433
448
p .mu .Lock ()
434
449
defer p .mu .Unlock ()
@@ -471,12 +486,12 @@ func (p *Project) updateGraph() bool {
471
486
case PendingReloadFileNames :
472
487
p .parsedCommandLine = tsoptions .ReloadFileNamesOfParsedCommandLine (p .parsedCommandLine , p .host .FS ())
473
488
writeFileNames = p .setRootFiles (p .parsedCommandLine .FileNames ())
489
+ p .pendingReload = PendingReloadNone
474
490
case PendingReloadFull :
475
491
if err := p .loadConfig (); err != nil {
476
492
panic (fmt .Sprintf ("failed to reload config: %v" , err ))
477
493
}
478
494
}
479
- p .pendingReload = PendingReloadNone
480
495
}
481
496
482
497
oldProgramReused := p .updateProgram ()
@@ -681,7 +696,7 @@ func (p *Project) extractUnresolvedImportsFromSourceFile(file *ast.SourceFile, o
681
696
func (p * Project ) UpdateTypingFiles (typingsInfo * TypingsInfo , typingFiles []string ) {
682
697
p .mu .Lock ()
683
698
defer p .mu .Unlock ()
684
- if p .typingsInfo != typingsInfo {
699
+ if p .isClosed () || p . typingsInfo != typingsInfo {
685
700
return
686
701
}
687
702
@@ -710,6 +725,12 @@ func (p *Project) UpdateTypingFiles(typingsInfo *TypingsInfo, typingFiles []stri
710
725
}
711
726
712
727
func (p * Project ) WatchTypingLocations (files []string ) {
728
+ p .mu .Lock ()
729
+ defer p .mu .Unlock ()
730
+ if p .isClosed () {
731
+ return
732
+ }
733
+
713
734
client := p .host .Client ()
714
735
if ! p .host .IsWatchEnabled () || client == nil {
715
736
return
@@ -785,14 +806,9 @@ func (p *Project) RemoveFile(info *ScriptInfo, fileExists bool, detachFromProjec
785
806
}
786
807
787
808
func (p * Project ) removeFile (info * ScriptInfo , fileExists bool , detachFromProject bool ) {
788
- if p .isRoot (info ) {
789
- switch p .kind {
790
- case KindInferred :
791
- p .rootFileNames .Delete (info .path )
792
- p .typeAcquisition = nil
793
- case KindConfigured :
794
- p .pendingReload = PendingReloadFileNames
795
- }
809
+ if p .isRoot (info ) && p .kind == KindInferred {
810
+ p .rootFileNames .Delete (info .path )
811
+ p .typeAcquisition = nil
796
812
}
797
813
p .onFileAddedOrRemoved ()
798
814
@@ -809,27 +825,21 @@ func (p *Project) removeFile(info *ScriptInfo, fileExists bool, detachFromProjec
809
825
}
810
826
}
811
827
812
- func (p * Project ) AddRoot (info * ScriptInfo ) {
828
+ func (p * Project ) AddInferredProjectRoot (info * ScriptInfo ) {
813
829
p .mu .Lock ()
814
830
defer p .mu .Unlock ()
815
- p . addRoot (info )
816
- p . markAsDirtyLocked ( )
817
- }
818
-
819
- func ( p * Project ) addRoot ( info * ScriptInfo ) {
831
+ if p . isRoot (info ) {
832
+ panic ( "script info is already a root" )
833
+ }
834
+ p . rootFileNames . Set ( info . path , info . fileName )
835
+ p . typeAcquisition = nil
820
836
// !!!
821
837
// if p.kind == KindInferred {
822
838
// p.host.startWatchingConfigFilesForInferredProjectRoot(info.path);
823
839
// // handle JS toggling
824
840
// }
825
- if p .isRoot (info ) {
826
- panic ("script info is already a root" )
827
- }
828
- p .rootFileNames .Set (info .path , info .fileName )
829
- if p .kind == KindInferred {
830
- p .typeAcquisition = nil
831
- }
832
841
info .attachToProject (p )
842
+ p .markAsDirtyLocked ()
833
843
}
834
844
835
845
func (p * Project ) LoadConfig () error {
@@ -845,6 +855,7 @@ func (p *Project) loadConfig() error {
845
855
panic ("loadConfig called on non-configured project" )
846
856
}
847
857
858
+ p .pendingReload = PendingReloadNone
848
859
if configFileContent , ok := p .host .FS ().ReadFile (p .configFileName ); ok {
849
860
configDir := tspath .GetDirectoryPath (p .configFileName )
850
861
tsConfigSourceFile := tsoptions .NewTsconfigSourceFileFromFilePath (p .configFileName , p .configFilePath , configFileContent )
@@ -885,38 +896,31 @@ func (p *Project) setRootFiles(rootFileNames []string) bool {
885
896
var hasChanged bool
886
897
newRootScriptInfos := make (map [tspath.Path ]struct {}, len (rootFileNames ))
887
898
for _ , file := range rootFileNames {
888
- scriptKind := p .getScriptKind (file )
889
899
path := p .toPath (file )
890
900
// !!! updateNonInferredProjectFiles uses a fileExists check, which I guess
891
901
// could be needed if a watcher fails?
892
- scriptInfo := p .host .GetOrCreateScriptInfoForFile (file , path , scriptKind )
893
902
newRootScriptInfos [path ] = struct {}{}
894
903
isAlreadyRoot := p .rootFileNames .Has (path )
895
904
hasChanged = hasChanged || ! isAlreadyRoot
896
-
897
- if ! isAlreadyRoot && scriptInfo != nil {
898
- p .addRoot (scriptInfo )
899
- if scriptInfo .isOpen {
900
- // !!!
901
- // s.removeRootOfInferredProjectIfNowPartOfOtherProject(scriptInfo)
902
- }
903
- } else if ! isAlreadyRoot {
904
- p .rootFileNames .Set (path , file )
905
- }
905
+ p .rootFileNames .Set (path , file )
906
+ // if !isAlreadyRoot {
907
+ // if scriptInfo.isOpen {
908
+ // !!!s.removeRootOfInferredProjectIfNowPartOfOtherProject(scriptInfo)
909
+ // }
910
+ // }
906
911
}
907
912
908
913
if p .rootFileNames .Size () > len (rootFileNames ) {
909
914
hasChanged = true
910
915
for root := range p .rootFileNames .Keys () {
911
916
if _ , ok := newRootScriptInfos [root ]; ! ok {
912
- if info := p .host .GetScriptInfoByPath (root ); info != nil {
913
- p .removeFile (info , true /*fileExists*/ , true /*detachFromProject*/ )
914
- } else {
915
- p .rootFileNames .Delete (root )
916
- }
917
+ p .rootFileNames .Delete (root )
917
918
}
918
919
}
919
920
}
921
+ if hasChanged {
922
+ p .onFileAddedOrRemoved ()
923
+ }
920
924
return hasChanged
921
925
}
922
926
@@ -964,21 +968,20 @@ func (p *Project) GetFileNames(excludeFilesFromExternalLibraries bool, excludeCo
964
968
}
965
969
966
970
func (p * Project ) print (writeFileNames bool , writeFileExplanation bool , writeFileVersionAndText bool , builder * strings.Builder ) string {
967
- builder .WriteString (fmt .Sprintf ("Project '%s' (%s)\n " , p .name , p .kind .String ()))
971
+ builder .WriteString (fmt .Sprintf ("\n Project '%s' (%s)\n " , p .name , p .kind .String ()))
968
972
if p .initialLoadPending {
969
- builder .WriteString ("\t Files (0) InitialLoadPending\n " )
973
+ builder .WriteString ("\n \ t Files (0) InitialLoadPending\n " )
970
974
} else if p .program == nil {
971
- builder .WriteString ("\t Files (0) NoProgram\n " )
975
+ builder .WriteString ("\n \ t Files (0) NoProgram\n " )
972
976
} else {
973
977
sourceFiles := p .program .GetSourceFiles ()
974
- builder .WriteString (fmt .Sprintf ("\t Files (%d)\n " , len (sourceFiles )))
978
+ builder .WriteString (fmt .Sprintf ("\n \ t Files (%d)\n " , len (sourceFiles )))
975
979
if writeFileNames {
976
980
for _ , sourceFile := range sourceFiles {
977
- builder .WriteString ("\t \t " + sourceFile .FileName ())
981
+ builder .WriteString ("\n \ t\t " + sourceFile .FileName ())
978
982
if writeFileVersionAndText {
979
983
builder .WriteString (fmt .Sprintf (" %d %s" , sourceFile .Version , sourceFile .Text ()))
980
984
}
981
- builder .WriteRune ('\n' )
982
985
}
983
986
// !!!
984
987
// if writeFileExplanation {}
@@ -997,7 +1000,49 @@ func (p *Project) Logf(format string, args ...interface{}) {
997
1000
}
998
1001
999
1002
func (p * Project ) Close () {
1000
- // !!!
1003
+ p .mu .Lock ()
1004
+ defer p .mu .Unlock ()
1005
+
1006
+ if p .program != nil {
1007
+ for _ , sourceFile := range p .program .GetSourceFiles () {
1008
+ p .host .DocumentRegistry ().ReleaseDocument (sourceFile , p .program .GetCompilerOptions ())
1009
+ if scriptInfo := p .host .GetScriptInfoByPath (sourceFile .Path ()); scriptInfo != nil {
1010
+ scriptInfo .detachFromProject (p )
1011
+ }
1012
+ }
1013
+ p .program = nil
1014
+ } else if p .kind == KindInferred {
1015
+ // Release root script infos for inferred projects.
1016
+ for path := range p .rootFileNames .Keys () {
1017
+ if info := p .host .GetScriptInfoByPath (path ); info != nil {
1018
+ info .detachFromProject (p )
1019
+ }
1020
+ }
1021
+ }
1022
+ p .rootFileNames = nil
1023
+ p .parsedCommandLine = nil
1024
+ p .checkerPool = nil
1025
+ p .unresolvedImportsPerFile = nil
1026
+ p .typingsInfo = nil
1027
+ p .typingFiles = nil
1028
+
1029
+ // Clean up file watchers waiting for missing files
1030
+ client := p .host .Client ()
1031
+ if p .host .IsWatchEnabled () && client != nil {
1032
+ ctx := context .Background ()
1033
+ if p .rootFilesWatch != nil {
1034
+ p .rootFilesWatch .update (ctx , nil )
1035
+ }
1036
+
1037
+ p .failedLookupsWatch .update (ctx , nil )
1038
+ p .affectingLocationsWatch .update (ctx , nil )
1039
+ p .typingsFilesWatch .update (ctx , nil )
1040
+ p .typingsDirectoryWatch .update (ctx , nil )
1041
+ }
1042
+ }
1043
+
1044
+ func (p * Project ) isClosed () bool {
1045
+ return p .rootFileNames == nil
1001
1046
}
1002
1047
1003
1048
func formatFileList (files []string , linePrefix string , groupSuffix string ) string {
0 commit comments