diff --git a/src/vs/code/electron-main/launch.ts b/src/vs/code/electron-main/launch.ts index 7c56c411513f3..26a5dad20644a 100644 --- a/src/vs/code/electron-main/launch.ts +++ b/src/vs/code/electron-main/launch.ts @@ -104,7 +104,7 @@ export class LaunchService implements ILaunchService { context, cli: args, userEnv, - forceNewWindow: args.wait || args['new-window'], + forceNewWindow: args['new-window'], preferNewWindow: !args['reuse-window'], forceReuseWindow: args['reuse-window'], diffMode: args.diff, @@ -115,7 +115,7 @@ export class LaunchService implements ILaunchService { // If the other instance is waiting to be killed, we hook up a window listener if one window // is being used and only then resolve the startup promise which will kill this second instance if (args.wait && usedWindows.length === 1 && usedWindows[0]) { - return this.windowsService.waitForWindowClose(usedWindows[0].id); + return this.windowsService.waitForWindowCloseOrLoad(usedWindows[0].id); } return TPromise.as(null); diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index f35d9a4545ef3..d32f47dc289e1 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -279,10 +279,6 @@ export class CodeWindow implements ICodeWindow { return this.currentConfig ? this.currentConfig.folderPath : void 0; } - public get openedFilePath(): string { - return this.currentConfig && this.currentConfig.filesToOpen && this.currentConfig.filesToOpen[0] && this.currentConfig.filesToOpen[0].filePath; - } - public setReady(): void { this._readyState = ReadyState.READY; @@ -516,6 +512,7 @@ export class CodeWindow implements ICodeWindow { delete configuration.filesToOpen; delete configuration.filesToCreate; delete configuration.filesToDiff; + delete configuration.filesToWait; // Some configuration things get inherited if the window is being reloaded and we are // in extension development mode. These options are all development related. diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 914a7514c1ff9..f5cc159bdb6c3 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -19,7 +19,7 @@ import { IPathWithLineAndColumn, parseLineAndColumnAware } from 'vs/code/node/pa import { ILifecycleService, UnloadReason, IWindowUnloadEvent } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; -import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, ReadyState } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, ReadyState, IPathsToWaitFor } from 'vs/platform/windows/common/windows'; import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderPath } from 'vs/code/node/windowsFinder'; import CommonEvent, { Emitter } from 'vs/base/common/event'; import product from 'vs/platform/node/product'; @@ -77,6 +77,7 @@ interface IOpenBrowserWindowOptions { filesToOpen?: IPath[]; filesToCreate?: IPath[]; filesToDiff?: IPath[]; + filesToWait?: IPathsToWaitFor; forceNewWindow?: boolean; windowToUse?: CodeWindow; @@ -120,6 +121,9 @@ export class WindowsManager implements IWindowsMainService { private _onWindowClose = new Emitter(); onWindowClose: CommonEvent = this._onWindowClose.event; + private _onWindowLoad = new Emitter(); + onWindowLoad: CommonEvent = this._onWindowLoad.event; + private _onActiveWindowChanged = new Emitter(); onActiveWindowChanged: CommonEvent = this._onActiveWindowChanged.event; @@ -376,6 +380,12 @@ export class WindowsManager implements IWindowsMainService { filesToCreate = []; // diff ignores other files that do not exist } + // When run with --wait, make sure we keep the paths to wait for + let filesToWait: IPathsToWaitFor; + if (openConfig.cli.wait && openConfig.cli.waitMarkerFilePath) { + filesToWait = { paths: [...filesToDiff, ...filesToOpen, ...filesToCreate], waitMarkerFilePath: openConfig.cli.waitMarkerFilePath }; + } + // // These are windows to open to show workspaces // @@ -409,7 +419,7 @@ export class WindowsManager implements IWindowsMainService { const emptyToOpen = pathsToOpen.filter(win => !win.workspace && !win.folderPath && !win.filePath && !win.backupPath).length; // Open based on config - const usedWindows = this.doOpen(openConfig, workspacesToOpen, workspacesToRestore, foldersToOpen, foldersToRestore, emptyToRestore, emptyToOpen, filesToOpen, filesToCreate, filesToDiff, foldersToAdd); + const usedWindows = this.doOpen(openConfig, workspacesToOpen, workspacesToRestore, foldersToOpen, foldersToRestore, emptyToRestore, emptyToOpen, filesToOpen, filesToCreate, filesToDiff, filesToWait, foldersToAdd); // Make sure to pass focus to one of the windows if we open multiple if (usedWindows.length > 1) { @@ -451,10 +461,10 @@ export class WindowsManager implements IWindowsMainService { } // If we got started with --wait from the CLI, we need to signal to the outside when the window - // used for the edit operation is closed so that the waiting process can continue. We do this by - // deleting the waitMarkerFilePath. + // used for the edit operation is closed or loaded to a different folder so that the waiting + // process can continue. We do this by deleting the waitMarkerFilePath. if (openConfig.context === OpenContext.CLI && openConfig.cli.wait && openConfig.cli.waitMarkerFilePath && usedWindows.length === 1 && usedWindows[0]) { - this.waitForWindowClose(usedWindows[0].id).done(() => fs.unlink(openConfig.cli.waitMarkerFilePath, error => void 0)); + this.waitForWindowCloseOrLoad(usedWindows[0].id).done(() => fs.unlink(openConfig.cli.waitMarkerFilePath, error => void 0)); } return usedWindows; @@ -481,6 +491,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], + filesToWait: IPathsToWaitFor, foldersToAdd: IPath[] ) { const usedWindows: CodeWindow[] = []; @@ -532,12 +543,13 @@ export class WindowsManager implements IWindowsMainService { else { // Do open files - usedWindows.push(this.doOpenFilesInExistingWindow(bestWindowOrFolder, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFilesInExistingWindow(bestWindowOrFolder, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; } } @@ -555,6 +567,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen, filesToCreate, filesToDiff, + filesToWait, forceNewWindow: true })); @@ -562,6 +575,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; } } @@ -575,12 +589,13 @@ export class WindowsManager implements IWindowsMainService { const windowOnWorkspace = windowsOnWorkspace[0]; // Do open files - usedWindows.push(this.doOpenFilesInExistingWindow(windowOnWorkspace, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFilesInExistingWindow(windowOnWorkspace, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then } @@ -592,12 +607,13 @@ export class WindowsManager implements IWindowsMainService { } // Do open folder - usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { workspace: workspaceToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { workspace: workspaceToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then }); @@ -613,12 +629,13 @@ export class WindowsManager implements IWindowsMainService { const windowOnFolderPath = windowsOnFolderPath[0]; // Do open files - usedWindows.push(this.doOpenFilesInExistingWindow(windowOnFolderPath, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFilesInExistingWindow(windowOnFolderPath, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then } @@ -630,12 +647,13 @@ export class WindowsManager implements IWindowsMainService { } // Do open folder - usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { folderPath: folderToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff)); + usedWindows.push(this.doOpenFolderOrWorkspace(openConfig, { folderPath: folderToOpen }, openFolderInNewWindow, filesToOpen, filesToCreate, filesToDiff, filesToWait)); // Reset these because we handled them filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then }); @@ -651,6 +669,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen, filesToCreate, filesToDiff, + filesToWait, forceNewWindow: true, emptyWindowBackupFolder })); @@ -659,6 +678,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen = []; filesToCreate = []; filesToDiff = []; + filesToWait = void 0; openFolderInNewWindow = true; // any other folders to open must open in new window then }); @@ -681,11 +701,11 @@ export class WindowsManager implements IWindowsMainService { return arrays.distinct(usedWindows); } - private doOpenFilesInExistingWindow(window: CodeWindow, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[]): CodeWindow { + private doOpenFilesInExistingWindow(window: CodeWindow, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], filesToWait: IPathsToWaitFor): CodeWindow { window.focus(); // make sure window has focus window.ready().then(readyWindow => { - readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff }); + readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff, filesToWait }); }); return window; @@ -701,7 +721,7 @@ export class WindowsManager implements IWindowsMainService { return window; } - private doOpenFolderOrWorkspace(openConfig: IOpenConfiguration, folderOrWorkspace: IPathToOpen, openInNewWindow: boolean, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], windowToUse?: CodeWindow): CodeWindow { + private doOpenFolderOrWorkspace(openConfig: IOpenConfiguration, folderOrWorkspace: IPathToOpen, openInNewWindow: boolean, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], filesToWait: IPathsToWaitFor, windowToUse?: CodeWindow): CodeWindow { const browserWindow = this.openInBrowserWindow({ userEnv: openConfig.userEnv, cli: openConfig.cli, @@ -711,6 +731,7 @@ export class WindowsManager implements IWindowsMainService { filesToOpen, filesToCreate, filesToDiff, + filesToWait, forceNewWindow: openInNewWindow, windowToUse }); @@ -1028,6 +1049,7 @@ export class WindowsManager implements IWindowsMainService { configuration.filesToOpen = options.filesToOpen; configuration.filesToCreate = options.filesToCreate; configuration.filesToDiff = options.filesToDiff; + configuration.filesToWait = options.filesToWait; configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir; // if we know the backup folder upfront (for empty windows to restore), we can set it @@ -1122,6 +1144,9 @@ export class WindowsManager implements IWindowsMainService { // Load it window.load(configuration); + + // Signal event + this._onWindowLoad.fire(window.id); } }); @@ -1361,8 +1386,8 @@ export class WindowsManager implements IWindowsMainService { } private onBeforeWindowUnload(e: IWindowUnloadEvent): void { - const windowClosing = e.reason === UnloadReason.CLOSE; - const windowLoading = e.reason === UnloadReason.LOAD; + const windowClosing = (e.reason === UnloadReason.CLOSE); + const windowLoading = (e.reason === UnloadReason.LOAD); if (!windowClosing && !windowLoading) { return; // only interested when window is closing or loading } @@ -1470,14 +1495,19 @@ export class WindowsManager implements IWindowsMainService { this.open({ context, cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true }); } - public waitForWindowClose(windowId: number): TPromise { + public waitForWindowCloseOrLoad(windowId: number): TPromise { return new TPromise(c => { - const toDispose = this.onWindowClose(id => { + function handler(id: number) { if (id === windowId) { - toDispose.dispose(); + closeListener.dispose(); + loadListener.dispose(); + c(null); } - }); + } + + const closeListener = this.onWindowClose(id => handler(id)); + const loadListener = this.onWindowLoad(id => handler(id)); }); } diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 7f81ffa9d2f12..ad6e24e0eb299 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -129,7 +129,7 @@ export const optionsHelp: { [name: string]: string; } = { '-r, --reuse-window': localize('reuseWindow', "Force opening a file or folder in the last active window."), '--user-data-dir ': localize('userDataDir', "Specifies the directory that user data is kept in, useful when running as root."), '--verbose': localize('verbose', "Print verbose output (implies --wait)."), - '-w, --wait': localize('wait', "Wait for the window to be closed before returning."), + '-w, --wait': localize('wait', "Wait for the files to be closed before returning."), '--extensions-dir ': localize('extensionHomePath', "Set the root path for extensions."), '--list-extensions': localize('listExtensions', "List the installed extensions."), '--show-versions': localize('showVersions', "Show versions of installed extensions, when using --list-extension."), diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index cbb0bd1434b4b..9340cb81583bc 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -203,10 +203,16 @@ export interface IPath { columnNumber?: number; } +export interface IPathsToWaitFor { + paths: IPath[]; + waitMarkerFilePath: string; +} + export interface IOpenFileRequest { filesToOpen?: IPath[]; filesToCreate?: IPath[]; filesToDiff?: IPath[]; + filesToWait?: IPathsToWaitFor; } export interface IAddFoldersRequest { diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 2e5d618c2a7db..e6fdc9f9940fb 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -68,7 +68,7 @@ export interface IWindowsMainService { pickFileAndOpen(options: INativeOpenDialogOptions): void; focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow; getLastActiveWindow(): ICodeWindow; - waitForWindowClose(windowId: number): TPromise; + waitForWindowCloseOrLoad(windowId: number): TPromise; openNewWindow(context: OpenContext): void; sendToFocused(channel: string, ...args: any[]): void; sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void; diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 0bef05ddb8e7d..947b60ef70835 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -17,7 +17,7 @@ import Severity from 'vs/base/common/severity'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IAction, Action } from 'vs/base/common/actions'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { AutoSaveConfiguration, IFileService } from 'vs/platform/files/common/files'; import { toResource } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService, IResourceInputType } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; @@ -77,7 +77,8 @@ export class ElectronWindow extends Themable { @IEnvironmentService private environmentService: IEnvironmentService, @ITelemetryService private telemetryService: ITelemetryService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @IFileService private fileService: IFileService ) { super(themeService); @@ -293,7 +294,7 @@ export class ElectronWindow extends Themable { // Single folder or no workspace: create workspace and open else { - let workspaceFolders: URI[] = []; + const workspaceFolders: URI[] = []; // Folder of workspace is the first of multi root workspace, so add it if (this.contextService.hasFolderWorkspace()) { @@ -309,8 +310,8 @@ export class ElectronWindow extends Themable { } private onOpenFiles(request: IOpenFileRequest): void { - let inputs: IResourceInputType[] = []; - let diffMode = (request.filesToDiff.length === 2); + const inputs: IResourceInputType[] = []; + const diffMode = (request.filesToDiff.length === 2); if (!diffMode && request.filesToOpen) { inputs.push(...this.toInputs(request.filesToOpen, false)); @@ -327,12 +328,26 @@ export class ElectronWindow extends Themable { if (inputs.length) { this.openResources(inputs, diffMode).done(null, errors.onUnexpectedError); } + + if (request.filesToWait && inputs.length) { + // In wait mode, listen to changes to the editors and wait until the files + // are closed that the user wants to wait for. When this happens we delete + // the wait marker file to signal to the outside that editing is done. + const resourcesToWaitFor = request.filesToWait.paths.map(p => URI.file(p.filePath)); + const waitMarkerFile = URI.file(request.filesToWait.waitMarkerFilePath); + const stacks = this.editorGroupService.getStacksModel(); + const unbind = stacks.onEditorClosed(() => { + if (resourcesToWaitFor.every(r => !stacks.isOpen(r))) { + unbind.dispose(); + this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError); + } + }); + } } private openResources(resources: (IResourceInput | IUntitledResourceInput)[], diffMode: boolean): TPromise { return this.partService.joinCreation().then((): TPromise => { - // In diffMode we open 2 resources as diff if (diffMode && resources.length === 2) { return this.editorService.openEditor({ leftResource: resources[0].resource, rightResource: resources[1].resource, options: { pinned: true } }); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 04db9a58944a5..cdaf31c800180 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -181,6 +181,7 @@ export class Workbench implements IPartService { private backupFileService: IBackupFileService; private configurationEditingService: IConfigurationEditingService; private workspaceMigrationService: WorkspaceMigrationService; + private fileService: IFileService; private titlebarPart: TitlebarPart; private activitybarPart: ActivitybarPart; private sidebarPart: SidebarPart; @@ -421,14 +422,13 @@ export class Workbench implements IPartService { } private resolveEditorsToOpen(): TPromise { + const config = this.workbenchParams.configuration; // Files to open, diff or create if (this.hasFilesToCreateOpenOrDiff) { - const filesToCreate = this.toInputs(this.workbenchParams.configuration.filesToCreate); - const filesToOpen = this.toInputs(this.workbenchParams.configuration.filesToOpen); - const filesToDiff = this.toInputs(this.workbenchParams.configuration.filesToDiff); // Files to diff is exclusive + const filesToDiff = this.toInputs(config.filesToDiff, false); if (filesToDiff && filesToDiff.length === 2) { return TPromise.as([{ leftResource: filesToDiff[0].resource, @@ -437,17 +437,11 @@ export class Workbench implements IPartService { }]); } - // Otherwise: Open/Create files - else { - const filesToCreateInputs: IUntitledResourceInput[] = filesToCreate.map(resourceInput => { - return { - filePath: resourceInput.resource.fsPath, - options: { pinned: true } - }; - }); + const filesToCreate = this.toInputs(config.filesToCreate, true); + const filesToOpen = this.toInputs(config.filesToOpen, false); - return TPromise.as([].concat(filesToOpen).concat(filesToCreateInputs)); - } + // Otherwise: Open/Create files + return TPromise.as([...filesToOpen, ...filesToCreate]); } // Empty workbench @@ -468,20 +462,21 @@ export class Workbench implements IPartService { return TPromise.as([]); } - private toInputs(paths?: IPath[]): IResourceInput[] { + private toInputs(paths: IPath[], isNew: boolean): (IResourceInput | IUntitledResourceInput)[] { if (!paths || !paths.length) { return []; } return paths.map(p => { - const input = {}; - input.resource = URI.file(p.filePath); - - input.options = { - pinned: true // opening on startup is always pinned and not preview - }; + const resource = URI.file(p.filePath); + let input: IResourceInput | IUntitledResourceInput; + if (isNew) { + input = { filePath: resource.fsPath, options: { pinned: true } } as IUntitledResourceInput; + } else { + input = { resource, options: { pinned: true } } as IResourceInput; + } - if (p.lineNumber) { + if (!isNew && p.lineNumber) { input.options.selection = { startLineNumber: p.lineNumber, startColumn: p.columnNumber @@ -579,9 +574,9 @@ export class Workbench implements IPartService { serviceCollection.set(ITitleService, this.titlebarPart); // File Service - const fileService = this.instantiationService.createInstance(RemoteFileService); - serviceCollection.set(IFileService, fileService); - this.toDispose.push(fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e))); + this.fileService = this.instantiationService.createInstance(RemoteFileService); + serviceCollection.set(IFileService, this.fileService); + this.toDispose.push(this.fileService.onFileChanges(e => this.configurationService.handleWorkspaceFileEvents(e))); // History serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService)); @@ -994,6 +989,16 @@ export class Workbench implements IPartService { // Listen to editor changes this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged())); + // Listen to editor closing (if we run with --wait) + const filesToWait = this.workbenchParams.configuration.filesToWait; + if (filesToWait) { + const resourcesToWaitFor = filesToWait.paths.map(p => URI.file(p.filePath)); + const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath); + const listenerDispose = this.editorPart.getStacksModel().onEditorClosed(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile)); + + this.toDispose.push(listenerDispose); + } + // Handle message service and quick open events this.toDispose.push((this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true))); this.toDispose.push((this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset())); @@ -1032,6 +1037,18 @@ export class Workbench implements IPartService { } } + private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void { + + // In wait mode, listen to changes to the editors and wait until the files + // are closed that the user wants to wait for. When this happens we delete + // the wait marker file to signal to the outside that editing is done. + const stacks = this.editorPart.getStacksModel(); + if (resourcesToWaitFor.every(r => !stacks.isOpen(r))) { + listenerDispose.dispose(); + this.fileService.del(waitMarkerFile).done(null, errors.onUnexpectedError); + } + } + private onEditorsChanged(): void { const visibleEditors = this.editorService.getVisibleEditors().length;