diff --git a/src/vs/base/common/paths.ts b/src/vs/base/common/paths.ts index d3ce1808e2f..c96193ba433 100644 --- a/src/vs/base/common/paths.ts +++ b/src/vs/base/common/paths.ts @@ -319,44 +319,6 @@ export function makePosixAbsolute(path: string): string { return isPosixAbsolute(normalize(path)) ? path : sep + path; } -export function isEqualOrParent(path: string, candidate: string): boolean { - - if (path === candidate) { - return true; - } - - path = normalize(path); - candidate = normalize(candidate); - - let candidateLen = candidate.length; - let lastCandidateChar = candidate.charCodeAt(candidateLen - 1); - if (lastCandidateChar === CharCode.Slash) { - candidate = candidate.substring(0, candidateLen - 1); - candidateLen -= 1; - } - - if (path === candidate) { - return true; - } - - if (!isLinux) { - // case insensitive - path = path.toLowerCase(); - candidate = candidate.toLowerCase(); - } - - if (path === candidate) { - return true; - } - - if (path.indexOf(candidate) !== 0) { - return false; - } - - let char = path.charCodeAt(candidateLen); - return char === CharCode.Slash; -} - // Reference: https://en.wikipedia.org/wiki/Filename const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g; const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i; diff --git a/src/vs/base/test/common/paths.test.ts b/src/vs/base/test/common/paths.test.ts index 32c8850ce15..26ec076adfc 100644 --- a/src/vs/base/test/common/paths.test.ts +++ b/src/vs/base/test/common/paths.test.ts @@ -169,32 +169,6 @@ suite('Paths', () => { assert.equal(paths.join('http://localhost/test', 'test'), 'http://localhost/test/test'); }); - test('isEqualOrParent', () => { - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo/')); - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo')); - assert(paths.isEqualOrParent('/', '/')); - assert(paths.isEqualOrParent('/foo', '/')); - assert(paths.isEqualOrParent('/foo', '/foo/')); - assert(!paths.isEqualOrParent('/foo', '/f')); - assert(!paths.isEqualOrParent('/foo', '/foo/b')); - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo/bar')); - assert(!paths.isEqualOrParent('foo/bar/test.ts', '/foo/bar')); - assert(!paths.isEqualOrParent('foo/bar/test.ts', 'foo/barr')); - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo/xxx/../bar')); - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo/./bar')); - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo\\bar\\')); - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo/bar/test.ts')); - assert(!paths.isEqualOrParent('foo/bar/test.ts', 'foo/bar/test')); - assert(!paths.isEqualOrParent('foo/bar/test.ts', 'foo/bar/test.')); - - if (!platform.isLinux) { - assert(paths.isEqualOrParent('/foo', '/fOO/')); - assert(paths.isEqualOrParent('/fOO', '/foo/')); - assert(paths.isEqualOrParent('foo/bar/test.ts', 'foo/BAR/test.ts')); - assert(!paths.isEqualOrParent('foo/bar/test.ts', 'foo/BAR/test.')); - } - }); - test('extname', () => { assert.equal(paths.extname('far.boo'), '.boo'); assert.equal(paths.extname('far.b'), '.b'); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index c5f9aa1050c..69aef5bce12 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -9,7 +9,6 @@ import * as path from 'path'; import * as fs from 'original-fs'; import * as platform from 'vs/base/common/platform'; import * as nls from 'vs/nls'; -import * as paths from 'vs/base/common/paths'; import * as types from 'vs/base/common/types'; import * as arrays from 'vs/base/common/arrays'; import { assign, mixin } from 'vs/base/common/objects'; @@ -31,6 +30,7 @@ import CommonEvent, { Emitter } from 'vs/base/common/event'; import product from 'vs/platform/node/product'; import { OpenContext } from 'vs/code/common/windows'; import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; +import { isParent, isEqual } from 'vs/platform/files/common/files'; enum WindowError { UNRESPONSIVE, @@ -234,8 +234,8 @@ export class WindowsManager implements IWindowsMainService { // Send to windows if (target) { const otherWindowsWithTarget = WindowsManager.WINDOWS.filter(w => w.id !== windowId && typeof w.openedWorkspacePath === 'string'); - const directTargetMatch = otherWindowsWithTarget.filter(w => this.isPathEqual(target, w.openedWorkspacePath)); - const parentTargetMatch = otherWindowsWithTarget.filter(w => paths.isEqualOrParent(target, w.openedWorkspacePath)); + const directTargetMatch = otherWindowsWithTarget.filter(w => isEqual(target, w.openedWorkspacePath)); + const parentTargetMatch = otherWindowsWithTarget.filter(w => isParent(target, w.openedWorkspacePath)); const targetWindow = directTargetMatch.length ? directTargetMatch[0] : parentTargetMatch[0]; // prefer direct match over parent match if (targetWindow) { @@ -317,7 +317,7 @@ export class WindowsManager implements IWindowsMainService { // Any non extension host window with same workspace else if (!win.isExtensionDevelopmentHost && !!win.openedWorkspacePath) { this.windowsState.openedFolders.forEach(o => { - if (this.isPathEqual(o.workspacePath, win.openedWorkspacePath)) { + if (isEqual(o.workspacePath, win.openedWorkspacePath)) { o.uiState = state.uiState; } }); @@ -510,7 +510,7 @@ export class WindowsManager implements IWindowsMainService { // Open remaining ones allFoldersToOpen.forEach(folderToOpen => { - if (windowsOnWorkspacePath.some(win => this.isPathEqual(win.openedWorkspacePath, folderToOpen))) { + if (windowsOnWorkspacePath.some(win => isEqual(win.openedWorkspacePath, folderToOpen))) { return; // ignore folders that are already open } @@ -684,7 +684,7 @@ export class WindowsManager implements IWindowsMainService { // Reload an existing extension development host window on the same path // We currently do not allow more than one extension development window // on the same extension path. - let res = WindowsManager.WINDOWS.filter(w => w.config && this.isPathEqual(w.config.extensionDevelopmentPath, openConfig.cli.extensionDevelopmentPath)); + let res = WindowsManager.WINDOWS.filter(w => w.config && isEqual(w.config.extensionDevelopmentPath, openConfig.cli.extensionDevelopmentPath)); if (res && res.length === 1) { this.reload(res[0], openConfig.cli); res[0].focus(); // make sure it gets focus and is restored @@ -906,7 +906,7 @@ export class WindowsManager implements IWindowsMainService { // Known Folder - load from stored settings if any if (configuration.workspacePath) { - const stateForWorkspace = this.windowsState.openedFolders.filter(o => this.isPathEqual(o.workspacePath, configuration.workspacePath)).map(o => o.uiState); + const stateForWorkspace = this.windowsState.openedFolders.filter(o => isEqual(o.workspacePath, configuration.workspacePath)).map(o => o.uiState); if (stateForWorkspace.length) { return stateForWorkspace[0]; } @@ -1103,17 +1103,17 @@ export class WindowsManager implements IWindowsMainService { const res = windowsToTest.filter(w => { // match on workspace - if (typeof w.openedWorkspacePath === 'string' && (this.isPathEqual(w.openedWorkspacePath, workspacePath))) { + if (typeof w.openedWorkspacePath === 'string' && (isEqual(w.openedWorkspacePath, workspacePath))) { return true; } // match on file - if (typeof w.openedFilePath === 'string' && this.isPathEqual(w.openedFilePath, filePath)) { + if (typeof w.openedFilePath === 'string' && isEqual(w.openedFilePath, filePath)) { return true; } // match on file path - if (typeof w.openedWorkspacePath === 'string' && filePath && paths.isEqualOrParent(filePath, w.openedWorkspacePath)) { + if (typeof w.openedWorkspacePath === 'string' && filePath && (isEqual(filePath, w.openedWorkspacePath) || isParent(filePath, w.openedWorkspacePath))) { return true; } @@ -1236,30 +1236,6 @@ export class WindowsManager implements IWindowsMainService { this._onWindowClose.fire(win.id); } - private isPathEqual(pathA: string, pathB: string): boolean { - if (pathA === pathB) { - return true; - } - - if (!pathA || !pathB) { - return false; - } - - pathA = path.normalize(pathA); - pathB = path.normalize(pathB); - - if (pathA === pathB) { - return true; - } - - if (!platform.isLinux) { - pathA = pathA.toLowerCase(); - pathB = pathB.toLowerCase(); - } - - return pathA === pathB; - } - public updateWindowsJumpList(): void { if (!platform.isWindows) { return; // only on windows diff --git a/src/vs/code/node/windowsUtils.ts b/src/vs/code/node/windowsUtils.ts index f73a36c83fe..21d38c13a1d 100644 --- a/src/vs/code/node/windowsUtils.ts +++ b/src/vs/code/node/windowsUtils.ts @@ -10,6 +10,7 @@ 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/code/common/windows'; +import { isParent, isEqual } from 'vs/platform/files/common/files'; /** * Exported subset of VSCodeWindow for testing. @@ -46,7 +47,7 @@ export function findBestWindowOrFolder({ win } function findBestWindow(windows: WINDOW[], filePath: string): WINDOW { - const containers = windows.filter(window => typeof window.openedWorkspacePath === 'string' && paths.isEqualOrParent(filePath, window.openedWorkspacePath)); + const containers = windows.filter(window => typeof window.openedWorkspacePath === 'string' && (isEqual(filePath, window.openedWorkspacePath) || isParent(filePath, window.openedWorkspacePath))); if (containers.length) { return containers.sort((a, b) => -(a.openedWorkspacePath.length - b.openedWorkspacePath.length))[0]; } diff --git a/src/vs/workbench/parts/git/browser/views/changes/changesView.ts b/src/vs/workbench/parts/git/browser/views/changes/changesView.ts index 05f83be527c..dba2872a91e 100644 --- a/src/vs/workbench/parts/git/browser/views/changes/changesView.ts +++ b/src/vs/workbench/parts/git/browser/views/changes/changesView.ts @@ -39,6 +39,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { isParent, isEqual } from 'vs/platform/files/common/files'; import IGitService = git.IGitService; @@ -452,12 +453,12 @@ export class ChangesView extends EventEmitter.EventEmitter implements GitView.IV const resource = WorkbenchEditorCommon.toResource(input, { filter: 'file' }); if (resource) { const workspaceRoot = this.contextService.getWorkspace().resource.fsPath; - if (!workspaceRoot || !paths.isEqualOrParent(resource.fsPath, workspaceRoot)) { + if (!workspaceRoot || !isEqual(resource.fsPath, workspaceRoot) || !isParent(resource.fsPath, workspaceRoot)) { return null; // out of workspace not yet supported } const repositoryRoot = this.gitService.getModel().getRepositoryRoot(); - if (!repositoryRoot || !paths.isEqualOrParent(resource.fsPath, repositoryRoot)) { + if (!repositoryRoot || !isEqual(resource.fsPath, repositoryRoot) || !isParent(resource.fsPath, repositoryRoot)) { return null; // out of repository not supported } diff --git a/src/vs/workbench/parts/git/browser/views/changes/changesViewer.ts b/src/vs/workbench/parts/git/browser/views/changes/changesViewer.ts index 75e8ab67fb0..23a5434853a 100644 --- a/src/vs/workbench/parts/git/browser/views/changes/changesViewer.ts +++ b/src/vs/workbench/parts/git/browser/views/changes/changesViewer.ts @@ -330,7 +330,6 @@ export class Renderer implements tree.IRenderer { }; const repositoryRoot = this.gitService.getModel().getRepositoryRoot(); - const workspaceRoot = this.contextService.getWorkspace().resource.fsPath; const status = fileStatus.getStatus(); const renamePath = fileStatus.getRename(); @@ -344,7 +343,7 @@ export class Renderer implements tree.IRenderer { data.status.title = Renderer.statusToTitle(status); const resource = URI.file(paths.normalize(paths.join(repositoryRoot, path))); - let isInWorkspace = paths.isEqualOrParent(resource.fsPath, workspaceRoot); + let isInWorkspace = this.contextService.isInsideWorkspace(resource); let rename = ''; let renameFolder = ''; @@ -358,7 +357,7 @@ export class Renderer implements tree.IRenderer { data.renameFolder.textContent = folder; const resource = URI.file(paths.normalize(paths.join(repositoryRoot, renamePath))); - isInWorkspace = paths.isEqualOrParent(resource.fsPath, workspaceRoot); + isInWorkspace = this.contextService.isInsideWorkspace(resource); } if (isInWorkspace) { diff --git a/src/vs/workbench/services/keybinding/test/keyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/keyboardMapper.test.ts index d1cca102576..ae695735c1b 100644 --- a/src/vs/workbench/services/keybinding/test/keyboardMapper.test.ts +++ b/src/vs/workbench/services/keybinding/test/keyboardMapper.test.ts @@ -14,7 +14,7 @@ import { OperatingSystem } from 'vs/base/common/platform'; import { UserSettingsLabelProvider, PrintableKeypress } from 'vs/platform/keybinding/common/keybindingLabels'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/abstractKeybindingService'; import { KeyboardEventCodeUtils, KeyboardEventCode } from 'vs/workbench/services/keybinding/common/keyboardEventCode'; -import { IHTMLContentElement } from "vs/base/common/htmlContent"; +import { IHTMLContentElement } from 'vs/base/common/htmlContent'; function _assertKeybindingTranslation(mapper: KeyboardMapper, OS: OperatingSystem, kb: number, expected: string[]): void { let keybindingLabel = new USLayoutResolvedKeybinding(createKeybinding(kb), OS).getUserSettingsLabel(); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 3238028c958..2b279afb06e 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -34,7 +34,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IEditorGroupService, GroupArrangement, GroupOrientation, ITabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService'; import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService'; -import { FileOperationEvent, IFileService, IResolveContentOptions, IFileOperationResult, IFileStat, IImportResult, FileChangesEvent, IResolveFileOptions, IContent, IUpdateContentOptions, IStreamContent } from 'vs/platform/files/common/files'; +import { FileOperationEvent, IFileService, IResolveContentOptions, IFileOperationResult, IFileStat, IImportResult, FileChangesEvent, IResolveFileOptions, IContent, IUpdateContentOptions, IStreamContent, isEqual, isParent } from 'vs/platform/files/common/files'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; @@ -52,7 +52,7 @@ import { RawTextSource, IRawTextSource } from 'vs/editor/common/model/textSource import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IThemeService, ITheme, IThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { Color } from "vs/base/common/color"; +import { Color } from 'vs/base/common/color'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, void 0); @@ -93,7 +93,7 @@ export class TestContextService implements IWorkspaceContextService { public isInsideWorkspace(resource: URI): boolean { if (resource && this.workspace) { - return paths.isEqualOrParent(resource.fsPath, this.workspace.resource.fsPath); + return isEqual(resource.fsPath, this.workspace.resource.fsPath) || isParent(resource.fsPath, this.workspace.resource.fsPath); } return false;