Skip to content

Commit

Permalink
Support 'code -rw' in running instance and wait until tab gets closed (
Browse files Browse the repository at this point in the history
…fixes #24327)
  • Loading branch information
bpasero committed Sep 11, 2017
1 parent 2c385b9 commit fa269df
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 57 deletions.
4 changes: 2 additions & 2 deletions src/vs/code/electron-main/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down
5 changes: 1 addition & 4 deletions src/vs/code/electron-main/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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.
Expand Down
68 changes: 49 additions & 19 deletions src/vs/code/electron-main/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -77,6 +77,7 @@ interface IOpenBrowserWindowOptions {
filesToOpen?: IPath[];
filesToCreate?: IPath[];
filesToDiff?: IPath[];
filesToWait?: IPathsToWaitFor;

forceNewWindow?: boolean;
windowToUse?: CodeWindow;
Expand Down Expand Up @@ -120,6 +121,9 @@ export class WindowsManager implements IWindowsMainService {
private _onWindowClose = new Emitter<number>();
onWindowClose: CommonEvent<number> = this._onWindowClose.event;

private _onWindowLoad = new Emitter<number>();
onWindowLoad: CommonEvent<number> = this._onWindowLoad.event;

private _onActiveWindowChanged = new Emitter<CodeWindow>();
onActiveWindowChanged: CommonEvent<CodeWindow> = this._onActiveWindowChanged.event;

Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -481,6 +491,7 @@ export class WindowsManager implements IWindowsMainService {
filesToOpen: IPath[],
filesToCreate: IPath[],
filesToDiff: IPath[],
filesToWait: IPathsToWaitFor,
foldersToAdd: IPath[]
) {
const usedWindows: CodeWindow[] = [];
Expand Down Expand Up @@ -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;
}
}

Expand All @@ -555,13 +567,15 @@ export class WindowsManager implements IWindowsMainService {
filesToOpen,
filesToCreate,
filesToDiff,
filesToWait,
forceNewWindow: true
}));

// Reset these because we handled them
filesToOpen = [];
filesToCreate = [];
filesToDiff = [];
filesToWait = void 0;
}
}

Expand All @@ -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
}
Expand All @@ -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
});
Expand All @@ -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
}
Expand All @@ -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
});
Expand All @@ -651,6 +669,7 @@ export class WindowsManager implements IWindowsMainService {
filesToOpen,
filesToCreate,
filesToDiff,
filesToWait,
forceNewWindow: true,
emptyWindowBackupFolder
}));
Expand All @@ -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
});
Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -711,6 +731,7 @@ export class WindowsManager implements IWindowsMainService {
filesToOpen,
filesToCreate,
filesToDiff,
filesToWait,
forceNewWindow: openInNewWindow,
windowToUse
});
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1122,6 +1144,9 @@ export class WindowsManager implements IWindowsMainService {

// Load it
window.load(configuration);

// Signal event
this._onWindowLoad.fire(window.id);
}
});

Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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<void> {
public waitForWindowCloseOrLoad(windowId: number): TPromise<void> {
return new TPromise<void>(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));
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/environment/node/argv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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 <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."),
Expand Down
6 changes: 6 additions & 0 deletions src/vs/platform/windows/common/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/platform/windows/electron-main/windows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export interface IWindowsMainService {
pickFileAndOpen(options: INativeOpenDialogOptions): void;
focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow;
getLastActiveWindow(): ICodeWindow;
waitForWindowClose(windowId: number): TPromise<void>;
waitForWindowCloseOrLoad(windowId: number): TPromise<void>;
openNewWindow(context: OpenContext): void;
sendToFocused(channel: string, ...args: any[]): void;
sendToAll(channel: string, payload: any, windowIdsToIgnore?: number[]): void;
Expand Down
Loading

0 comments on commit fa269df

Please sign in to comment.