diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index 5553baaf07dd2..001025ed63f7f 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -72,11 +72,37 @@ interface IOpenBrowserWindowOptions { } interface IPathResolveOptions { + + /** + * By default, resolving a path will check + * if the path exists. This can be disabled + * with this flag. + */ readonly ignoreFileNotFound?: boolean; + + /** + * Will reject a path if it points to a transient + * workspace as indicated by a `transient: true` + * property in the workspace file. + */ + readonly rejectTransientWorkspaces?: boolean; + + /** + * If enabled, will resolve the path line/column + * aware and properly remove this information + * from the resulting file path. + */ readonly gotoLineMode?: boolean; + + /** + * Forces to resolve the provided path as workspace + * file instead of opening it as a file. + */ readonly forceOpenWorkspaceAsFile?: boolean; + /** - * The remoteAuthority to use if the URL to open is neither file nor vscode-remote + * The remoteAuthority to use if the URL to open is + * neither `file` nor `vscode-remote`. */ readonly remoteAuthority?: string; } @@ -209,9 +235,12 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic const foldersToAdd: ISingleFolderWorkspacePathToOpen[] = []; const foldersToOpen: ISingleFolderWorkspacePathToOpen[] = []; + const workspacesToOpen: IWorkspacePathToOpen[] = []; - const workspacesToRestore: IWorkspacePathToOpen[] = []; - const emptyToRestore: IEmptyWindowBackupInfo[] = []; + const untitledWorkspacesToRestore: IWorkspacePathToOpen[] = []; + + const emptyWindowsWithBackupsToRestore: IEmptyWindowBackupInfo[] = []; + let filesToOpen: IFilesToOpen | undefined; let emptyToOpen = 0; @@ -235,7 +264,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic } filesToOpen.filesToOpenOrCreate.push(path); } else if (path.backupPath) { - emptyToRestore.push({ backupFolder: basename(path.backupPath), remoteAuthority: path.remoteAuthority }); + emptyWindowsWithBackupsToRestore.push({ backupFolder: basename(path.backupPath), remoteAuthority: path.remoteAuthority }); } else { emptyToOpen++; } @@ -257,19 +286,19 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic if (openConfig.initialStartup) { // Untitled workspaces are always restored - workspacesToRestore.push(...this.workspacesManagementMainService.getUntitledWorkspacesSync()); - workspacesToOpen.push(...workspacesToRestore); + untitledWorkspacesToRestore.push(...this.workspacesManagementMainService.getUntitledWorkspacesSync()); + workspacesToOpen.push(...untitledWorkspacesToRestore); // Empty windows with backups are always restored - emptyToRestore.push(...this.backupMainService.getEmptyWindowBackupPaths()); + emptyWindowsWithBackupsToRestore.push(...this.backupMainService.getEmptyWindowBackupPaths()); } else { - emptyToRestore.length = 0; + emptyWindowsWithBackupsToRestore.length = 0; } // Open based on config - const { windows: usedWindows, filesOpenedInWindow } = this.doOpen(openConfig, workspacesToOpen, foldersToOpen, emptyToRestore, emptyToOpen, filesToOpen, foldersToAdd); + const { windows: usedWindows, filesOpenedInWindow } = this.doOpen(openConfig, workspacesToOpen, foldersToOpen, emptyWindowsWithBackupsToRestore, emptyToOpen, filesToOpen, foldersToAdd); - this.logService.trace(`windowsManager#open used window count ${usedWindows.length} (workspacesToOpen: ${workspacesToOpen.length}, foldersToOpen: ${foldersToOpen.length}, emptyToRestore: ${emptyToRestore.length}, emptyToOpen: ${emptyToOpen})`); + this.logService.trace(`windowsManager#open used window count ${usedWindows.length} (workspacesToOpen: ${workspacesToOpen.length}, foldersToOpen: ${foldersToOpen.length}, emptyToRestore: ${emptyWindowsWithBackupsToRestore.length}, emptyToOpen: ${emptyToOpen})`); // Make sure to pass focus to the most relevant of the windows if we open multiple if (usedWindows.length > 1) { @@ -300,8 +329,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic for (let i = usedWindows.length - 1; i >= 0; i--) { const usedWindow = usedWindows[i]; if ( - (usedWindow.openedWorkspace && workspacesToRestore.some(workspace => usedWindow.openedWorkspace && workspace.workspace.id === usedWindow.openedWorkspace.id)) || // skip over restored workspace - (usedWindow.backupPath && emptyToRestore.some(empty => usedWindow.backupPath && empty.backupFolder === basename(usedWindow.backupPath))) // skip over restored empty window + (usedWindow.openedWorkspace && untitledWorkspacesToRestore.some(workspace => usedWindow.openedWorkspace && workspace.workspace.id === usedWindow.openedWorkspace.id)) || // skip over restored workspace + (usedWindow.backupPath && emptyWindowsWithBackupsToRestore.some(empty => usedWindow.backupPath && empty.backupFolder === basename(usedWindow.backupPath))) // skip over restored empty window ) { continue; } @@ -810,7 +839,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic // Workspaces if (lastSessionWindow.workspace) { - const pathToOpen = this.resolveOpenable({ workspaceUri: lastSessionWindow.workspace.configPath }, { remoteAuthority: lastSessionWindow.remoteAuthority }); + const pathToOpen = this.resolveOpenable({ workspaceUri: lastSessionWindow.workspace.configPath }, { remoteAuthority: lastSessionWindow.remoteAuthority, rejectTransientWorkspaces: true /* https://github.com/microsoft/vscode/issues/119695 */ }); if (isWorkspacePathToOpen(pathToOpen)) { pathsToOpen.push(pathToOpen); } @@ -850,7 +879,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic return restoreWindows; } - private resolveOpenable(openable: IWindowOpenable, options: IPathResolveOptions = {}): IPathToOpen | undefined { + private resolveOpenable(openable: IWindowOpenable, options: IPathResolveOptions = Object.create(null)): IPathToOpen | undefined { // handle file:// openables with some extra validation let uri = this.resourceFromOpenable(openable); @@ -927,6 +956,16 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic if (!options.forceOpenWorkspaceAsFile) { const workspace = this.workspacesManagementMainService.resolveLocalWorkspaceSync(URI.file(path)); if (workspace) { + + // If the workspace is transient and we are to ignore + // transient workspaces, reject it. Also remove traces + // in the history if any. + if (workspace.transient && options.rejectTransientWorkspaces) { + this.workspacesHistoryMainService.removeRecentlyOpened([URI.file(path)]); + + return undefined; + } + return { workspace: { id: workspace.id, configPath: workspace.configPath }, remoteAuthority: workspace.remoteAuthority, exists: true }; } }