@@ -11,78 +11,85 @@ import { ITextFileEditorModel, ITextFileEditorModelManager, TextFileModelChangeE
1111import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle' ;
1212import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation' ;
1313import { ResourceMap } from 'vs/base/common/map' ;
14+ import { IFileService , FileChangesEvent } from 'vs/platform/files/common/files' ;
15+ import { distinct , coalesce } from 'vs/base/common/arrays' ;
16+ import { ResourceQueue } from 'vs/base/common/async' ;
17+ import { onUnexpectedError } from 'vs/base/common/errors' ;
1418
1519export class TextFileEditorModelManager extends Disposable implements ITextFileEditorModelManager {
1620
17- private readonly _onModelDisposed : Emitter < URI > = this . _register ( new Emitter < URI > ( ) ) ;
18- readonly onModelDisposed : Event < URI > = this . _onModelDisposed . event ;
21+ private readonly _onModelDisposed = this . _register ( new Emitter < URI > ( ) ) ;
22+ readonly onModelDisposed = this . _onModelDisposed . event ;
1923
20- private readonly _onModelContentChanged : Emitter < TextFileModelChangeEvent > = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
21- readonly onModelContentChanged : Event < TextFileModelChangeEvent > = this . _onModelContentChanged . event ;
24+ private readonly _onModelContentChanged = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
25+ readonly onModelContentChanged = this . _onModelContentChanged . event ;
2226
23- private readonly _onModelDirty : Emitter < TextFileModelChangeEvent > = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
24- readonly onModelDirty : Event < TextFileModelChangeEvent > = this . _onModelDirty . event ;
27+ private readonly _onModelDirty = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
28+ readonly onModelDirty = this . _onModelDirty . event ;
2529
26- private readonly _onModelSaveError : Emitter < TextFileModelChangeEvent > = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
27- readonly onModelSaveError : Event < TextFileModelChangeEvent > = this . _onModelSaveError . event ;
30+ private readonly _onModelSaveError = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
31+ readonly onModelSaveError = this . _onModelSaveError . event ;
2832
29- private readonly _onModelSaved : Emitter < TextFileModelChangeEvent > = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
30- readonly onModelSaved : Event < TextFileModelChangeEvent > = this . _onModelSaved . event ;
33+ private readonly _onModelSaved = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
34+ readonly onModelSaved = this . _onModelSaved . event ;
3135
32- private readonly _onModelReverted : Emitter < TextFileModelChangeEvent > = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
33- readonly onModelReverted : Event < TextFileModelChangeEvent > = this . _onModelReverted . event ;
36+ private readonly _onModelReverted = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
37+ readonly onModelReverted = this . _onModelReverted . event ;
3438
35- private readonly _onModelEncodingChanged : Emitter < TextFileModelChangeEvent > = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
36- readonly onModelEncodingChanged : Event < TextFileModelChangeEvent > = this . _onModelEncodingChanged . event ;
39+ private readonly _onModelEncodingChanged = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
40+ readonly onModelEncodingChanged = this . _onModelEncodingChanged . event ;
3741
38- private readonly _onModelOrphanedChanged : Emitter < TextFileModelChangeEvent > = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
39- readonly onModelOrphanedChanged : Event < TextFileModelChangeEvent > = this . _onModelOrphanedChanged . event ;
42+ private readonly _onModelOrphanedChanged = this . _register ( new Emitter < TextFileModelChangeEvent > ( ) ) ;
43+ readonly onModelOrphanedChanged = this . _onModelOrphanedChanged . event ;
4044
41- private _onModelsDirty : Event < readonly TextFileModelChangeEvent [ ] > | undefined ;
42- get onModelsDirty ( ) : Event < readonly TextFileModelChangeEvent [ ] > {
45+ private _onModelsDirty : Event < ReadonlyArray < TextFileModelChangeEvent > > | undefined ;
46+ get onModelsDirty ( ) : Event < ReadonlyArray < TextFileModelChangeEvent > > {
4347 if ( ! this . _onModelsDirty ) {
4448 this . _onModelsDirty = this . debounce ( this . onModelDirty ) ;
4549 }
4650
4751 return this . _onModelsDirty ;
4852 }
4953
50- private _onModelsSaveError : Event < readonly TextFileModelChangeEvent [ ] > | undefined ;
51- get onModelsSaveError ( ) : Event < readonly TextFileModelChangeEvent [ ] > {
54+ private _onModelsSaveError : Event < ReadonlyArray < TextFileModelChangeEvent > > | undefined ;
55+ get onModelsSaveError ( ) : Event < ReadonlyArray < TextFileModelChangeEvent > > {
5256 if ( ! this . _onModelsSaveError ) {
5357 this . _onModelsSaveError = this . debounce ( this . onModelSaveError ) ;
5458 }
5559
5660 return this . _onModelsSaveError ;
5761 }
5862
59- private _onModelsSaved : Event < readonly TextFileModelChangeEvent [ ] > | undefined ;
60- get onModelsSaved ( ) : Event < readonly TextFileModelChangeEvent [ ] > {
63+ private _onModelsSaved : Event < ReadonlyArray < TextFileModelChangeEvent > > | undefined ;
64+ get onModelsSaved ( ) : Event < ReadonlyArray < TextFileModelChangeEvent > > {
6165 if ( ! this . _onModelsSaved ) {
6266 this . _onModelsSaved = this . debounce ( this . onModelSaved ) ;
6367 }
6468
6569 return this . _onModelsSaved ;
6670 }
6771
68- private _onModelsReverted : Event < readonly TextFileModelChangeEvent [ ] > | undefined ;
69- get onModelsReverted ( ) : Event < readonly TextFileModelChangeEvent [ ] > {
72+ private _onModelsReverted : Event < ReadonlyArray < TextFileModelChangeEvent > > | undefined ;
73+ get onModelsReverted ( ) : Event < ReadonlyArray < TextFileModelChangeEvent > > {
7074 if ( ! this . _onModelsReverted ) {
7175 this . _onModelsReverted = this . debounce ( this . onModelReverted ) ;
7276 }
7377
7478 return this . _onModelsReverted ;
7579 }
7680
77- private mapResourceToDisposeListener = new ResourceMap < IDisposable > ( ) ;
78- private mapResourceToStateChangeListener = new ResourceMap < IDisposable > ( ) ;
79- private mapResourceToModelContentChangeListener = new ResourceMap < IDisposable > ( ) ;
80- private mapResourceToModel = new ResourceMap < ITextFileEditorModel > ( ) ;
81- private mapResourceToPendingModelLoaders = new ResourceMap < Promise < ITextFileEditorModel > > ( ) ;
81+ private readonly mapResourceToDisposeListener = new ResourceMap < IDisposable > ( ) ;
82+ private readonly mapResourceToStateChangeListener = new ResourceMap < IDisposable > ( ) ;
83+ private readonly mapResourceToModelContentChangeListener = new ResourceMap < IDisposable > ( ) ;
84+ private readonly mapResourceToModel = new ResourceMap < ITextFileEditorModel > ( ) ;
85+ private readonly mapResourceToPendingModelLoaders = new ResourceMap < Promise < ITextFileEditorModel > > ( ) ;
86+
87+ private readonly modelLoadQueue = new ResourceQueue ( ) ;
8288
8389 constructor (
8490 @ILifecycleService private readonly lifecycleService : ILifecycleService ,
85- @IInstantiationService private readonly instantiationService : IInstantiationService
91+ @IInstantiationService private readonly instantiationService : IInstantiationService ,
92+ @IFileService private readonly fileService : IFileService
8693 ) {
8794 super ( ) ;
8895
@@ -91,11 +98,37 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
9198
9299 private registerListeners ( ) : void {
93100
101+ // Update models from file change events
102+ this . _register ( this . fileService . onFileChanges ( e => this . onFileChanges ( e ) ) ) ;
103+
94104 // Lifecycle
95105 this . lifecycleService . onShutdown ( this . dispose , this ) ;
96106 }
97107
98- private debounce ( event : Event < TextFileModelChangeEvent > ) : Event < readonly TextFileModelChangeEvent [ ] > {
108+ private onFileChanges ( e : FileChangesEvent ) : void {
109+
110+ // Collect distinct (saved) models to update.
111+ //
112+ // Note: we also consider the added event because it could be that a file was added
113+ // and updated right after.
114+ distinct ( coalesce ( [ ...e . getUpdated ( ) , ...e . getAdded ( ) ]
115+ . map ( ( { resource } ) => this . get ( resource ) ) )
116+ . filter ( model => model && ! model . isDirty ( ) ) , model => model . resource . toString ( ) )
117+ . forEach ( model => this . queueModelLoad ( model ) ) ;
118+ }
119+
120+ private queueModelLoad ( model : ITextFileEditorModel ) : void {
121+
122+ // Load model to update (use a queue to prevent accumulation of loads
123+ // when the load actually takes long. At most we only want the queue
124+ // to have a size of 2 (1 running load and 1 queued load).
125+ const queue = this . modelLoadQueue . queueFor ( model . resource ) ;
126+ if ( queue . size <= 1 ) {
127+ queue . queue ( ( ) => model . load ( ) . then ( undefined , onUnexpectedError ) ) ;
128+ }
129+ }
130+
131+ private debounce ( event : Event < TextFileModelChangeEvent > ) : Event < ReadonlyArray < TextFileModelChangeEvent > > {
99132 return Event . debounce ( event , ( prev : TextFileModelChangeEvent [ ] , cur : TextFileModelChangeEvent ) => {
100133 if ( ! prev ) {
101134 prev = [ cur ] ;
0 commit comments