提交 124f4c71 编写于 作者: B Benjamin Pasero

make single-folder case more explicit (rename workspacePath => folderPath)

上级 6da138c8
......@@ -211,9 +211,9 @@ export class CodeApplication {
// Send to windows
if (target) {
const otherWindowsWithTarget = this.windowsMainService.getWindows().filter(w => w.id !== windowId && typeof w.openedWorkspacePath === 'string');
const directTargetMatch = otherWindowsWithTarget.filter(w => isEqual(target, w.openedWorkspacePath, !platform.isLinux /* ignorecase */));
const parentTargetMatch = otherWindowsWithTarget.filter(w => isParent(target, w.openedWorkspacePath, !platform.isLinux /* ignorecase */));
const otherWindowsWithTarget = this.windowsMainService.getWindows().filter(w => w.id !== windowId && typeof w.openedFolderPath === 'string');
const directTargetMatch = otherWindowsWithTarget.filter(w => isEqual(target, w.openedFolderPath, !platform.isLinux /* ignorecase */));
const parentTargetMatch = otherWindowsWithTarget.filter(w => isParent(target, w.openedFolderPath, !platform.isLinux /* ignorecase */));
const targetWindow = directTargetMatch.length ? directTargetMatch[0] : parentTargetMatch[0]; // prefer direct match over parent match
if (targetWindow) {
......
......@@ -277,14 +277,14 @@ export class CodeWindow implements ICodeWindow {
return this._lastFocusTime;
}
public get openedWorkspacePath(): string {
return this.currentConfig ? this.currentConfig.workspacePath : void 0;
}
public get backupPath(): string {
return this.currentConfig ? this.currentConfig.backupPath : void 0;
}
public get openedFolderPath(): string {
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;
}
......
......@@ -21,7 +21,7 @@ import { ILifecycleService, UnloadReason } from 'vs/platform/lifecycle/electron-
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace } from 'vs/code/node/windowsFinder';
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnFolder } from 'vs/code/node/windowsFinder';
import CommonEvent, { Emitter } from 'vs/base/common/event';
import product from 'vs/platform/node/product';
import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
......@@ -41,17 +41,24 @@ interface INewWindowState extends ISingleWindowState {
hasDefaultState?: boolean;
}
interface IWindowState {
interface ILegacyWindowState extends IWindowState {
workspacePath?: string;
}
interface IWindowState {
folderPath?: string;
backupPath: string;
uiState: ISingleWindowState;
}
interface ILegacyWindowsState extends IWindowsState {
openedFolders?: IWindowState[];
}
interface IWindowsState {
lastActiveWindow?: IWindowState;
lastPluginDevelopmentHostWindow?: IWindowState;
openedWindows: IWindowState[];
openedFolders?: IWindowState[]; // TODO@Ben deprecated
}
type RestoreWindowsSetting = 'all' | 'folders' | 'one' | 'none';
......@@ -59,7 +66,7 @@ type RestoreWindowsSetting = 'all' | 'folders' | 'one' | 'none';
interface IOpenBrowserWindowOptions {
userEnv?: IProcessEnvironment;
cli?: ParsedArgs;
workspacePath?: string;
folderPath?: string;
initialStartup?: boolean;
......@@ -70,13 +77,13 @@ interface IOpenBrowserWindowOptions {
forceNewWindow?: boolean;
windowToUse?: CodeWindow;
emptyWorkspaceBackupFolder?: string;
emptyWindowBackupFolder?: string;
}
interface IWindowToOpen extends IPath {
// the workspace spath for a Code instance to open
workspacePath?: string;
// the folder path for a Code instance to open
folderPath?: string;
// the backup spath for a Code instance to use
backupPath?: string;
......@@ -123,16 +130,33 @@ export class WindowsManager implements IWindowsMainService {
@IHistoryMainService private historyService: IHistoryMainService
) {
this.windowsState = this.storageService.getItem<IWindowsState>(WindowsManager.windowsStateStorageKey) || { openedWindows: [] };
this.fileDialog = new FileDialog(environmentService, telemetryService, storageService, this);
this.migrateLegacyWindowState();
}
private migrateLegacyWindowState(): void {
const state: ILegacyWindowsState = this.windowsState;
// TODO@Ben migration from previous openedFolders to new openedWindows property
if (Array.isArray(this.windowsState.openedFolders) && this.windowsState.openedFolders.length > 0) {
this.windowsState.openedWindows = this.windowsState.openedFolders;
this.windowsState.openedFolders = void 0;
} else if (!this.windowsState.openedWindows) {
this.windowsState.openedWindows = [];
if (Array.isArray(state.openedFolders) && state.openedFolders.length > 0) {
state.openedWindows = state.openedFolders;
state.openedFolders = void 0;
} else if (!state.openedWindows) {
state.openedWindows = [];
}
this.fileDialog = new FileDialog(environmentService, telemetryService, storageService, this);
// TODO@Ben migration from previous workspacePath in window state to folderPath
const states: ILegacyWindowState[] = [];
states.push(state.lastActiveWindow);
states.push(state.lastPluginDevelopmentHostWindow);
states.push(...state.openedWindows);
states.forEach(state => {
if (state && typeof state.workspacePath === 'string') {
state.folderPath = state.workspacePath;
state.workspacePath = void 0;
}
});
}
public ready(initialUserEnv: IProcessEnvironment): void {
......@@ -180,7 +204,7 @@ export class WindowsManager implements IWindowsMainService {
// and then onBeforeQuit(). Using the quit action however will first issue onBeforeQuit()
// and then onBeforeWindowClose().
private onBeforeQuit(): void {
const currentWindowsState: IWindowsState = {
const currentWindowsState: ILegacyWindowsState = {
openedWindows: [],
openedFolders: [], // TODO@Ben migration so that old clients do not fail over data (prevents NPEs)
lastPluginDevelopmentHostWindow: this.windowsState.lastPluginDevelopmentHostWindow,
......@@ -195,14 +219,14 @@ export class WindowsManager implements IWindowsMainService {
}
if (activeWindow) {
currentWindowsState.lastActiveWindow = { workspacePath: activeWindow.openedWorkspacePath, uiState: activeWindow.serializeWindowState(), backupPath: activeWindow.backupPath };
currentWindowsState.lastActiveWindow = { folderPath: activeWindow.openedFolderPath, uiState: activeWindow.serializeWindowState(), backupPath: activeWindow.backupPath };
}
}
// 2.) Find extension host window
const extensionHostWindow = WindowsManager.WINDOWS.filter(w => w.isExtensionDevelopmentHost && !w.isExtensionTestHost)[0];
if (extensionHostWindow) {
currentWindowsState.lastPluginDevelopmentHostWindow = { workspacePath: extensionHostWindow.openedWorkspacePath, uiState: extensionHostWindow.serializeWindowState(), backupPath: extensionHostWindow.backupPath };
currentWindowsState.lastPluginDevelopmentHostWindow = { folderPath: extensionHostWindow.openedFolderPath, uiState: extensionHostWindow.serializeWindowState(), backupPath: extensionHostWindow.backupPath };
}
// 3.) All windows (except extension host) for N >= 2 to support restoreWindows: all or for auto update
......@@ -213,7 +237,7 @@ export class WindowsManager implements IWindowsMainService {
if (this.getWindowCount() > 1) {
currentWindowsState.openedWindows = WindowsManager.WINDOWS.filter(w => !w.isExtensionDevelopmentHost).map(w => {
return <IWindowState>{
workspacePath: w.openedWorkspacePath,
folderPath: w.openedFolderPath,
uiState: w.serializeWindowState(),
backupPath: w.backupPath
};
......@@ -231,15 +255,15 @@ export class WindowsManager implements IWindowsMainService {
}
// On Window close, update our stored UI state of this window
const state: IWindowState = { workspacePath: win.openedWorkspacePath, uiState: win.serializeWindowState(), backupPath: win.backupPath };
const state: IWindowState = { folderPath: win.openedFolderPath, uiState: win.serializeWindowState(), backupPath: win.backupPath };
if (win.isExtensionDevelopmentHost && !win.isExtensionTestHost) {
this.windowsState.lastPluginDevelopmentHostWindow = state; // do not let test run window state overwrite our extension development state
}
// Any non extension host window with same workspace
else if (!win.isExtensionDevelopmentHost && !!win.openedWorkspacePath) {
// Any non extension host window with same folder
else if (!win.isExtensionDevelopmentHost && !!win.openedFolderPath) {
this.windowsState.openedWindows.forEach(o => {
if (isEqual(o.workspacePath, win.openedWorkspacePath, !isLinux /* ignorecase */)) {
if (isEqual(o.folderPath, win.openedFolderPath, !isLinux /* ignorecase */)) {
o.uiState = state.uiState;
}
});
......@@ -260,8 +284,8 @@ export class WindowsManager implements IWindowsMainService {
//
// These are windows to open to show either folders or files (including diffing files or creating them)
//
const foldersToOpen = arrays.distinct(windowsToOpen.filter(win => win.workspacePath && !win.filePath).map(win => win.workspacePath), folder => isLinux ? folder : folder.toLowerCase()); // prevent duplicates
const emptyToOpen = windowsToOpen.filter(win => !win.workspacePath && !win.filePath && !win.backupPath).length;
const foldersToOpen = arrays.distinct(windowsToOpen.filter(win => win.folderPath && !win.filePath).map(win => win.folderPath), folder => isLinux ? folder : folder.toLowerCase()); // prevent duplicates
const emptyToOpen = windowsToOpen.filter(win => !win.folderPath && !win.filePath && !win.backupPath).length;
let filesToOpen = windowsToOpen.filter(path => !!path.filePath && !path.createFilePath);
let filesToCreate = windowsToOpen.filter(path => !!path.filePath && path.createFilePath);
......@@ -279,8 +303,8 @@ export class WindowsManager implements IWindowsMainService {
//
const hotExitRestore = (openConfig.initialStartup && !openConfig.cli.extensionDevelopmentPath);
const foldersToRestore = hotExitRestore ? this.backupService.getWorkspaceBackupPaths() : [];
let emptyToRestore = hotExitRestore ? this.backupService.getEmptyWorkspaceBackupPaths() : [];
emptyToRestore.push(...windowsToOpen.filter(w => !w.workspacePath && w.backupPath).map(w => path.basename(w.backupPath))); // add empty workspaces with backupPath
let emptyToRestore = hotExitRestore ? this.backupService.getEmptyWindowBackupPaths() : [];
emptyToRestore.push(...windowsToOpen.filter(w => !w.folderPath && w.backupPath).map(w => path.basename(w.backupPath))); // add empty windows with backupPath
emptyToRestore = arrays.distinct(emptyToRestore); // prevent duplicates
// Open based on config
......@@ -300,8 +324,8 @@ export class WindowsManager implements IWindowsMainService {
const recentPaths: { path: string; isFile?: boolean; }[] = [];
windowsToOpen.forEach(win => {
if (win.filePath || win.workspacePath) {
recentPaths.push({ path: win.filePath || win.workspacePath, isFile: !!win.filePath });
if (win.filePath || win.folderPath) {
recentPaths.push({ path: win.filePath || win.folderPath, isFile: !!win.filePath });
}
});
......@@ -374,7 +398,7 @@ export class WindowsManager implements IWindowsMainService {
userEnv: openConfig.userEnv,
cli: openConfig.cli,
initialStartup: openConfig.initialStartup,
workspacePath: folderToOpen,
folderPath: folderToOpen,
filesToOpen,
filesToCreate,
filesToDiff,
......@@ -396,9 +420,9 @@ export class WindowsManager implements IWindowsMainService {
if (allFoldersToOpen.length > 0) {
// Check for existing instances
const windowsOnWorkspacePath = arrays.coalesce(allFoldersToOpen.map(folderToOpen => findWindowOnWorkspace(WindowsManager.WINDOWS, folderToOpen)));
if (windowsOnWorkspacePath.length > 0) {
const browserWindow = windowsOnWorkspacePath[0];
const windowsOnFolderPath = arrays.coalesce(allFoldersToOpen.map(folderToOpen => findWindowOnFolder(WindowsManager.WINDOWS, folderToOpen)));
if (windowsOnFolderPath.length > 0) {
const browserWindow = windowsOnFolderPath[0];
browserWindow.focus(); // just focus one of them
const files = { filesToOpen, filesToCreate, filesToDiff }; // copy to object because they get reset shortly after
......@@ -418,7 +442,7 @@ export class WindowsManager implements IWindowsMainService {
// Open remaining ones
allFoldersToOpen.forEach(folderToOpen => {
if (windowsOnWorkspacePath.some(win => isEqual(win.openedWorkspacePath, folderToOpen, !isLinux /* ignorecase */))) {
if (windowsOnFolderPath.some(win => isEqual(win.openedFolderPath, folderToOpen, !isLinux /* ignorecase */))) {
return; // ignore folders that are already open
}
......@@ -426,7 +450,7 @@ export class WindowsManager implements IWindowsMainService {
userEnv: openConfig.userEnv,
cli: openConfig.cli,
initialStartup: openConfig.initialStartup,
workspacePath: folderToOpen,
folderPath: folderToOpen,
filesToOpen,
filesToCreate,
filesToDiff,
......@@ -446,7 +470,7 @@ export class WindowsManager implements IWindowsMainService {
// Handle empty
if (emptyToRestore.length > 0) {
emptyToRestore.forEach(emptyWorkspaceBackupFolder => {
emptyToRestore.forEach(emptyWindowBackupFolder => {
const browserWindow = this.openInBrowserWindow({
userEnv: openConfig.userEnv,
cli: openConfig.cli,
......@@ -455,7 +479,7 @@ export class WindowsManager implements IWindowsMainService {
filesToCreate,
filesToDiff,
forceNewWindow: true,
emptyWorkspaceBackupFolder
emptyWindowBackupFolder
});
usedWindows.push(browserWindow);
......@@ -468,7 +492,7 @@ export class WindowsManager implements IWindowsMainService {
});
}
// Only open empty if no empty workspaces were restored
// Only open empty if no empty windows were restored
else if (emptyToOpen > 0) {
for (let i = 0; i < emptyToOpen; i++) {
const browserWindow = this.openInBrowserWindow({
......@@ -561,16 +585,16 @@ export class WindowsManager implements IWindowsMainService {
switch (restoreWindows) {
// none: we always open an empty workspace
// none: we always open an empty window
case 'none':
return [Object.create(null)];
// one: restore last opened folder or empty workspace
// one: restore last opened folder or empty window
case 'one':
if (lastActiveWindow) {
// return folder path if it is valid
const folder = lastActiveWindow.workspacePath;
const folder = lastActiveWindow.folderPath;
if (folder) {
const validatedFolderPath = this.parsePath(folder);
if (validatedFolderPath) {
......@@ -578,7 +602,7 @@ export class WindowsManager implements IWindowsMainService {
}
}
// otherwise use backup path to restore empty workspaces
// otherwise use backup path to restore empty windows
else if (lastActiveWindow.backupPath) {
return [{ backupPath: lastActiveWindow.backupPath }];
}
......@@ -591,8 +615,8 @@ export class WindowsManager implements IWindowsMainService {
case 'folders':
// Windows with Folders
const lastOpenedFolders = this.windowsState.openedWindows.filter(w => !!w.workspacePath).map(o => o.workspacePath);
const lastActiveFolder = lastActiveWindow && lastActiveWindow.workspacePath;
const lastOpenedFolders = this.windowsState.openedWindows.filter(w => !!w.folderPath).map(o => o.folderPath);
const lastActiveFolder = lastActiveWindow && lastActiveWindow.folderPath;
if (lastActiveFolder) {
lastOpenedFolders.push(lastActiveFolder);
}
......@@ -601,8 +625,8 @@ export class WindowsManager implements IWindowsMainService {
// Windows that were Empty
if (restoreWindows === 'all') {
const lastOpenedEmpty = this.windowsState.openedWindows.filter(w => !w.workspacePath && w.backupPath).map(w => w.backupPath);
const lastActiveEmpty = lastActiveWindow && !lastActiveWindow.workspacePath && lastActiveWindow.backupPath;
const lastOpenedEmpty = this.windowsState.openedWindows.filter(w => !w.folderPath && w.backupPath).map(w => w.backupPath);
const lastActiveEmpty = lastActiveWindow && !lastActiveWindow.folderPath && lastActiveWindow.backupPath;
if (lastActiveEmpty) {
lastOpenedEmpty.push(lastActiveEmpty);
}
......@@ -617,7 +641,7 @@ export class WindowsManager implements IWindowsMainService {
break;
}
// Always fallback to empty workspace
// Always fallback to empty window
return [Object.create(null)];
}
......@@ -662,7 +686,7 @@ export class WindowsManager implements IWindowsMainService {
lineNumber: gotoLineMode ? parsedPath.line : void 0,
columnNumber: gotoLineMode ? parsedPath.column : void 0
} :
{ workspacePath: candidate };
{ folderPath: candidate };
}
} catch (error) {
this.historyService.removeFromRecentPathsList(candidate); // since file does not seem to exist anymore, remove from recent
......@@ -717,17 +741,17 @@ export class WindowsManager implements IWindowsMainService {
return;
}
// Fill in previously opened workspace unless an explicit path is provided and we are not unit testing
// Fill in previously opened folder unless an explicit path is provided and we are not unit testing
if (openConfig.cli._.length === 0 && !openConfig.cli.extensionTestsPath) {
const workspaceToOpen = this.windowsState.lastPluginDevelopmentHostWindow && this.windowsState.lastPluginDevelopmentHostWindow.workspacePath;
if (workspaceToOpen) {
openConfig.cli._ = [workspaceToOpen];
const folderToOpen = this.windowsState.lastPluginDevelopmentHostWindow && this.windowsState.lastPluginDevelopmentHostWindow.folderPath;
if (folderToOpen) {
openConfig.cli._ = [folderToOpen];
}
}
// Make sure we are not asked to open a path that is already opened
if (openConfig.cli._.length > 0) {
res = WindowsManager.WINDOWS.filter(w => w.openedWorkspacePath && openConfig.cli._.indexOf(w.openedWorkspacePath) >= 0);
res = WindowsManager.WINDOWS.filter(w => w.openedFolderPath && openConfig.cli._.indexOf(w.openedFolderPath) >= 0);
if (res.length) {
openConfig.cli._ = [];
}
......@@ -745,18 +769,18 @@ export class WindowsManager implements IWindowsMainService {
configuration.execPath = process.execPath;
configuration.userEnv = assign({}, this.initialUserEnv, options.userEnv || {});
configuration.isInitialStartup = options.initialStartup;
configuration.workspacePath = options.workspacePath;
configuration.folderPath = options.folderPath;
configuration.filesToOpen = options.filesToOpen;
configuration.filesToCreate = options.filesToCreate;
configuration.filesToDiff = options.filesToDiff;
configuration.nodeCachedDataDir = this.environmentService.nodeCachedDataDir;
// if we know the backup folder upfront (for empty workspaces to restore), we can set it
// if we know the backup folder upfront (for empty windows to restore), we can set it
// directly here which helps for restoring UI state associated with that window.
// For all other cases we first call into registerWindowForBackupsSync() to set it before
// loading the window.
if (options.emptyWorkspaceBackupFolder) {
configuration.backupPath = path.join(this.environmentService.backupHome, options.emptyWorkspaceBackupFolder);
if (options.emptyWindowBackupFolder) {
configuration.backupPath = path.join(this.environmentService.backupHome, options.emptyWindowBackupFolder);
}
let codeWindow: CodeWindow;
......@@ -853,7 +877,7 @@ export class WindowsManager implements IWindowsMainService {
// Register window for backups
if (!configuration.extensionDevelopmentPath) {
const backupPath = this.backupService.registerWindowForBackupsSync(codeWindow.id, !configuration.workspacePath, options.emptyWorkspaceBackupFolder, configuration.workspacePath);
const backupPath = this.backupService.registerWindowForBackupsSync(codeWindow.id, !configuration.folderPath, options.emptyWindowBackupFolder, configuration.folderPath);
configuration.backupPath = backupPath;
}
......@@ -873,18 +897,18 @@ export class WindowsManager implements IWindowsMainService {
}
// Known Folder - load from stored settings if any
if (configuration.workspacePath) {
const stateForWorkspace = this.windowsState.openedWindows.filter(o => isEqual(o.workspacePath, configuration.workspacePath, !isLinux /* ignorecase */)).map(o => o.uiState);
if (stateForWorkspace.length) {
return stateForWorkspace[0];
if (configuration.folderPath) {
const stateForFolder = this.windowsState.openedWindows.filter(o => isEqual(o.folderPath, configuration.folderPath, !isLinux /* ignorecase */)).map(o => o.uiState);
if (stateForFolder.length) {
return stateForFolder[0];
}
}
// Empty workspace with backups
// Empty windows with backups
else if (configuration.backupPath) {
const stateForWorkspace = this.windowsState.openedWindows.filter(o => o.backupPath === configuration.backupPath).map(o => o.uiState);
if (stateForWorkspace.length) {
return stateForWorkspace[0];
const stateForEmptyWindow = this.windowsState.openedWindows.filter(o => o.backupPath === configuration.backupPath).map(o => o.uiState);
if (stateForEmptyWindow.length) {
return stateForEmptyWindow[0];
}
}
......
......@@ -12,7 +12,7 @@ import * as paths from 'vs/base/common/paths';
import { OpenContext } from 'vs/platform/windows/common/windows';
export interface ISimpleWindow {
openedWorkspacePath: string;
openedFolderPath: string;
openedFilePath?: string;
extensionDevelopmentPath?: string;
lastFocusTime: number;
......@@ -34,7 +34,7 @@ export function findBestWindowOrFolderForFile<W extends ISimpleWindow>({ windows
const folderWithCodeSettings = !reuseWindow && findFolderWithCodeSettings(filePath, userHome, codeSettingsFolder);
// Return if we found a window that has the parent of the file path opened
if (windowOnFilePath && !(folderWithCodeSettings && folderWithCodeSettings.length > windowOnFilePath.openedWorkspacePath.length)) {
if (windowOnFilePath && !(folderWithCodeSettings && folderWithCodeSettings.length > windowOnFilePath.openedFolderPath.length)) {
return windowOnFilePath;
}
......@@ -51,9 +51,9 @@ function findWindowOnFilePath<W extends ISimpleWindow>(windows: W[], filePath: s
// 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.openedWorkspacePath === 'string' && paths.isEqualOrParent(filePath, window.openedWorkspacePath, !platform.isLinux /* ignorecase */));
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.openedWorkspacePath.length - b.openedWorkspacePath.length))[0];
return windowsOnFilePath.sort((a, b) => -(a.openedFolderPath.length - b.openedFolderPath.length))[0];
}
return null;
......@@ -105,7 +105,7 @@ export function getLastActiveWindow<W extends ISimpleWindow>(windows: W[]): W {
return null;
}
export function findWindowOnWorkspace<W extends ISimpleWindow>(windows: W[], workspacePath: string): W {
export function findWindowOnFolder<W extends ISimpleWindow>(windows: W[], folderPath: string): W {
if (windows.length) {
// Sort the last active window to the front of the array of windows to test
......@@ -119,8 +119,8 @@ export function findWindowOnWorkspace<W extends ISimpleWindow>(windows: W[], wor
// Find it
const res = windowsToTest.filter(w => {
// match on workspace
if (typeof w.openedWorkspacePath === 'string' && (paths.isEqual(w.openedWorkspacePath, workspacePath, !platform.isLinux /* ignorecase */))) {
// match on folder
if (typeof w.openedFolderPath === 'string' && (paths.isEqual(w.openedFolderPath, folderPath, !platform.isLinux /* ignorecase */))) {
return true;
}
......
......@@ -22,9 +22,9 @@ function options(custom?: Partial<IBestWindowOrFolderOptions<ISimpleWindow>>): I
};
}
const vscodeFolderWindow = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'vscode_folder') };
const lastActiveWindow = { lastFocusTime: 3, openedWorkspacePath: null };
const noVscodeFolderWindow = { lastFocusTime: 2, openedWorkspacePath: path.join(fixturesFolder, 'no_vscode_folder') };
const vscodeFolderWindow = { lastFocusTime: 1, openedFolderPath: path.join(fixturesFolder, 'vscode_folder') };
const lastActiveWindow = { lastFocusTime: 3, openedFolderPath: null };
const noVscodeFolderWindow = { lastFocusTime: 2, openedFolderPath: path.join(fixturesFolder, 'no_vscode_folder') };
const windows = [
vscodeFolderWindow,
lastActiveWindow,
......@@ -101,7 +101,7 @@ suite('WindowsFinder', () => {
});
test('Existing window wins over vscode folder if more specific', () => {
const window = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'vscode_folder', 'nested_folder') };
const window = { lastFocusTime: 1, openedFolderPath: path.join(fixturesFolder, 'vscode_folder', 'nested_folder') };
assert.equal(findBestWindowOrFolderForFile(options({
windows: [window],
filePath: path.join(fixturesFolder, 'vscode_folder', 'nested_folder', 'subfolder', 'file.txt')
......@@ -114,8 +114,8 @@ suite('WindowsFinder', () => {
});
test('More specific existing window wins', () => {
const window = { lastFocusTime: 2, openedWorkspacePath: path.join(fixturesFolder, 'no_vscode_folder') };
const nestedFolderWindow = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder') };
const window = { lastFocusTime: 2, openedFolderPath: path.join(fixturesFolder, 'no_vscode_folder') };
const nestedFolderWindow = { lastFocusTime: 1, openedFolderPath: path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder') };
assert.equal(findBestWindowOrFolderForFile(options({
windows: [window, nestedFolderWindow],
filePath: path.join(fixturesFolder, 'no_vscode_folder', 'nested_folder', 'subfolder', 'file.txt')
......@@ -123,7 +123,7 @@ suite('WindowsFinder', () => {
});
test('VSCode folder wins over existing window if more specific', () => {
const window = { lastFocusTime: 1, openedWorkspacePath: path.join(fixturesFolder, 'vscode_folder') };
const window = { lastFocusTime: 1, openedFolderPath: path.join(fixturesFolder, 'vscode_folder') };
assert.equal(findBestWindowOrFolderForFile(options({
windows: [window],
filePath: path.join(fixturesFolder, 'vscode_folder', 'nested_vscode_folder', 'subfolder', 'file.txt')
......
......@@ -16,7 +16,7 @@ export interface IBackupMainService {
_serviceBrand: any;
getWorkspaceBackupPaths(): string[];
getEmptyWorkspaceBackupPaths(): string[];
getEmptyWindowBackupPaths(): string[];
registerWindowForBackupsSync(windowId: number, isEmptyWorkspace: boolean, backupFolder?: string, workspacePath?: string): string;
registerWindowForBackupsSync(windowId: number, isEmptyWindow: boolean, backupFolder?: string, workspacePath?: string): string;
}
\ No newline at end of file
......@@ -43,25 +43,25 @@ export class BackupMainService implements IBackupMainService {
return this.backups.folderWorkspaces.slice(0); // return a copy
}
public getEmptyWorkspaceBackupPaths(): string[] {
public getEmptyWindowBackupPaths(): string[] {
return this.backups.emptyWorkspaces.slice(0); // return a copy
}
public registerWindowForBackupsSync(windowId: number, isEmptyWorkspace: boolean, backupFolder?: string, workspacePath?: string): string {
public registerWindowForBackupsSync(windowId: number, isEmptyWindow: boolean, backupFolder?: string, workspacePath?: string): string {
// Generate a new folder if this is a new empty workspace
if (isEmptyWorkspace && !backupFolder) {
backupFolder = this.getRandomEmptyWorkspaceId();
if (isEmptyWindow && !backupFolder) {
backupFolder = this.getRandomEmptyWindowId();
}
this.pushBackupPathsSync(isEmptyWorkspace ? backupFolder : workspacePath, isEmptyWorkspace);
this.pushBackupPathsSync(isEmptyWindow ? backupFolder : workspacePath, isEmptyWindow);
return path.join(this.backupHome, isEmptyWorkspace ? backupFolder : this.getWorkspaceHash(workspacePath));
return path.join(this.backupHome, isEmptyWindow ? backupFolder : this.getWorkspaceHash(workspacePath));
}
private pushBackupPathsSync(workspaceIdentifier: string, isEmptyWorkspace: boolean): string {
const array = isEmptyWorkspace ? this.backups.emptyWorkspaces : this.backups.folderWorkspaces;
if (this.indexOf(workspaceIdentifier, isEmptyWorkspace) === -1) {
private pushBackupPathsSync(workspaceIdentifier: string, isEmptyWindow: boolean): string {
const array = isEmptyWindow ? this.backups.emptyWorkspaces : this.backups.folderWorkspaces;
if (this.indexOf(workspaceIdentifier, isEmptyWindow) === -1) {
array.push(workspaceIdentifier);
this.saveSync();
}
......@@ -69,12 +69,12 @@ export class BackupMainService implements IBackupMainService {
return workspaceIdentifier;
}
protected removeBackupPathSync(workspaceIdentifier: string, isEmptyWorkspace: boolean): void {
const array = isEmptyWorkspace ? this.backups.emptyWorkspaces : this.backups.folderWorkspaces;
protected removeBackupPathSync(workspaceIdentifier: string, isEmptyWindow: boolean): void {
const array = isEmptyWindow ? this.backups.emptyWorkspaces : this.backups.folderWorkspaces;
if (!array) {
return;
}
const index = this.indexOf(workspaceIdentifier, isEmptyWorkspace);
const index = this.indexOf(workspaceIdentifier, isEmptyWindow);
if (index === -1) {
return;
}
......@@ -82,13 +82,13 @@ export class BackupMainService implements IBackupMainService {
this.saveSync();
}
private indexOf(workspaceIdentifier: string, isEmptyWorkspace: boolean): number {
const array = isEmptyWorkspace ? this.backups.emptyWorkspaces : this.backups.folderWorkspaces;
private indexOf(workspaceIdentifier: string, isEmptyWindow: boolean): number {
const array = isEmptyWindow ? this.backups.emptyWorkspaces : this.backups.folderWorkspaces;
if (!array) {
return -1;
}
if (isEmptyWorkspace) {
if (isEmptyWindow) {
return array.indexOf(workspaceIdentifier);
}
......@@ -140,7 +140,7 @@ export class BackupMainService implements IBackupMainService {
}
private validateBackupWorkspaces(backups: IBackupWorkspacesFormat): void {
const staleBackupWorkspaces: { workspaceIdentifier: string; backupPath: string; isEmptyWorkspace: boolean }[] = [];
const staleBackupWorkspaces: { workspaceIdentifier: string; backupPath: string; isEmptyWindow: boolean }[] = [];
// Validate Folder Workspaces
backups.folderWorkspaces.forEach(workspacePath => {
......@@ -151,13 +151,13 @@ export class BackupMainService implements IBackupMainService {
// If the folder has no backups, make sure to delete it
// If the folder has backups, but the target workspace is missing, convert backups to empty ones
if (!hasBackups || missingWorkspace) {
staleBackupWorkspaces.push({ workspaceIdentifier: workspacePath, backupPath, isEmptyWorkspace: false });
staleBackupWorkspaces.push({ workspaceIdentifier: workspacePath, backupPath, isEmptyWindow: false });
if (missingWorkspace) {
const identifier = this.pushBackupPathsSync(this.getRandomEmptyWorkspaceId(), true /* is empty workspace */);
const newEmptyWorkspaceBackupPath = path.join(path.dirname(backupPath), identifier);
const identifier = this.pushBackupPathsSync(this.getRandomEmptyWindowId(), true /* is empty workspace */);
const newEmptyWindowBackupPath = path.join(path.dirname(backupPath), identifier);
try {
fs.renameSync(backupPath, newEmptyWorkspaceBackupPath);
fs.renameSync(backupPath, newEmptyWindowBackupPath);
} catch (ex) {
console.error(`Backup: Could not rename backup folder for missing workspace: ${ex.toString()}`);
......@@ -167,17 +167,17 @@ export class BackupMainService implements IBackupMainService {
}
});
// Validate Empty Workspaces
// Validate Empty Windows
backups.emptyWorkspaces.forEach(backupFolder => {
const backupPath = path.join(this.backupHome, backupFolder);
if (!this.hasBackupsSync(backupPath)) {
staleBackupWorkspaces.push({ workspaceIdentifier: backupFolder, backupPath, isEmptyWorkspace: true });
staleBackupWorkspaces.push({ workspaceIdentifier: backupFolder, backupPath, isEmptyWindow: true });
}
});
// Clean up stale backups
staleBackupWorkspaces.forEach(staleBackupWorkspace => {
const { backupPath, workspaceIdentifier, isEmptyWorkspace } = staleBackupWorkspace;
const { backupPath, workspaceIdentifier, isEmptyWindow } = staleBackupWorkspace;
try {
extfs.delSync(backupPath);
......@@ -185,7 +185,7 @@ export class BackupMainService implements IBackupMainService {
console.error(`Backup: Could not delete stale backup: ${ex.toString()}`);
}
this.removeBackupPathSync(workspaceIdentifier, isEmptyWorkspace);
this.removeBackupPathSync(workspaceIdentifier, isEmptyWindow);
});
}
......@@ -220,7 +220,7 @@ export class BackupMainService implements IBackupMainService {
}
}
private getRandomEmptyWorkspaceId(): string {
private getRandomEmptyWindowId(): string {
return (Date.now() + Math.round(Math.random() * 1000)).toString();
}
......
......@@ -117,11 +117,11 @@ suite('BackupMainService', () => {
fs.mkdirSync(fileBackups);
service.registerWindowForBackupsSync(1, false, null, fooFile.fsPath);
assert.equal(service.getWorkspaceBackupPaths().length, 1);
assert.equal(service.getEmptyWorkspaceBackupPaths().length, 0);
assert.equal(service.getEmptyWindowBackupPaths().length, 0);
fs.writeFileSync(path.join(fileBackups, 'backup.txt'), '');
service.loadSync();
assert.equal(service.getWorkspaceBackupPaths().length, 0);
assert.equal(service.getEmptyWorkspaceBackupPaths().length, 1);
assert.equal(service.getEmptyWindowBackupPaths().length, 1);
done();
});
......@@ -179,46 +179,46 @@ suite('BackupMainService', () => {
});
test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
});
test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
fs.writeFileSync(backupWorkspacesPath, '');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{]');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, 'foo');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
});
test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
fs.writeFileSync(backupWorkspacesPath, '{}');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
});
test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": ["bar"]}}');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": []}}');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": "bar"}}');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":"foo"}');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":1}');
service.loadSync();
assert.deepEqual(service.getEmptyWorkspaceBackupPaths(), []);
assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
});
});
......
......@@ -34,7 +34,7 @@ export interface IHistoryMainService {
// methods
addToRecentPathsList(paths: { path: string; isFile?: boolean; }[]): void;
getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList;
getRecentPathsList(folderPath?: string, filesToOpen?: IPath[]): IRecentPathsList;
removeFromRecentPathsList(path: string): void;
removeFromRecentPathsList(paths: string[]): void;
clearRecentPathsList(): void;
......@@ -130,7 +130,7 @@ export class HistoryMainService implements IHistoryMainService {
this._onRecentPathsChange.fire();
}
public getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList {
public getRecentPathsList(folderPath?: string, filesToOpen?: IPath[]): IRecentPathsList {
let files: string[];
let folders: string[];
......@@ -149,9 +149,9 @@ export class HistoryMainService implements IHistoryMainService {
files.unshift(...filesToOpen.map(f => f.filePath));
}
// Add current workspace path to beginning if set
if (workspacePath) {
folders.unshift(workspacePath);
// Add current folder path to beginning if set
if (folderPath) {
folders.unshift(folderPath);
}
// Clear those dupes
......
......@@ -204,8 +204,7 @@ export interface IWindowConfiguration extends ParsedArgs, IOpenFileRequest {
perfAppReady?: number;
perfWindowLoadTime?: number;
workspacePath?: string;
folderPath?: string;
backupPath?: string;
nodeCachedDataDir: string;
......
......@@ -17,7 +17,7 @@ export interface ICodeWindow {
id: number;
win: Electron.BrowserWindow;
config: IWindowConfiguration;
openedWorkspacePath: string;
openedFolderPath: string;
lastFocusTime: number;
readyState: ReadyState;
......
......@@ -160,7 +160,7 @@ export class WindowsService implements IWindowsService, IDisposable {
const codeWindow = this.windowsMainService.getWindowById(windowId);
if (codeWindow) {
const { files, folders } = this.historyService.getRecentPathsList(codeWindow.config.workspacePath, codeWindow.config.filesToOpen);
const { files, folders } = this.historyService.getRecentPathsList(codeWindow.config.folderPath, codeWindow.config.filesToOpen);
return TPromise.as({ files, folders });
}
......@@ -273,7 +273,7 @@ export class WindowsService implements IWindowsService, IDisposable {
getWindows(): TPromise<{ id: number; path: string; title: string; }[]> {
const windows = this.windowsMainService.getWindows();
const result = windows.map(w => ({ path: w.openedWorkspacePath, title: w.win.getTitle(), id: w.id, filename: w.getRepresentedFilename() }));
const result = windows.map(w => ({ path: w.openedFolderPath, title: w.win.getTitle(), id: w.id, filename: w.getRepresentedFilename() }));
return TPromise.as(result);
}
......
......@@ -148,32 +148,32 @@ function legacyWorkspaceToMultiRootWorkspace(legacyWorkspace: LegacyWorkspace):
}
function resolveLegacyWorkspace(configuration: IWindowConfiguration): TPromise<LegacyWorkspace> {
if (!configuration.workspacePath) {
if (!configuration.folderPath) {
return TPromise.as(null);
}
return realpath(configuration.workspacePath).then(realWorkspacePath => {
return realpath(configuration.folderPath).then(realFolderPath => {
// for some weird reason, node adds a trailing slash to UNC paths
// we never ever want trailing slashes as our workspace path unless
// someone opens root ("/").
// See also https://github.com/nodejs/io.js/issues/1765
if (paths.isUNC(realWorkspacePath) && strings.endsWith(realWorkspacePath, paths.nativeSep)) {
realWorkspacePath = strings.rtrim(realWorkspacePath, paths.nativeSep);
if (paths.isUNC(realFolderPath) && strings.endsWith(realFolderPath, paths.nativeSep)) {
realFolderPath = strings.rtrim(realFolderPath, paths.nativeSep);
}
// update config
configuration.workspacePath = realWorkspacePath;
configuration.folderPath = realFolderPath;
// resolve ctime of workspace
return stat(realWorkspacePath).then(folderStat => new LegacyWorkspace(
uri.file(realWorkspacePath),
return stat(realFolderPath).then(folderStat => new LegacyWorkspace(
uri.file(realFolderPath),
platform.isLinux ? folderStat.ino : folderStat.birthtime.getTime() // On Linux, birthtime is ctime, so we cannot use it! We use the ino instead!
));
}, error => {
errors.onUnexpectedError(error);
return null; // treat invalid paths as empty workspace
return null; // treat invalid paths as empty window
});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册