Open parent folder with .vscode when opening files from CLI or desktop (fixes #20671)

This commit is contained in:
Christof Marti
2017-02-15 16:05:52 -08:00
parent c153d54d1c
commit da9058d568
9 changed files with 296 additions and 50 deletions

View File

@@ -0,0 +1,123 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as path from 'path';
import * as fs from 'original-fs';
import * as platform from 'vs/base/common/platform';
import * as paths from 'vs/base/common/paths';
export enum OpenContext {
// opening when running from the command line
CLI,
// macOS only: opening from the dock (also when opening files to a running instance from desktop)
DOCK,
// opening from the main application window
MENU,
// opening from a file or folder dialog
DIALOG,
// opening from the OS's UI
DESKTOP,
// opening through the API
API
}
/**
* Exported subset of VSCodeWindow for testing.
*/
export interface ISimpleWindow {
openedWorkspacePath: string;
lastFocusTime: number;
}
/**
* Exported for testing.
*/
export interface IBestWindowOrFolderOptions<WINDOW> {
windows: WINDOW[];
newWindow: boolean;
reuseWindow: boolean;
context: OpenContext;
filePath?: string;
userHome?: string;
vscodeFolder?: string;
}
export function findBestWindowOrFolder<WINDOW extends ISimpleWindow>({ windows, newWindow, reuseWindow, context, filePath, userHome, vscodeFolder }: IBestWindowOrFolderOptions<WINDOW>): WINDOW | string {
// OpenContext.DOCK implies newWindow unless overwritten by settings.
const findBest = filePath && (context === OpenContext.DESKTOP || context === OpenContext.CLI || context === OpenContext.DOCK);
const bestWindow = !newWindow && findBest && findBestWindow(windows, filePath);
const bestFolder = !newWindow && !reuseWindow && findBest && findBestFolder(filePath, userHome, vscodeFolder);
if (bestWindow && !(bestFolder && bestFolder.length > bestWindow.openedWorkspacePath.length)) {
return bestWindow;
} else if (bestFolder) {
return bestFolder;
}
return !newWindow ? getLastActiveWindow(windows) : null;
}
function findBestWindow<WINDOW extends ISimpleWindow>(windows: WINDOW[], filePath: string): WINDOW {
const containers = windows.filter(window => typeof window.openedWorkspacePath === 'string' && paths.isEqualOrParent(filePath, window.openedWorkspacePath));
if (containers.length) {
return containers.sort((a, b) => -(a.openedWorkspacePath.length - b.openedWorkspacePath.length))[0];
}
return null;
}
function findBestFolder(filePath: string, userHome?: string, vscodeFolder?: string): string {
let folder = path.dirname(paths.normalize(filePath, true));
let homeFolder = userHome && paths.normalize(userHome, true);
if (!platform.isLinux) {
homeFolder = homeFolder && homeFolder.toLowerCase();
}
let previous = null;
try {
while (folder !== previous) {
if (isProjectFolder(folder, homeFolder, vscodeFolder)) {
return folder;
}
previous = folder;
folder = path.dirname(folder);
}
} catch (err) {
// assume impossible to access
}
return null;
}
function isProjectFolder(folder: string, normalizedUserHome?: string, vscodeFolder = '.vscode') {
try {
if ((platform.isLinux ? folder : folder.toLowerCase()) === normalizedUserHome) {
// ~/.vscode/extensions is used for extensions
return fs.statSync(path.join(folder, vscodeFolder, 'settings.json')).isFile();
} else {
return fs.statSync(path.join(folder, vscodeFolder)).isDirectory();
}
} catch (err) {
if (!(err && err.code === 'ENOENT')) {
throw err;
}
}
return false;
}
export function getLastActiveWindow<WINDOW extends ISimpleWindow>(windows: WINDOW[]): WINDOW {
if (windows.length) {
const lastFocussedDate = Math.max.apply(Math, windows.map(w => w.lastFocusTime));
const res = windows.filter(w => w.lastFocusTime === lastFocussedDate);
if (res && res.length) {
return res[0];
}
}
return null;
}