@@ -33,19 +33,55 @@ class ResourceStackElement {
3333 this . strResources = [ this . strResource ] ;
3434 }
3535}
36+
37+ const enum RemovedResourceReason {
38+ ExternalRemoval = 0 ,
39+ NoParallelUniverses = 1
40+ }
41+
42+ class RemovedResources {
43+ public readonly set : Set < string > = new Set < string > ( ) ;
44+ public readonly reason : [ URI [ ] , URI [ ] ] = [ [ ] , [ ] ] ;
45+
46+ public createMessage ( ) : string {
47+ let messages : string [ ] = [ ] ;
48+ if ( this . reason [ RemovedResourceReason . ExternalRemoval ] . length > 0 ) {
49+ const paths = this . reason [ RemovedResourceReason . ExternalRemoval ] . map ( uri => uri . scheme === Schemas . file ? uri . fsPath : uri . path ) ;
50+ messages . push ( nls . localize ( 'externalRemoval' , "The following files have been closed: {0}." , paths . join ( ', ' ) ) ) ;
51+ }
52+ if ( this . reason [ RemovedResourceReason . NoParallelUniverses ] . length > 0 ) {
53+ const paths = this . reason [ RemovedResourceReason . NoParallelUniverses ] . map ( uri => uri . scheme === Schemas . file ? uri . fsPath : uri . path ) ;
54+ messages . push ( nls . localize ( 'noParallelUniverses' , "The following files have been modified in an incompatible way: {0}." , paths . join ( ', ' ) ) ) ;
55+ }
56+ return messages . join ( '\n' ) ;
57+ }
58+ }
59+
3660class WorkspaceStackElement {
3761 public readonly type = UndoRedoElementType . Workspace ;
3862 public readonly actual : IWorkspaceUndoRedoElement ;
3963 public readonly label : string ;
4064
4165 public readonly resources : URI [ ] ;
4266 public readonly strResources : string [ ] ;
67+ public removedResources : RemovedResources | null ;
4368
4469 constructor ( actual : IWorkspaceUndoRedoElement ) {
4570 this . actual = actual ;
4671 this . label = actual . label ;
4772 this . resources = actual . resources . slice ( 0 ) ;
4873 this . strResources = this . resources . map ( resource => uriGetComparisonKey ( resource ) ) ;
74+ this . removedResources = null ;
75+ }
76+
77+ public removeResource ( resource : URI , strResource : string , reason : RemovedResourceReason ) : void {
78+ if ( ! this . removedResources ) {
79+ this . removedResources = new RemovedResources ( ) ;
80+ }
81+ if ( ! this . removedResources . set . has ( strResource ) ) {
82+ this . removedResources . set . add ( strResource ) ;
83+ this . removedResources . reason [ reason ] . push ( resource ) ;
84+ }
4985 }
5086}
5187type StackElement = ResourceStackElement | WorkspaceStackElement ;
@@ -91,7 +127,7 @@ export class UndoRedoService implements IUndoRedoService {
91127 // remove the future
92128 for ( const futureElement of editStack . future ) {
93129 if ( futureElement . type === UndoRedoElementType . Workspace ) {
94- this . _splitFutureWorkspaceElement ( futureElement , strResource ) ;
130+ futureElement . removeResource ( resource , strResource , RemovedResourceReason . NoParallelUniverses ) ;
95131 }
96132 }
97133 editStack . future = [ ] ;
@@ -114,7 +150,7 @@ export class UndoRedoService implements IUndoRedoService {
114150 return null ;
115151 }
116152
117- private _splitPastWorkspaceElement ( toRemove : WorkspaceStackElement , ignoreStrResource : string | null ) : void {
153+ private _splitPastWorkspaceElement ( toRemove : WorkspaceStackElement , ignoreResources : Set < string > | null ) : void {
118154 const individualArr = toRemove . actual . split ( ) ;
119155 const individualMap = new Map < string , ResourceStackElement > ( ) ;
120156 for ( const _element of individualArr ) {
@@ -123,7 +159,7 @@ export class UndoRedoService implements IUndoRedoService {
123159 }
124160
125161 for ( const strResource of toRemove . strResources ) {
126- if ( strResource === ignoreStrResource ) {
162+ if ( ignoreResources && ignoreResources . has ( strResource ) ) {
127163 continue ;
128164 }
129165 const editStack = this . _editStacks . get ( strResource ) ! ;
@@ -142,7 +178,7 @@ export class UndoRedoService implements IUndoRedoService {
142178 }
143179 }
144180
145- private _splitFutureWorkspaceElement ( toRemove : WorkspaceStackElement , ignoreStrResource : string | null ) : void {
181+ private _splitFutureWorkspaceElement ( toRemove : WorkspaceStackElement , ignoreResources : Set < string > | null ) : void {
146182 const individualArr = toRemove . actual . split ( ) ;
147183 const individualMap = new Map < string , ResourceStackElement > ( ) ;
148184 for ( const _element of individualArr ) {
@@ -151,7 +187,7 @@ export class UndoRedoService implements IUndoRedoService {
151187 }
152188
153189 for ( const strResource of toRemove . strResources ) {
154- if ( strResource === ignoreStrResource ) {
190+ if ( ignoreResources && ignoreResources . has ( strResource ) ) {
155191 continue ;
156192 }
157193 const editStack = this . _editStacks . get ( strResource ) ! ;
@@ -174,14 +210,14 @@ export class UndoRedoService implements IUndoRedoService {
174210 const strResource = uriGetComparisonKey ( resource ) ;
175211 if ( this . _editStacks . has ( strResource ) ) {
176212 const editStack = this . _editStacks . get ( strResource ) ! ;
177- for ( const pastElement of editStack . past ) {
178- if ( pastElement . type === UndoRedoElementType . Workspace ) {
179- this . _splitPastWorkspaceElement ( pastElement , strResource ) ;
213+ for ( const element of editStack . past ) {
214+ if ( element . type === UndoRedoElementType . Workspace ) {
215+ element . removeResource ( resource , strResource , RemovedResourceReason . ExternalRemoval ) ;
180216 }
181217 }
182- for ( const futureElement of editStack . future ) {
183- if ( futureElement . type === UndoRedoElementType . Workspace ) {
184- this . _splitFutureWorkspaceElement ( futureElement , strResource ) ;
218+ for ( const element of editStack . future ) {
219+ if ( element . type === UndoRedoElementType . Workspace ) {
220+ element . removeResource ( resource , strResource , RemovedResourceReason . ExternalRemoval ) ;
185221 }
186222 }
187223 this . _editStacks . delete ( strResource ) ;
@@ -220,6 +256,13 @@ export class UndoRedoService implements IUndoRedoService {
220256 }
221257
222258 private _workspaceUndo ( resource : URI , element : WorkspaceStackElement ) : Promise < void > | void {
259+ if ( element . removedResources ) {
260+ this . _splitPastWorkspaceElement ( element , element . removedResources . set ) ;
261+ const message = nls . localize ( 'cannotWorkspaceUndo' , "Could not undo '{0}' across all files. {1}" , element . label , element . removedResources . createMessage ( ) ) ;
262+ this . _notificationService . info ( message ) ;
263+ return ;
264+ }
265+
223266 // this must be the last past element in all the impacted resources!
224267 let affectedEditStacks : ResourceEditStack [ ] = [ ] ;
225268 for ( const strResource of element . strResources ) {
@@ -236,7 +279,7 @@ export class UndoRedoService implements IUndoRedoService {
236279 if ( cannotUndoDueToResources . length > 0 ) {
237280 this . _splitPastWorkspaceElement ( element , null ) ;
238281 const paths = cannotUndoDueToResources . map ( r => r . scheme === Schemas . file ? r . fsPath : r . path ) ;
239- const message = nls . localize ( 'undoFurtherChanges ' , "Could not undo '{0}' across all files because changes were made to {1}" , element . label , paths . join ( ', ' ) ) ;
282+ const message = nls . localize ( 'cannotWorkspaceUndoDueToChanges ' , "Could not undo '{0}' across all files because changes were made to {1}" , element . label , paths . join ( ', ' ) ) ;
240283 this . _notificationService . info ( message ) ;
241284 return ;
242285 }
@@ -297,6 +340,13 @@ export class UndoRedoService implements IUndoRedoService {
297340 }
298341
299342 private _workspaceRedo ( resource : URI , element : WorkspaceStackElement ) : Promise < void > | void {
343+ if ( element . removedResources ) {
344+ this . _splitFutureWorkspaceElement ( element , element . removedResources . set ) ;
345+ const message = nls . localize ( 'cannotWorkspaceRedo' , "Could not redo '{0}' across all files. {1}" , element . label , element . removedResources . createMessage ( ) ) ;
346+ this . _notificationService . info ( message ) ;
347+ return ;
348+ }
349+
300350 // this must be the last future element in all the impacted resources!
301351 let affectedEditStacks : ResourceEditStack [ ] = [ ] ;
302352 for ( const strResource of element . strResources ) {
@@ -313,7 +363,7 @@ export class UndoRedoService implements IUndoRedoService {
313363 if ( cannotRedoDueToResources . length > 0 ) {
314364 this . _splitFutureWorkspaceElement ( element , null ) ;
315365 const paths = cannotRedoDueToResources . map ( r => r . scheme === Schemas . file ? r . fsPath : r . path ) ;
316- const message = nls . localize ( 'redoFurtherChanges ' , "Could not redo '{0}' across all files because changes were made to {1}" , element . label , paths . join ( ', ' ) ) ;
366+ const message = nls . localize ( 'cannotWorkspaceRedoDueToChanges ' , "Could not redo '{0}' across all files because changes were made to {1}" , element . label , paths . join ( ', ' ) ) ;
317367 this . _notificationService . info ( message ) ;
318368 return ;
319369 }
0 commit comments