diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index 1f0a372ca4349..e1227fb264256 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -9,7 +9,7 @@ import platform = require('vs/base/common/platform'); import types = require('vs/base/common/types'); import { nativeSep, normalize } from 'vs/base/common/paths'; import { endsWith, ltrim } from 'vs/base/common/strings'; -import { isEqual, isParent } from 'vs/platform/files/common/files'; +import { isEqualOrParent } from 'vs/platform/files/common/files'; export interface ILabelProvider { @@ -45,7 +45,7 @@ export function getPathLabel(resource: URI | string, basePathProvider?: URI | st const basepath = basePathProvider && getPath(basePathProvider); - if (basepath && (isEqual(absolutePath, basepath) || isParent(absolutePath, basepath))) { + if (basepath && isEqualOrParent(absolutePath, basepath)) { if (basepath === absolutePath) { return ''; // no label if pathes are identical } diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index eaed0d4acbe8c..e6973131844bb 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -373,7 +373,11 @@ export function equalsIgnoreCase(a: string, b: string): boolean { return false; } - for (let i = 0; i < len1; i++) { + return doEqualsIgnoreCase(a, b); +} + +export function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean { + for (let i = 0; i < stopAt; i++) { let codeA = a.charCodeAt(i), codeB = b.charCodeAt(i); @@ -396,6 +400,15 @@ export function equalsIgnoreCase(a: string, b: string): boolean { return true; } +export function beginsWithIgnoreCase(str: string, candidate: string): boolean { + const candidateLength = candidate.length; + if (candidate.length > str.length) { + return false; + } + + return doEqualsIgnoreCase(str, candidate, candidateLength); +} + /** * @returns the length of the common prefix of the two strings. */ diff --git a/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts index 84c7bee02ed46..84282f3265c16 100644 --- a/src/vs/base/test/common/strings.test.ts +++ b/src/vs/base/test/common/strings.test.ts @@ -9,7 +9,6 @@ import strings = require('vs/base/common/strings'); suite('Strings', () => { test('equalsIgnoreCase', function () { - assert(strings.equalsIgnoreCase('', '')); assert(!strings.equalsIgnoreCase('', '1')); assert(!strings.equalsIgnoreCase('1', '')); @@ -21,6 +20,32 @@ suite('Strings', () => { assert(strings.equalsIgnoreCase('ÖL', 'Öl')); }); + test('beginsWithIgnoreCase', function () { + assert(strings.beginsWithIgnoreCase('', '')); + assert(!strings.beginsWithIgnoreCase('', '1')); + assert(strings.beginsWithIgnoreCase('1', '')); + + assert(strings.beginsWithIgnoreCase('a', 'a')); + assert(strings.beginsWithIgnoreCase('abc', 'Abc')); + assert(strings.beginsWithIgnoreCase('abc', 'ABC')); + assert(strings.beginsWithIgnoreCase('Höhenmeter', 'HÖhenmeter')); + assert(strings.beginsWithIgnoreCase('ÖL', 'Öl')); + + assert(strings.beginsWithIgnoreCase('alles klar', 'a')); + assert(strings.beginsWithIgnoreCase('alles klar', 'A')); + assert(strings.beginsWithIgnoreCase('alles klar', 'alles k')); + assert(strings.beginsWithIgnoreCase('alles klar', 'alles K')); + assert(strings.beginsWithIgnoreCase('alles klar', 'ALLES K')); + assert(strings.beginsWithIgnoreCase('alles klar', 'alles klar')); + assert(strings.beginsWithIgnoreCase('alles klar', 'ALLES KLAR')); + + assert(!strings.beginsWithIgnoreCase('alles klar', ' ALLES K')); + assert(!strings.beginsWithIgnoreCase('alles klar', 'ALLES K ')); + assert(!strings.beginsWithIgnoreCase('alles klar', 'öALLES K ')); + assert(!strings.beginsWithIgnoreCase('alles klar', ' ')); + assert(!strings.beginsWithIgnoreCase('alles klar', 'ö')); + }); + test('compareIgnoreCase', function () { function assertCompareIgnoreCase(a: string, b: string): void { diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 69aef5bce128a..8cd4171ce5518 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -30,7 +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'; +import { isParent, isEqual, isEqualOrParent } from 'vs/platform/files/common/files'; enum WindowError { UNRESPONSIVE, @@ -1113,7 +1113,7 @@ export class WindowsManager implements IWindowsMainService { } // match on file path - if (typeof w.openedWorkspacePath === 'string' && filePath && (isEqual(filePath, w.openedWorkspacePath) || isParent(filePath, w.openedWorkspacePath))) { + if (typeof w.openedWorkspacePath === 'string' && filePath && isEqualOrParent(filePath, w.openedWorkspacePath)) { return true; } diff --git a/src/vs/code/node/windowsUtils.ts b/src/vs/code/node/windowsUtils.ts index 21d38c13a1d6c..d4f9403534a7d 100644 --- a/src/vs/code/node/windowsUtils.ts +++ b/src/vs/code/node/windowsUtils.ts @@ -10,7 +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'; +import { isEqualOrParent } from 'vs/platform/files/common/files'; /** * Exported subset of VSCodeWindow for testing. @@ -47,7 +47,7 @@ export function findBestWindowOrFolder({ win } function findBestWindow(windows: WINDOW[], filePath: string): WINDOW { - const containers = windows.filter(window => typeof window.openedWorkspacePath === 'string' && (isEqual(filePath, window.openedWorkspacePath) || isParent(filePath, window.openedWorkspacePath))); + const containers = windows.filter(window => typeof window.openedWorkspacePath === 'string' && isEqualOrParent(filePath, window.openedWorkspacePath)); if (containers.length) { return containers.sort((a, b) => -(a.openedWorkspacePath.length - b.openedWorkspacePath.length))[0]; } diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 1e7170d167b3f..578772f89a8c3 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -13,6 +13,7 @@ import { isLinux } from 'vs/base/common/platform'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; import { Schemas } from 'vs/base/common/network'; +import { equalsIgnoreCase, beginsWithIgnoreCase } from 'vs/base/common/strings'; export const IFileService = createDecorator('fileService'); @@ -231,7 +232,7 @@ export class FileChangesEvent extends events.Event { // For deleted also return true when deleted folder is parent of target path if (type === FileChangeType.DELETED) { - return isEqual(resource.fsPath, change.resource.fsPath) || isParent(resource.fsPath, change.resource.fsPath); + return isEqualOrParent(resource.fsPath, change.resource.fsPath); } return isEqual(resource.fsPath, change.resource.fsPath); @@ -325,18 +326,30 @@ export function isEqual(resourceOrPathA: string | URI, resourceOrPathB: string | const pathA = resourceOrPathA; const pathB = resourceOrPathB as string; - if (isLinux || identityEquals) { + if (isLinux) { return identityEquals; } - if (pathA.length !== pathB.length) { + return equalsIgnoreCase(pathA, pathB); +} + +export function isParent(path: string, candidate: string): boolean { + if (candidate.length > path.length) { return false; } - return pathA.toLowerCase() === pathB.toLowerCase(); + if (!isLinux) { + return beginsWithIgnoreCase(path, candidate + paths.nativeSep); + } + + return path.indexOf(candidate + paths.nativeSep) === 0; } -export function isParent(path: string, candidate: string): boolean { +export function isEqualOrParent(path: string, candidate: string): boolean { + if (path === candidate) { + return true; + } + if (candidate.length > path.length) { return false; } @@ -344,12 +357,24 @@ export function isParent(path: string, candidate: string): boolean { if (!isLinux) { path = path.toLowerCase(); candidate = candidate.toLowerCase(); + + if (path === candidate) { + return true; + } } return path.indexOf(candidate + paths.nativeSep) === 0; } export function indexOf(path: string, candidate: string): number { + if (candidate.length > path.length) { + return -1; + } + + if (path === candidate) { + return 0; + } + if (!isLinux) { path = path.toLowerCase(); candidate = candidate.toLowerCase(); diff --git a/src/vs/platform/files/test/files.test.ts b/src/vs/platform/files/test/files.test.ts index 80c1abd7bd028..93a5076dc3a44 100644 --- a/src/vs/platform/files/test/files.test.ts +++ b/src/vs/platform/files/test/files.test.ts @@ -8,7 +8,7 @@ import * as assert from 'assert'; import URI from 'vs/base/common/uri'; import { join } from 'vs/base/common/paths'; -import { FileChangeType, FileChangesEvent, isEqual, isParent, indexOf } from 'vs/platform/files/common/files'; +import { FileChangeType, FileChangesEvent, isEqual, isParent, isEqualOrParent, indexOf } from 'vs/platform/files/common/files'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; suite('Files', () => { @@ -94,8 +94,41 @@ suite('Files', () => { } }); + test('isEqualOrParent', function () { + assert(isEqualOrParent('foo/bar/test.ts', 'foo')); + assert(isEqualOrParent('/', '/')); + assert(isEqualOrParent('/foo', '/foo')); + assert(!isEqualOrParent('/foo', '/f')); + assert(!isEqualOrParent('/foo', '/foo/b')); + assert(isEqualOrParent('foo/bar/test.ts', 'foo/bar')); + assert(!isEqualOrParent('foo/bar/test.ts', '/foo/bar')); + assert(!isEqualOrParent('foo/bar/test.ts', 'foo/barr')); + assert(isEqualOrParent('foo/bar/test.ts', 'foo/bar/test.ts')); + assert(!isEqualOrParent('foo/bar/test.ts', 'foo/bar/test')); + assert(!isEqualOrParent('foo/bar/test.ts', 'foo/bar/test.')); + + if (!isLinux) { + assert(isEqualOrParent('/foo', '/fOO')); + assert(isEqualOrParent('/fOO', '/foo')); + assert(isEqualOrParent('foo/bar/test.ts', 'foo/BAR/test.ts')); + assert(!isEqualOrParent('foo/bar/test.ts', 'foo/BAR/test.')); + } + + if (isWindows) { + assert.ok(!isEqualOrParent('c:\\some\\path', 'c:\\some\\path')); + assert.ok(isEqualOrParent('c:\\some\\path', 'c:\\some')); + assert.ok(!isEqualOrParent('c:\\some\\path', 'c:\\some\\path')); + assert.ok(isEqualOrParent('c:\\some\\path', 'c:\\some')); + } + }); + test('indexOf', function () { assert.equal(indexOf('/some/path', '/some/path'), 0); + assert.equal(indexOf('/some/path/more', '/some/path'), 0); + + assert.equal(indexOf('c:\\some\\path', 'c:\\some\\path'), 0); + assert.equal(indexOf('c:\\some\\path\\more', 'c:\\some\\path'), 0); + assert.equal(indexOf('/some/path', '/some/other/path'), -1); if (isLinux) { diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index f9d1a620d9bd6..611e8a42f52e5 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -7,7 +7,7 @@ import URI from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import paths = require('vs/base/common/paths'); -import { isEqual, isParent } from 'vs/platform/files/common/files'; +import { isEqualOrParent } from 'vs/platform/files/common/files'; export const IWorkspaceContextService = createDecorator('contextService'); @@ -84,7 +84,7 @@ export class WorkspaceContextService implements IWorkspaceContextService { public isInsideWorkspace(resource: URI): boolean { if (resource && this.workspace) { - return isEqual(resource.fsPath, this.workspace.resource.fsPath) || isParent(resource.fsPath, this.workspace.resource.fsPath); + return isEqualOrParent(resource.fsPath, this.workspace.resource.fsPath); } return false; diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index e7b10bc1ff7a8..8e47c17348699 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -25,7 +25,7 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { VIEWLET_ID } from 'vs/workbench/parts/files/common/files'; import labels = require('vs/base/common/labels'); import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileService, IFileStat, isEqual, isParent } from 'vs/platform/files/common/files'; +import { IFileService, IFileStat, isEqual, isEqualOrParent } from 'vs/platform/files/common/files'; import { toResource, IEditorIdentifier, EditorInput } from 'vs/workbench/common/editor'; import { FileStat, NewStatPlaceholder } from 'vs/workbench/parts/files/common/explorerViewModel'; import { ExplorerView } from 'vs/workbench/parts/files/browser/views/explorerView'; @@ -288,7 +288,7 @@ class RenameFileAction extends BaseRenameAction { public runAction(newName: string): TPromise { let isDirtyCaseChange = false; - const dirty = this.textFileService.getDirty().filter(d => isEqual(d.fsPath, this.element.resource.fsPath) || isParent(d.fsPath, this.element.resource.fsPath)); + const dirty = this.textFileService.getDirty().filter(d => isEqualOrParent(d.fsPath, this.element.resource.fsPath)); const dirtyRenamed = dirty.map(d => { const targetPath = paths.join(this.element.parent.resource.fsPath, newName); let renamed: URI; @@ -702,7 +702,7 @@ export class BaseDeleteFileAction extends BaseFileAction { // Handle dirty let revertPromise: TPromise = TPromise.as(null); - const dirty = this.textFileService.getDirty().filter(d => isEqual(d.fsPath, this.element.resource.fsPath) || isParent(d.fsPath, this.element.resource.fsPath)); + const dirty = this.textFileService.getDirty().filter(d => isEqualOrParent(d.fsPath, this.element.resource.fsPath)); if (dirty.length) { let message: string; if (this.element.isDirectory) { @@ -994,7 +994,7 @@ export class PasteFileAction extends BaseFileAction { } // Check if target is ancestor of pasted folder - if (!isEqual(this.element.resource.fsPath, fileToCopy.resource.fsPath) && (isEqual(this.element.resource.fsPath, fileToCopy.resource.fsPath) || isParent(this.element.resource.fsPath, fileToCopy.resource.fsPath))) { + if (!isEqual(this.element.resource.fsPath, fileToCopy.resource.fsPath) && isEqualOrParent(this.element.resource.fsPath, fileToCopy.resource.fsPath)) { return false; } diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index ab636419a80fb..dc2cbcaa081e2 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -17,7 +17,7 @@ import { prepareActions } from 'vs/workbench/browser/actionBarRegistry'; import { ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocussedContext, ExplorerFocussedContext } from 'vs/workbench/parts/files/common/files'; -import { FileOperation, FileOperationEvent, IResolveFileOptions, FileChangeType, FileChangesEvent, IFileChange, IFileService, isEqual, isParent } from 'vs/platform/files/common/files'; +import { FileOperation, FileOperationEvent, IResolveFileOptions, FileChangeType, FileChangesEvent, IFileChange, IFileService, isEqual, isEqualOrParent } from 'vs/platform/files/common/files'; import { RefreshViewExplorerAction, NewFolderAction, NewFileAction } from 'vs/workbench/parts/files/browser/fileActions'; import { FileDragAndDrop, FileFilter, FileSorter, FileController, FileRenderer, FileDataSource, FileViewletState, FileAccessibilityProvider } from 'vs/workbench/parts/files/browser/views/explorerViewer'; import lifecycle = require('vs/base/common/lifecycle'); @@ -734,7 +734,7 @@ export class ExplorerView extends CollapsibleViewletView { // Drop those path which are parents of the current one for (let i = resolvedDirectories.length - 1; i >= 0; i--) { const resource = resolvedDirectories[i]; - if (isEqual(stat.resource.fsPath, resource.fsPath) || isParent(stat.resource.fsPath, resource.fsPath)) { + if (isEqualOrParent(stat.resource.fsPath, resource.fsPath)) { resolvedDirectories.splice(i); } } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 9875befbb440a..a7ef92c102316 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -26,7 +26,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegistry'; import { IFilesConfiguration } from 'vs/workbench/parts/files/common/files'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileOperationResult, FileOperationResult, IFileService, isEqual, isParent } from 'vs/platform/files/common/files'; +import { IFileOperationResult, FileOperationResult, IFileService, isEqual, isEqualOrParent } from 'vs/platform/files/common/files'; import { ResourceMap } from 'vs/base/common/map'; import { DuplicateFileAction, ImportFileAction, IEditableData, IFileViewletState } from 'vs/workbench/parts/files/browser/fileActions'; import { IDataSource, ITree, IElementCallback, IAccessibilityProvider, IRenderer, ContextMenuEvent, ISorter, IFilter, IDragAndDrop, IDragAndDropData, IDragOverReaction, DRAG_OVER_ACCEPT_BUBBLE_DOWN, DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY, DRAG_OVER_ACCEPT_BUBBLE_UP, DRAG_OVER_ACCEPT_BUBBLE_UP_COPY, DRAG_OVER_REJECT } from 'vs/base/parts/tree/browser/tree'; @@ -697,7 +697,7 @@ export class FileDragAndDrop implements IDragAndDrop { return true; // Can not move a file to the same parent unless we copy } - if (isEqual(target.resource.fsPath, source.resource.fsPath) || isParent(target.resource.fsPath, source.resource.fsPath)) { + if (isEqualOrParent(target.resource.fsPath, source.resource.fsPath)) { return true; // Can not move a parent folder into one of its children } @@ -759,7 +759,7 @@ export class FileDragAndDrop implements IDragAndDrop { }; // 1. check for dirty files that are being moved and backup to new target - const dirty = this.textFileService.getDirty().filter(d => isEqual(d.fsPath, source.resource.fsPath) || isParent(d.fsPath, source.resource.fsPath)); + const dirty = this.textFileService.getDirty().filter(d => isEqualOrParent(d.fsPath, source.resource.fsPath)); return TPromise.join(dirty.map(d => { let moved: URI; @@ -802,7 +802,7 @@ export class FileDragAndDrop implements IDragAndDrop { // Move with overwrite if the user confirms if (this.messageService.confirm(confirm)) { - const targetDirty = this.textFileService.getDirty().filter(d => isEqual(d.fsPath, targetResource.fsPath) || isParent(d.fsPath, targetResource.fsPath)); + const targetDirty = this.textFileService.getDirty().filter(d => isEqualOrParent(d.fsPath, targetResource.fsPath)); // Make sure to revert all dirty in target first to be able to overwrite properly return this.textFileService.revertAll(targetDirty, { soft: true /* do not attempt to load content from disk */ }).then(() => { diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index 46a39c0fb4989..30038c6973d09 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -13,7 +13,7 @@ import { IEditor, IEditorViewState, isCommonCodeEditor } from 'vs/editor/common/ import { toResource, IEditorStacksModel, SideBySideEditorInput, IEditorGroup, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor'; import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/parts/files/common/files'; import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; -import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent, isEqual, indexOf, isParent } from 'vs/platform/files/common/files'; +import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent, isEqual, indexOf, isEqualOrParent } from 'vs/platform/files/common/files'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -113,8 +113,8 @@ export class FileEditorTracker implements IWorkbenchContribution { // Do NOT close any opened editor that matches the resource path (either equal or being parent) of the // resource we move to (movedTo). Otherwise we would close a resource that has been renamed to the same - // path but different casing. - if (movedTo && (isEqual(resource.fsPath, movedTo.fsPath) || isParent(resource.fsPath, movedTo.fsPath)) && resource.fsPath.indexOf(movedTo.fsPath) === 0) { + // path but different casing. + if (movedTo && isEqualOrParent(resource.fsPath, movedTo.fsPath) && resource.fsPath.indexOf(movedTo.fsPath) === 0) { return; } @@ -122,7 +122,7 @@ export class FileEditorTracker implements IWorkbenchContribution { if (arg1 instanceof FileChangesEvent) { matches = arg1.contains(resource, FileChangeType.DELETED); } else { - matches = isEqual(resource.fsPath, arg1.fsPath) || isParent(resource.fsPath, arg1.fsPath); + matches = isEqualOrParent(resource.fsPath, arg1.fsPath); } if (!matches) { @@ -194,7 +194,7 @@ export class FileEditorTracker implements IWorkbenchContribution { const resource = input.getResource(); // Update Editor if file (or any parent of the input) got renamed or moved - if (isEqual(resource.fsPath, oldResource.fsPath) || isParent(resource.fsPath, oldResource.fsPath)) { + if (isEqualOrParent(resource.fsPath, oldResource.fsPath)) { let reopenFileResource: URI; if (oldResource.toString() === resource.toString()) { reopenFileResource = newResource; // file got moved diff --git a/src/vs/workbench/parts/files/common/explorerViewModel.ts b/src/vs/workbench/parts/files/common/explorerViewModel.ts index 1608e5b0659dd..33066d5f6e6c5 100644 --- a/src/vs/workbench/parts/files/common/explorerViewModel.ts +++ b/src/vs/workbench/parts/files/common/explorerViewModel.ts @@ -7,7 +7,7 @@ import URI from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); -import { IFileStat, isEqual, isParent } from 'vs/platform/files/common/files'; +import { IFileStat, isEqual, isParent, isEqualOrParent } from 'vs/platform/files/common/files'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { IEditorInput } from 'vs/platform/editor/common/editor'; import { IEditorGroup, toResource } from 'vs/workbench/common/editor'; @@ -61,7 +61,7 @@ export class FileStat implements IFileStat { // the folder is fully resolved if either it has a list of children or the client requested this by using the resolveTo // array of resource path to resolve. stat.isDirectoryResolved = !!raw.children || (!!resolveTo && resolveTo.some((r) => { - return isEqual(r.fsPath, stat.resource.fsPath) || isParent(r.fsPath, stat.resource.fsPath); + return isEqualOrParent(r.fsPath, stat.resource.fsPath); })); // Recurse into children 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 dba2872a91edf..7be73c477ce2c 100644 --- a/src/vs/workbench/parts/git/browser/views/changes/changesView.ts +++ b/src/vs/workbench/parts/git/browser/views/changes/changesView.ts @@ -39,7 +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 { isEqualOrParent } from 'vs/platform/files/common/files'; import IGitService = git.IGitService; @@ -453,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 || !isEqual(resource.fsPath, workspaceRoot) || !isParent(resource.fsPath, workspaceRoot)) { + if (!workspaceRoot || !isEqualOrParent(resource.fsPath, workspaceRoot)) { return null; // out of workspace not yet supported } const repositoryRoot = this.gitService.getModel().getRepositoryRoot(); - if (!repositoryRoot || !isEqual(resource.fsPath, repositoryRoot) || !isParent(resource.fsPath, repositoryRoot)) { + if (!repositoryRoot || !isEqualOrParent(resource.fsPath, repositoryRoot)) { return null; // out of repository not supported } diff --git a/src/vs/workbench/services/files/node/fileService.ts b/src/vs/workbench/services/files/node/fileService.ts index 14c75332f7206..b00931d927ed9 100644 --- a/src/vs/workbench/services/files/node/fileService.ts +++ b/src/vs/workbench/services/files/node/fileService.ts @@ -11,7 +11,7 @@ import os = require('os'); import crypto = require('crypto'); import assert = require('assert'); -import { isEqual, isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveContentOptions, IFileStat, IStreamContent, IFileOperationResult, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent } from 'vs/platform/files/common/files'; +import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveContentOptions, IFileStat, IStreamContent, IFileOperationResult, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, isEqualOrParent } from 'vs/platform/files/common/files'; import strings = require('vs/base/common/strings'); import { ResourceMap } from 'vs/base/common/map'; import arrays = require('vs/base/common/arrays'); @@ -433,7 +433,7 @@ export class FileService implements IFileService { // 2.) make sure target is deleted before we move/copy unless this is a case rename of the same file let deleteTargetPromise = TPromise.as(null); if (exists && !isCaseRename) { - if (isEqual(sourcePath, targetPath) || isParent(sourcePath, targetPath)) { + if (isEqualOrParent(sourcePath, targetPath)) { return TPromise.wrapError(nls.localize('unableToMoveCopyError', "Unable to move/copy. File would replace folder it is contained in.")); // catch this corner case! } @@ -898,7 +898,7 @@ export class StatResolver { let resolveFolderChildren = false; if (files.length === 1 && resolveSingleChildDescendants) { resolveFolderChildren = true; - } else if (childCount > 0 && absoluteTargetPaths && absoluteTargetPaths.some(targetPath => isEqual(targetPath, fileResource.fsPath) || isParent(targetPath, fileResource.fsPath))) { + } else if (childCount > 0 && absoluteTargetPaths && absoluteTargetPaths.some(targetPath => isEqualOrParent(targetPath, fileResource.fsPath))) { resolveFolderChildren = true; } diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 64a34c6c566fe..fc2f38f11ef4f 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, isEqual, isParent } from 'vs/platform/files/common/files'; +import { FileOperationEvent, IFileService, IResolveContentOptions, IFileOperationResult, IFileStat, IImportResult, FileChangesEvent, IResolveFileOptions, IContent, IUpdateContentOptions, IStreamContent, isEqualOrParent } 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'; @@ -93,7 +93,7 @@ export class TestContextService implements IWorkspaceContextService { public isInsideWorkspace(resource: URI): boolean { if (resource && this.workspace) { - return isEqual(resource.fsPath, this.workspace.resource.fsPath) || isParent(resource.fsPath, this.workspace.resource.fsPath); + return isEqualOrParent(resource.fsPath, this.workspace.resource.fsPath); } return false;