diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 1f6636d40b0..8b7f7ee1cfe 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -32,6 +32,7 @@ import { TPromise } from "vs/base/common/winjs.base"; import { IWorkspacesMainService, IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceSavedEvent, WORKSPACE_FILTER } from "vs/platform/workspaces/common/workspaces"; import { IInstantiationService } from "vs/platform/instantiation/common/instantiation"; import { mnemonicButtonLabel } from "vs/base/common/labels"; +import URI from "vs/base/common/uri"; enum WindowError { UNRESPONSIVE, @@ -285,7 +286,7 @@ export class WindowsManager implements IWindowsMainService { buttonLabel: mnemonicButtonLabel(localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")), title: localize('saveWorkspace', "Save Workspace"), filters: WORKSPACE_FILTER, - defaultPath: path.dirname(resolvedWorkspace.folders[0]) // pick the parent of the first root by default + defaultPath: path.dirname(URI.parse(resolvedWorkspace.folders[0]).fsPath) // pick the parent of the first root by default }); if (target) { @@ -516,12 +517,34 @@ export class WindowsManager implements IWindowsMainService { reuseWindow: openConfig.forceReuseWindow, context: openConfig.context, filePath: fileToCheck && fileToCheck.filePath, - userHome: this.environmentService.userHome + userHome: this.environmentService.userHome, + workspaceResolver: workspace => this.workspacesService.resolveWorkspaceSync(workspace.configPath) }); - // We found a suitable window to open the files within: send the files to open over - if (bestWindowOrFolder instanceof CodeWindow && bestWindowOrFolder.openedFolderPath) { - foldersToOpen.push(bestWindowOrFolder.openedFolderPath); + // We found a window to open the files in + if (bestWindowOrFolder instanceof CodeWindow) { + + // Window is workspace + if (bestWindowOrFolder.openedWorkspace) { + workspacesToOpen.push(bestWindowOrFolder.openedWorkspace); + } + + // Window is single folder + else if (bestWindowOrFolder.openedFolderPath) { + foldersToOpen.push(bestWindowOrFolder.openedFolderPath); + } + + // Window is empty + else { + + // Do open files + usedWindows.push(this.doOpenFilesInExistingWindow(bestWindowOrFolder, filesToOpen, filesToCreate, filesToDiff)); + + // Reset these because we handled them + filesToOpen = []; + filesToCreate = []; + filesToDiff = []; + } } // We found a suitable folder to open: add it to foldersToOpen diff --git a/src/vs/code/node/windowsFinder.ts b/src/vs/code/node/windowsFinder.ts index 555945e8ca9..7adae5d0093 100644 --- a/src/vs/code/node/windowsFinder.ts +++ b/src/vs/code/node/windowsFinder.ts @@ -10,7 +10,8 @@ import * as fs from 'fs'; import * as platform from 'vs/base/common/platform'; import * as paths from 'vs/base/common/paths'; import { OpenContext } from 'vs/platform/windows/common/windows'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces"; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IStoredWorkspace } from "vs/platform/workspaces/common/workspaces"; +import URI from "vs/base/common/uri"; export interface ISimpleWindow { openedWorkspace?: IWorkspaceIdentifier; @@ -28,19 +29,25 @@ export interface IBestWindowOrFolderOptions { filePath?: string; userHome?: string; codeSettingsFolder?: string; + workspaceResolver: (workspace: IWorkspaceIdentifier) => IStoredWorkspace; } -export function findBestWindowOrFolderForFile({ windows, newWindow, reuseWindow, context, filePath, userHome, codeSettingsFolder }: IBestWindowOrFolderOptions): W | string { +export function findBestWindowOrFolderForFile({ windows, newWindow, reuseWindow, context, filePath, userHome, codeSettingsFolder, workspaceResolver }: IBestWindowOrFolderOptions): W | string { if (!newWindow && filePath && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK)) { - const windowOnFilePath = findWindowOnFilePath(windows, filePath); - const folderWithCodeSettings = !reuseWindow && findFolderWithCodeSettings(filePath, userHome, codeSettingsFolder); + const windowOnFilePath = findWindowOnFilePath(windows, filePath, workspaceResolver); - // Return if we found a window that has the parent of the file path opened + // 1) window wins if it has a workspace opened + if (windowOnFilePath && !!windowOnFilePath.openedWorkspace) { + return windowOnFilePath; + } + + // 2) window wins if it has a folder opened that is more specific than settings folder + const folderWithCodeSettings = !reuseWindow && findFolderWithCodeSettings(filePath, userHome, codeSettingsFolder); if (windowOnFilePath && !(folderWithCodeSettings && folderWithCodeSettings.length > windowOnFilePath.openedFolderPath.length)) { return windowOnFilePath; } - // Return if we found a parent folder with a code settings folder inside + // 3) finally return path to folder with settings if (folderWithCodeSettings) { return folderWithCodeSettings; } @@ -49,13 +56,22 @@ export function findBestWindowOrFolderForFile({ windows return !newWindow ? getLastActiveWindow(windows) : null; } -function findWindowOnFilePath(windows: W[], filePath: string): W { +function findWindowOnFilePath(windows: W[], filePath: string, workspaceResolver: (workspace: IWorkspaceIdentifier) => IStoredWorkspace): W { - // From all windows that have the parent of the file opened, return the window - // that has the most specific folder opened ( = longest path wins) - const windowsOnFilePath = windows.filter(window => typeof window.openedFolderPath === 'string' && paths.isEqualOrParent(filePath, window.openedFolderPath, !platform.isLinux /* ignorecase */)); - if (windowsOnFilePath.length) { - return windowsOnFilePath.sort((a, b) => -(a.openedFolderPath.length - b.openedFolderPath.length))[0]; + // First check for windows with workspaces that have a parent folder of the provided path opened + const workspaceWindows = windows.filter(window => !!window.openedWorkspace); + for (let i = 0; i < workspaceWindows.length; i++) { + const window = workspaceWindows[i]; + const resolvedWorkspace = workspaceResolver(window.openedWorkspace); + if (resolvedWorkspace && resolvedWorkspace.folders.some(folderUri => paths.isEqualOrParent(filePath, URI.parse(folderUri).fsPath, !platform.isLinux /* ignorecase */))) { + return window; + } + } + + // Then go with single folder windows that are parent of the provided file path + const singleFolderWindowsOnFilePath = windows.filter(window => typeof window.openedFolderPath === 'string' && paths.isEqualOrParent(filePath, window.openedFolderPath, !platform.isLinux /* ignorecase */)); + if (singleFolderWindowsOnFilePath.length) { + return singleFolderWindowsOnFilePath.sort((a, b) => -(a.openedFolderPath.length - b.openedFolderPath.length))[0]; } return null; diff --git a/src/vs/code/test/node/windowsFinder.test.ts b/src/vs/code/test/node/windowsFinder.test.ts index 64bc5cfa906..fa176c30c29 100644 --- a/src/vs/code/test/node/windowsFinder.test.ts +++ b/src/vs/code/test/node/windowsFinder.test.ts @@ -8,9 +8,15 @@ import assert = require('assert'); import path = require('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"; const fixturesFolder = require.toUrl('./fixtures'); +const testWorkspace: IWorkspaceIdentifier = { + id: Date.now().toString(), + configPath: path.join(fixturesFolder, 'workspaces.json') +}; + function options(custom?: Partial>): IBestWindowOrFolderOptions { return { windows: [], @@ -18,6 +24,7 @@ function options(custom?: Partial>): I reuseWindow: false, context: OpenContext.CLI, codeSettingsFolder: '_vscode', + workspaceResolver: workspace => { return workspace === testWorkspace ? { id: testWorkspace.id, folders: [path.join(fixturesFolder, 'vscode_workspace_1_folder'), path.join(fixturesFolder, 'vscode_workspace_2_folder')] } : null; }, ...custom }; } @@ -152,4 +159,12 @@ suite('WindowsFinder', () => { userHome: path.join(fixturesFolder, 'vscode_home_folder') })), path.join(fixturesFolder, 'vscode_home_folder')); }); + + test('Workspace folder wins', () => { + const window = { lastFocusTime: 1, openedWorkspace: testWorkspace }; + assert.equal(findBestWindowOrFolderForFile(options({ + windows: [window], + filePath: path.join(fixturesFolder, 'vscode_workspace_2_folder', 'nested_vscode_folder', 'subfolder', 'file.txt') + })), window); + }); });