debt - move enterWorkspace into workspace service

This commit is contained in:
Benjamin Pasero
2019-09-30 11:35:50 +02:00
parent 65c65e2697
commit 25fb4bcd78
24 changed files with 420 additions and 329 deletions

View File

@@ -384,8 +384,7 @@ export class CodeApplication extends Disposable {
}
// Setup Auth Handler
const authHandler = appInstantiationService.createInstance(ProxyAuthHandler);
this._register(authHandler);
this._register(new ProxyAuthHandler());
// Open Windows
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));

View File

@@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { Disposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { BrowserWindow, app, AuthInfo, WebContents, Event as ElectronEvent } from 'electron';
@@ -22,18 +21,21 @@ type Credentials = {
password: string;
};
export class ProxyAuthHandler {
export class ProxyAuthHandler extends Disposable {
_serviceBrand: undefined;
private retryCount = 0;
private disposables: IDisposable[] = [];
constructor(
@IWindowsMainService private readonly windowsMainService: IWindowsMainService
) {
constructor() {
super();
this.registerListeners();
}
private registerListeners(): void {
const onLogin = Event.fromNodeEventEmitter<LoginEvent>(app, 'login', (event, webContents, req, authInfo, cb) => ({ event, webContents, req, authInfo, cb }));
onLogin(this.onLogin, this, this.disposables);
this._register(onLogin(this.onLogin, this));
}
private onLogin({ event, authInfo, cb }: LoginEvent): void {
@@ -61,10 +63,9 @@ export class ProxyAuthHandler {
}
};
const focusedWindow = this.windowsMainService.getFocusedWindow();
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
opts.parent = focusedWindow.win;
opts.parent = focusedWindow;
opts.modal = true;
}
@@ -89,8 +90,4 @@ export class ProxyAuthHandler {
win.close();
});
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}

View File

@@ -20,20 +20,20 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows';
import { INativeOpenDialogOptions } from 'vs/platform/dialogs/node/dialogs';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/code/node/windowsFinder';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/platform/windows/node/window';
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
import product from 'vs/platform/product/common/product';
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
import { IProcessEnvironment, isMacintosh, isWindows } from 'vs/base/common/platform';
import { IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IEnterWorkspaceResult, IRecent } from 'vs/platform/workspaces/common/workspaces';
import { IWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, hasWorkspaceFileExtension, IRecent } from 'vs/platform/workspaces/common/workspaces';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { dirExists } from 'vs/base/node/pfs';
import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources';
import { getComparisonKey, isEqual, normalizePath, originalFSPath, hasTrailingPathSeparator, removeTrailingPathSeparator } from 'vs/base/common/resources';
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage';
import { getWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
@@ -167,8 +167,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
private readonly windowsState: IWindowsState;
private lastClosedWindowState?: IWindowState;
private readonly workspacesManager: WorkspacesManager;
private readonly _onWindowReady = this._register(new Emitter<ICodeWindow>());
readonly onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
@@ -203,8 +201,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.windowsState.openedWindows = [];
}
this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this, dialogMainService);
this.lifecycleMainService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex());
}
@@ -259,6 +255,11 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.lastClosedWindowState = undefined;
}
});
// Signal a window is ready after having entered a workspace
this._register(this.workspacesMainService.onWorkspaceEntered(event => {
this._onWindowReady.fire(event.window);
}));
}
// Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS:
@@ -857,7 +858,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
path.label = pathToOpen.label;
pathsToOpen.push(path);
} else {
const uri = resourceFromURIToOpen(pathToOpen);
const uri = this.resourceFromURIToOpen(pathToOpen);
// Warn about the invalid URI or path
let message, detail;
if (uri.scheme === Schemas.file) {
@@ -1020,7 +1022,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return undefined;
}
let uri = resourceFromURIToOpen(toOpen);
let uri = this.resourceFromURIToOpen(toOpen);
if (uri.scheme === Schemas.file) {
return this.parsePath(uri.fsPath, options, isFileToOpen(toOpen));
}
@@ -1069,6 +1071,18 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
};
}
private resourceFromURIToOpen(openable: IWindowOpenable): URI {
if (isWorkspaceToOpen(openable)) {
return openable.workspaceUri;
}
if (isFolderToOpen(openable)) {
return openable.folderUri;
}
return openable.fileUri;
}
private parsePath(anyPath: string, options: IPathParseOptions, forceOpenWorkspaceAsFile?: boolean): IPathToOpen | undefined {
if (!anyPath) {
return undefined;
@@ -1183,7 +1197,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return { openFolderInNewWindow: !!openFolderInNewWindow, openFilesInNewWindow };
}
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): void {
openExtensionDevelopmentHostWindow(extensionDevelopmentPath: string[], openConfig: IOpenConfiguration): ICodeWindow[] {
// Reload an existing extension development host window on the same path
// We currently do not allow more than one extension development window
@@ -1193,7 +1207,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.reload(existingWindow, openConfig.cli);
existingWindow.focus(); // make sure it gets focus and is restored
return;
return [existingWindow];
}
let folderUris = openConfig.cli['folder-uri'] || [];
let fileUris = openConfig.cli['file-uri'] || [];
@@ -1284,7 +1298,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
noRecentEntry: true,
waitMarkerFileURI: openConfig.waitMarkerFileURI
};
this.open(openArgs);
return this.open(openArgs);
}
private openInBrowserWindow(options: IOpenBrowserWindowOptions): ICodeWindow {
@@ -1578,23 +1593,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
});
}
async enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined> {
const result = await this.workspacesManager.enterWorkspace(win, path);
return result ? this.doEnterWorkspace(win, result) : undefined;
}
private doEnterWorkspace(win: ICodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult {
// Mark as recently opened
this.workspacesHistoryMainService.addRecentlyOpened([{ workspace: result.workspace }]);
// Trigger Eevent to indicate load of workspace into window
this._onWindowReady.fire(win);
return result;
}
focusLastActive(cli: ParsedArgs, context: OpenContext): ICodeWindow {
const lastActive = this.getLastActiveWindow();
if (lastActive) {
@@ -1611,7 +1609,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return getLastActiveWindow(WindowsManager.WINDOWS);
}
getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined {
private getLastActiveWindowForAuthority(remoteAuthority: string | undefined): ICodeWindow | undefined {
return getLastActiveWindow(WindowsManager.WINDOWS.filter(window => window.remoteAuthority === remoteAuthority));
}
@@ -1628,10 +1626,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
return this.open({ context, cli, forceEmpty: true, forceNewWindow, forceReuseWindow });
}
openNewTabbedWindow(context: OpenContext): ICodeWindow[] {
return this.open({ context, cli: this.environmentService.args, forceNewTabbedWindow: true, forceEmpty: true });
}
waitForWindowCloseOrLoad(windowId: number): Promise<void> {
return new Promise<void>(resolve => {
function handler(id: number) {
@@ -1666,7 +1660,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
getFocusedWindow(): ICodeWindow | undefined {
private getFocusedWindow(): ICodeWindow | undefined {
const win = BrowserWindow.getFocusedWindow();
if (win) {
return this.getWindowById(win.id);
@@ -1860,88 +1854,3 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
}
}
}
class WorkspacesManager {
constructor(
private readonly workspacesMainService: IWorkspacesMainService,
private readonly backupMainService: IBackupMainService,
private readonly windowsMainService: IWindowsMainService,
private readonly dialogMainService: IDialogMainService
) { }
async enterWorkspace(window: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | null> {
if (!window || !window.win || !window.isReady) {
return null; // return early if the window is not ready or disposed
}
const isValid = await this.isValidTargetWorkspacePath(window, path);
if (!isValid) {
return null; // return early if the workspace is not valid
}
return this.doOpenWorkspace(window, getWorkspaceIdentifier(path));
}
private async isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise<boolean> {
if (!path) {
return true;
}
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) {
return false; // window is already opened on a workspace with that path
}
// Prevent overwriting a workspace that is currently opened in another window
if (findWindowOnWorkspace(this.windowsMainService.getWindows(), getWorkspaceIdentifier(path))) {
const options: MessageBoxOptions = {
title: product.nameLong,
type: 'info',
buttons: [localize('ok', "OK")],
message: localize('workspaceOpenedMessage', "Unable to save workspace '{0}'", resourcesBasename(path)),
detail: localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."),
noLink: true
};
await this.dialogMainService.showMessageBox(options, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
return false;
}
return true; // OK
}
private doOpenWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult {
window.focus();
// Register window for backups and migrate current backups over
let backupPath: string | undefined;
if (!window.config.extensionDevelopmentPath) {
backupPath = this.backupMainService.registerWorkspaceBackupSync({ workspace, remoteAuthority: window.remoteAuthority }, window.config.backupPath);
}
// if the window was opened on an untitled workspace, delete it.
if (window.openedWorkspace && this.workspacesMainService.isUntitledWorkspace(window.openedWorkspace)) {
this.workspacesMainService.deleteUntitledWorkspaceSync(window.openedWorkspace);
}
// Update window configuration properly based on transition to workspace
window.config.folderUri = undefined;
window.config.workspace = workspace;
window.config.backupPath = backupPath;
return { workspace, backupPath };
}
}
function resourceFromURIToOpen(openable: IWindowOpenable): URI {
if (isWorkspaceToOpen(openable)) {
return openable.workspaceUri;
}
if (isFolderToOpen(openable)) {
return openable.folderUri;
}
return openable.fileUri;
}

View File

@@ -35,12 +35,15 @@ export function restoreWindowsState(data: WindowsStateStorageData | undefined):
if (windowsState.lastActiveWindow) {
result.lastActiveWindow = restoreWindowState(windowsState.lastActiveWindow);
}
if (windowsState.lastPluginDevelopmentHostWindow) {
result.lastPluginDevelopmentHostWindow = restoreWindowState(windowsState.lastPluginDevelopmentHostWindow);
}
if (Array.isArray(windowsState.openedWindows)) {
result.openedWindows = windowsState.openedWindows.map(windowState => restoreWindowState(windowState));
}
return result;
}
@@ -49,9 +52,11 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState {
if (windowState.backupPath) {
result.backupPath = windowState.backupPath;
}
if (windowState.remoteAuthority) {
result.remoteAuthority = windowState.remoteAuthority;
}
if (windowState.folder) {
result.folderUri = URI.parse(windowState.folder);
} else if (windowState.folderUri) {
@@ -59,11 +64,13 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState {
} else if (windowState.folderPath) {
result.folderUri = URI.file(windowState.folderPath);
}
if (windowState.workspaceIdentifier) {
result.workspace = { id: windowState.workspaceIdentifier.id, configPath: URI.parse(windowState.workspaceIdentifier.configURIPath) };
} else if (windowState.workspace) {
result.workspace = { id: windowState.workspace.id, configPath: URI.file(windowState.workspace.configPath) };
}
return result;
}
@@ -83,4 +90,4 @@ function serializeWindowState(windowState: IWindowState): ISerializedWindowState
remoteAuthority: windowState.remoteAuthority,
uiState: windowState.uiState
};
}
}

View File

@@ -1,131 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as platform from 'vs/base/common/platform';
import * as extpath from 'vs/base/common/extpath';
import { OpenContext } from 'vs/platform/windows/common/windows';
import { IWorkspaceIdentifier, IResolvedWorkspace, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { URI } from 'vs/base/common/uri';
import { isEqual, isEqualOrParent } from 'vs/base/common/resources';
export interface ISimpleWindow {
openedWorkspace?: IWorkspaceIdentifier;
openedFolderUri?: URI;
extensionDevelopmentPath?: string[];
lastFocusTime: number;
}
export interface IBestWindowOrFolderOptions<W extends ISimpleWindow> {
windows: W[];
newWindow: boolean;
context: OpenContext;
fileUri?: URI;
userHome?: string;
codeSettingsFolder?: string;
localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null;
}
export function findBestWindowOrFolderForFile<W extends ISimpleWindow>({ windows, newWindow, context, fileUri, localWorkspaceResolver: workspaceResolver }: IBestWindowOrFolderOptions<W>): W | undefined {
if (!newWindow && fileUri && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) {
const windowOnFilePath = findWindowOnFilePath(windows, fileUri, workspaceResolver);
if (windowOnFilePath) {
return windowOnFilePath;
}
}
return !newWindow ? getLastActiveWindow(windows) : undefined;
}
function findWindowOnFilePath<W extends ISimpleWindow>(windows: W[], fileUri: URI, localWorkspaceResolver: (workspace: IWorkspaceIdentifier) => IResolvedWorkspace | null): W | null {
// First check for windows with workspaces that have a parent folder of the provided path opened
for (const window of windows) {
const workspace = window.openedWorkspace;
if (workspace) {
const resolvedWorkspace = localWorkspaceResolver(workspace);
if (resolvedWorkspace) {
// workspace could be resolved: It's in the local file system
if (resolvedWorkspace.folders.some(folder => isEqualOrParent(fileUri, folder.uri))) {
return window;
}
} else {
// use the config path instead
if (isEqualOrParent(fileUri, workspace.configPath)) {
return window;
}
}
}
}
// Then go with single folder windows that are parent of the provided file path
const singleFolderWindowsOnFilePath = windows.filter(window => window.openedFolderUri && isEqualOrParent(fileUri, window.openedFolderUri));
if (singleFolderWindowsOnFilePath.length) {
return singleFolderWindowsOnFilePath.sort((a, b) => -(a.openedFolderUri!.path.length - b.openedFolderUri!.path.length))[0];
}
return null;
}
export function getLastActiveWindow<W extends ISimpleWindow>(windows: W[]): W | undefined {
const lastFocusedDate = Math.max.apply(Math, windows.map(window => window.lastFocusTime));
return windows.filter(window => window.lastFocusTime === lastFocusedDate)[0];
}
export function findWindowOnWorkspace<W extends ISimpleWindow>(windows: W[], workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)): W | null {
if (isSingleFolderWorkspaceIdentifier(workspace)) {
for (const window of windows) {
// match on folder
if (isSingleFolderWorkspaceIdentifier(workspace)) {
if (window.openedFolderUri && isEqual(window.openedFolderUri, workspace)) {
return window;
}
}
}
} else if (isWorkspaceIdentifier(workspace)) {
for (const window of windows) {
// match on workspace
if (window.openedWorkspace && window.openedWorkspace.id === workspace.id) {
return window;
}
}
}
return null;
}
export function findWindowOnExtensionDevelopmentPath<W extends ISimpleWindow>(windows: W[], extensionDevelopmentPaths: string[]): W | null {
const matches = (uriString: string): boolean => {
return extensionDevelopmentPaths.some(p => extpath.isEqual(p, uriString, !platform.isLinux /* ignorecase */));
};
for (const window of windows) {
// match on extension development path. The path can be one or more paths or uri strings, using paths.isEqual is not 100% correct but good enough
const currPaths = window.extensionDevelopmentPath;
if (currPaths && currPaths.some(p => matches(p))) {
return window;
}
}
return null;
}
export function findWindowOnWorkspaceOrFolderUri<W extends ISimpleWindow>(windows: W[], uri: URI | undefined): W | null {
if (!uri) {
return null;
}
for (const window of windows) {
// check for workspace config path
if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, uri)) {
return window;
}
// check for folder path
if (window.openedFolderUri && isEqual(window.openedFolderUri, uri)) {
return window;
}
}
return null;
}

View File

@@ -1,128 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as path from 'vs/base/common/path';
import { findBestWindowOrFolderForFile, ISimpleWindow, IBestWindowOrFolderOptions } from 'vs/code/node/windowsFinder';
import { OpenContext } from 'vs/platform/windows/common/windows';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
import { URI } from 'vs/base/common/uri';
import { getPathFromAmdModule } from 'vs/base/common/amd';
const fixturesFolder = getPathFromAmdModule(require, './fixtures');
const testWorkspace: IWorkspaceIdentifier = {
id: Date.now().toString(),
configPath: URI.file(path.join(fixturesFolder, 'workspaces.json'))
};
const testWorkspaceFolders = toWorkspaceFolders([{ path: path.join(fixturesFolder, 'vscode_workspace_1_folder') }, { path: path.join(fixturesFolder, 'vscode_workspace_2_folder') }], testWorkspace.configPath);
function options(custom?: Partial<IBestWindowOrFolderOptions<ISimpleWindow>>): IBestWindowOrFolderOptions<ISimpleWindow> {
return {
windows: [],
newWindow: false,
context: OpenContext.CLI,
codeSettingsFolder: '_vscode',
localWorkspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, configPath: workspace.configPath, folders: testWorkspaceFolders } : null; },
...custom
};
}
const vscodeFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder')) };
const lastActiveWindow: ISimpleWindow = { lastFocusTime: 3, openedFolderUri: undefined };
const noVscodeFolderWindow: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) };
const windows: ISimpleWindow[] = [
vscodeFolderWindow,
lastActiveWindow,
noVscodeFolderWindow,
];
suite('WindowsFinder', () => {
test('New window without folder when no windows exist', () => {
assert.equal(findBestWindowOrFolderForFile(options()), null);
assert.equal(findBestWindowOrFolderForFile(options({
fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'file.txt'))
})), null);
assert.equal(findBestWindowOrFolderForFile(options({
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt')),
newWindow: true
})), null);
assert.equal(findBestWindowOrFolderForFile(options({
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt')),
})), null);
assert.equal(findBestWindowOrFolderForFile(options({
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt')),
context: OpenContext.API
})), null);
assert.equal(findBestWindowOrFolderForFile(options({
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt'))
})), null);
assert.equal(findBestWindowOrFolderForFile(options({
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'new_folder', 'new_file.txt'))
})), null);
});
test('New window without folder when windows exist', () => {
assert.equal(findBestWindowOrFolderForFile(options({
windows,
fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'file.txt')),
newWindow: true
})), null);
});
test('Last active window', () => {
assert.equal(findBestWindowOrFolderForFile(options({
windows
})), lastActiveWindow);
assert.equal(findBestWindowOrFolderForFile(options({
windows,
fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder2', 'file.txt'))
})), lastActiveWindow);
assert.equal(findBestWindowOrFolderForFile(options({
windows: [lastActiveWindow, noVscodeFolderWindow],
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt')),
})), lastActiveWindow);
assert.equal(findBestWindowOrFolderForFile(options({
windows,
fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'file.txt')),
context: OpenContext.API
})), lastActiveWindow);
});
test('Existing window with folder', () => {
assert.equal(findBestWindowOrFolderForFile(options({
windows,
fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'file.txt'))
})), noVscodeFolderWindow);
assert.equal(findBestWindowOrFolderForFile(options({
windows,
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'file.txt'))
})), vscodeFolderWindow);
const window: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder')) };
assert.equal(findBestWindowOrFolderForFile(options({
windows: [window],
fileUri: URI.file(path.join(fixturesFolder, 'vscode_folder', 'nested_folder', 'subfolder', 'file.txt'))
})), window);
});
test('More specific existing window wins', () => {
const window: ISimpleWindow = { lastFocusTime: 2, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder')) };
const nestedFolderWindow: ISimpleWindow = { lastFocusTime: 1, openedFolderUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder')) };
assert.equal(findBestWindowOrFolderForFile(options({
windows: [window, nestedFolderWindow],
fileUri: URI.file(path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder', 'subfolder', 'file.txt'))
})), nestedFolderWindow);
});
test('Workspace folder wins', () => {
const window: ISimpleWindow = { lastFocusTime: 1, openedWorkspace: testWorkspace };
assert.equal(findBestWindowOrFolderForFile(options({
windows: [window],
fileUri: URI.file(path.join(fixturesFolder, 'vscode_workspace_2_folder', 'nested_vscode_folder', 'subfolder', 'file.txt'))
})), window);
});
});