@@ -8,13 +8,13 @@ import { URI } from 'vs/base/common/uri';
88import * as nls from 'vs/nls' ;
99import { IWorkspaceContextService , WorkbenchState } from 'vs/platform/workspace/common/workspace' ;
1010import { IJSONEditingService , JSONEditingError , JSONEditingErrorCode } from 'vs/workbench/services/configuration/common/jsonEditing' ;
11- import { IWorkspaceIdentifier , IWorkspaceFolderCreationData , IWorkspacesService , rewriteWorkspaceFileForNewLocation , WORKSPACE_FILTER , IEnterWorkspaceResult , hasWorkspaceFileExtension , WORKSPACE_EXTENSION , isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces' ;
11+ import { IWorkspaceIdentifier , IWorkspaceFolderCreationData , IWorkspacesService , rewriteWorkspaceFileForNewLocation , WORKSPACE_FILTER , IEnterWorkspaceResult , hasWorkspaceFileExtension , WORKSPACE_EXTENSION , isUntitledWorkspace , IStoredWorkspace } from 'vs/platform/workspaces/common/workspaces' ;
1212import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService' ;
1313import { ConfigurationScope , IConfigurationRegistry , Extensions as ConfigurationExtensions , IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry' ;
1414import { Registry } from 'vs/platform/registry/common/platform' ;
1515import { ICommandService } from 'vs/platform/commands/common/commands' ;
1616import { distinct } from 'vs/base/common/arrays' ;
17- import { isEqual , getComparisonKey , isEqualAuthority } from 'vs/base/common/resources' ;
17+ import { isEqual , getComparisonKey , isEqualAuthority , extUri } from 'vs/base/common/resources' ;
1818import { INotificationService , Severity } from 'vs/platform/notification/common/notification' ;
1919import { IFileService } from 'vs/platform/files/common/files' ;
2020import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService' ;
@@ -24,14 +24,15 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
2424import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles' ;
2525import { IHostService } from 'vs/workbench/services/host/browser/host' ;
2626import { Schemas } from 'vs/base/common/network' ;
27+ import { SaveReason } from 'vs/workbench/common/editor' ;
2728
2829export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditingService {
2930
3031 declare readonly _serviceBrand : undefined ;
3132
3233 constructor (
3334 @IJSONEditingService private readonly jsonEditingService : IJSONEditingService ,
34- @IWorkspaceContextService private readonly contextService : WorkspaceService ,
35+ @IWorkspaceContextService protected readonly contextService : WorkspaceService ,
3536 @IConfigurationService private readonly configurationService : IConfigurationService ,
3637 @INotificationService private readonly notificationService : INotificationService ,
3738 @ICommandService private readonly commandService : ICommandService ,
@@ -206,12 +207,18 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi
206207 }
207208
208209 async saveAndEnterWorkspace ( path : URI ) : Promise < void > {
209- if ( ! await this . isValidTargetWorkspacePath ( path ) ) {
210+ const workspaceIdentifier = this . getCurrentWorkspaceIdentifier ( ) ;
211+ if ( ! workspaceIdentifier ) {
210212 return ;
211213 }
212214
213- const workspaceIdentifier = this . getCurrentWorkspaceIdentifier ( ) ;
214- if ( ! workspaceIdentifier ) {
215+ // Allow to save the workspace of the current window
216+ if ( extUri . isEqual ( workspaceIdentifier . configPath , path ) ) {
217+ return this . saveWorkspace ( workspaceIdentifier ) ;
218+ }
219+
220+ // From this moment on we require a valid target that is not opened already
221+ if ( ! await this . isValidTargetWorkspacePath ( path ) ) {
215222 return ;
216223 }
217224
@@ -224,7 +231,7 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi
224231 return true ; // OK
225232 }
226233
227- protected async saveWorkspaceAs ( workspace : IWorkspaceIdentifier , targetConfigPathURI : URI ) : Promise < any > {
234+ protected async saveWorkspaceAs ( workspace : IWorkspaceIdentifier , targetConfigPathURI : URI ) : Promise < void > {
228235 const configPathURI = workspace . configPath ;
229236
230237 // Return early if target is same as source
@@ -240,6 +247,28 @@ export abstract class AbstractWorkspaceEditingService implements IWorkspaceEditi
240247 await this . textFileService . create ( targetConfigPathURI , newRawWorkspaceContents , { overwrite : true } ) ;
241248 }
242249
250+ protected async saveWorkspace ( workspace : IWorkspaceIdentifier ) : Promise < void > {
251+ const configPathURI = workspace . configPath ;
252+
253+ // First: try to save any existing model as it could be dirty
254+ const existingModel = this . textFileService . files . get ( configPathURI ) ;
255+ if ( existingModel ) {
256+ await existingModel . save ( { force : true , reason : SaveReason . EXPLICIT } ) ;
257+ return ;
258+ }
259+
260+ // Second: if the file exists on disk, simply return
261+ const workspaceFileExists = await this . fileService . exists ( configPathURI ) ;
262+ if ( workspaceFileExists ) {
263+ return ;
264+ }
265+
266+ // Finally, we need to re-create the file as it was deleted
267+ const newWorkspace : IStoredWorkspace = { folders : [ ] } ;
268+ const newRawWorkspaceContents = rewriteWorkspaceFileForNewLocation ( JSON . stringify ( newWorkspace , null , '\t' ) , configPathURI , false , configPathURI ) ;
269+ await this . textFileService . create ( configPathURI , newRawWorkspaceContents ) ;
270+ }
271+
243272 private handleWorkspaceConfigurationEditingError ( error : JSONEditingError ) : void {
244273 switch ( error . code ) {
245274 case JSONEditingErrorCode . ERROR_INVALID_FILE :
0 commit comments