Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/microsoft/vscode.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Rieken <johannes.rieken@gmail.com>2020-05-29 10:33:00 +0300
committerJohannes Rieken <johannes.rieken@gmail.com>2020-05-29 10:33:14 +0300
commit187dedbdc33e91b53dff9e3ed0f8278b27d113c7 (patch)
tree09cadb290c5c3391463d5f85ead628b0a92d45f9
parent5bc69ea145fc91a7ceab283a1a97d35b2a9fd738 (diff)
remove the ability to ignore path casing from util functions itself, #93368
This change removes the `ignorePathCasing` argument from utils like `isEqual` et al. This is replaced with ExtUri-instances that know (or guess) when path casing matters.
-rw-r--r--src/vs/base/common/resources.ts150
-rw-r--r--src/vs/base/test/common/resources.test.ts61
-rw-r--r--src/vs/editor/contrib/gotoSymbol/referencesModel.ts6
-rw-r--r--src/vs/platform/files/common/fileService.ts10
-rw-r--r--src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts4
-rw-r--r--src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts6
-rw-r--r--src/vs/workbench/contrib/files/browser/views/explorerView.ts8
-rw-r--r--src/vs/workbench/contrib/markers/browser/markersModel.ts8
-rw-r--r--src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts8
-rw-r--r--src/vs/workbench/services/log/common/keyValueLogProvider.ts6
-rw-r--r--src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts4
11 files changed, 156 insertions, 115 deletions
diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts
index a243b433d60..69d176baca8 100644
--- a/src/vs/base/common/resources.ts
+++ b/src/vs/base/common/resources.ts
@@ -33,7 +33,16 @@ export interface IExtUri {
* @param uri2 Uri
* @param ignoreFragment Ignore the fragment (defaults to `false`)
*/
- isEqual(uri1: URI, uri2: URI, ignoreFragment?: boolean): boolean;
+ isEqual(uri1: URI | undefined, uri2: URI | undefined, ignoreFragment?: boolean): boolean;
+
+ /**
+ * Tests whether a `candidate` URI is a parent or equal of a given `base` URI.
+ *
+ * @param base A uri which is "longer"
+ * @param parentCandidate A uri which is "shorter" then `base`
+ * @param ignoreFragment Ignore the fragment (defaults to `false`)
+ */
+ isEqualOrParent(base: URI, parentCandidate: URI, ignoreFragment?: boolean): boolean;
/**
* Creates a key from a resource URI to be used to resource comparison and for resource maps.
@@ -42,6 +51,13 @@ export interface IExtUri {
* @param ignoreFragment Ignore the fragment (defaults to `false`)
*/
getComparisonKey(uri: URI, ignoreFragment?: boolean): string;
+
+ /**
+ *
+ * @param from
+ * @param to
+ */
+ relativePath(from: URI, to: URI): string | undefined;
}
export class ExtUri implements IExtUri {
@@ -71,11 +87,62 @@ export class ExtUri implements IExtUri {
}
getComparisonKey(uri: URI, ignoreFragment: boolean = false): string {
- return getComparisonKey(uri, this._ignorePathCasing(uri), ignoreFragment);
+ return uri.with({
+ path: this._ignorePathCasing(uri) ? uri.path.toLowerCase() : undefined,
+ fragment: ignoreFragment ? null : undefined
+ }).toString();
+ }
+
+ isEqual(uri1: URI | undefined, uri2: URI | undefined, ignoreFragment: boolean = false): boolean {
+ if (uri1 === uri2) {
+ return true;
+ }
+ if (!uri1 || !uri2) {
+ return false;
+ }
+ if (uri1.scheme !== uri2.scheme || !isEqualAuthority(uri1.authority, uri2.authority)) {
+ return false;
+ }
+ const p1 = uri1.path, p2 = uri2.path;
+ return (p1 === p2 || this._ignorePathCasing(uri1) && equalsIgnoreCase(p1, p2)) && uri1.query === uri2.query && (ignoreFragment || uri1.fragment === uri2.fragment);
}
- isEqual(uri1: URI, uri2: URI, ignoreFragment: boolean = false): boolean {
- return isEqual(uri1, uri2, this._ignorePathCasing(uri1), ignoreFragment);
+ isEqualOrParent(base: URI, parentCandidate: URI, ignoreFragment: boolean = false): boolean {
+ if (base.scheme === parentCandidate.scheme) {
+ if (base.scheme === Schemas.file) {
+ return extpath.isEqualOrParent(originalFSPath(base), originalFSPath(parentCandidate), this._ignorePathCasing(base)) && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);
+ }
+ if (isEqualAuthority(base.authority, parentCandidate.authority)) {
+ return extpath.isEqualOrParent(base.path, parentCandidate.path, this._ignorePathCasing(base), '/') && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);
+ }
+ }
+ return false;
+ }
+
+ // --- path math
+
+ relativePath(from: URI, to: URI): string | undefined {
+ if (from.scheme !== to.scheme || !isEqualAuthority(from.authority, to.authority)) {
+ return undefined;
+ }
+ if (from.scheme === Schemas.file) {
+ const relativePath = paths.relative(originalFSPath(from), originalFSPath(to));
+ return isWindows ? extpath.toSlashes(relativePath) : relativePath;
+ }
+ let fromPath = from.path || '/', toPath = to.path || '/';
+ if (this._ignorePathCasing(from)) {
+ // make casing of fromPath match toPath
+ let i = 0;
+ for (const len = Math.min(fromPath.length, toPath.length); i < len; i++) {
+ if (fromPath.charCodeAt(i) !== toPath.charCodeAt(i)) {
+ if (fromPath.charAt(i).toLowerCase() !== toPath.charAt(i).toLowerCase()) {
+ break;
+ }
+ }
+ }
+ fromPath = toPath.substr(0, i) + fromPath.substr(i);
+ }
+ return paths.posix.relative(fromPath, toPath);
}
}
@@ -86,8 +153,16 @@ export class ExtUri implements IExtUri {
* assertEqual(aUri.toString() === bUri.toString(), exturi.isEqual(aUri, bUri))
* ```
*/
-export const exturi = new ExtUri(() => false);
+export const extUri = new ExtUri(() => false);
+/**
+ * BIASED utility that always ignores the casing of uris path. ONLY use these util if you
+ * understand what you are doing.
+ *
+ * Note that `IUriIdentityService#extUri` is a better replacement for this because that utility
+ * knows when path casing matters and when not.
+ */
+export const extUriIgnorePathCase = new ExtUri(_ => true);
//#endregion
@@ -95,25 +170,20 @@ export function originalFSPath(uri: URI): string {
return uriToFsPath(uri, true);
}
-// DO NOT EXPORT, DO NOT USE
-function _ignorePathCasingGuess(resource: URI | undefined): boolean {
+const exturiBiasedIgnorePathCase = new ExtUri(uri => {
// A file scheme resource is in the same platform as code, so ignore case for non linux platforms
// Resource can be from another platform. Lowering the case as an hack. Should come from File system provider
- return resource && resource.scheme === Schemas.file ? !isLinux : true;
-}
+ return uri && uri.scheme === Schemas.file ? !isLinux : true;
+});
/**
* Creates a key from a resource URI to be used to resource comparison and for resource maps.
*
* @param resource Uri
- * @param ignorePathCasing Ignore casing when comparing path component (defaults mostly to `true`)
* @param ignoreFragment Ignore the fragment (defaults to `false`)
*/
-export function getComparisonKey(resource: URI, ignorePathCasing: boolean = _ignorePathCasingGuess(resource), ignoreFragment: boolean = false): string {
- return resource.with({
- path: ignorePathCasing ? resource.path.toLowerCase() : undefined,
- fragment: ignoreFragment ? null : undefined
- }).toString();
+export function getComparisonKey(resource: URI, ignoreFragment: boolean = false): string {
+ return exturiBiasedIgnorePathCase.getComparisonKey(resource, ignoreFragment);
}
/**
@@ -124,18 +194,8 @@ export function getComparisonKey(resource: URI, ignorePathCasing: boolean = _ign
* @param ignorePathCasing Ignore casing when comparing path component (defaults mostly to `true`)
* @param ignoreFragment Ignore the fragment (defaults to `false`)
*/
-export function isEqual(first: URI | undefined, second: URI | undefined, ignorePathCasing: boolean = _ignorePathCasingGuess(first), ignoreFragment: boolean = false): boolean {
- if (first === second) {
- return true;
- }
- if (!first || !second) {
- return false;
- }
- if (first.scheme !== second.scheme || !isEqualAuthority(first.authority, second.authority)) {
- return false;
- }
- const p1 = first.path, p2 = second.path;
- return (p1 === p2 || ignorePathCasing && equalsIgnoreCase(p1, p2)) && first.query === second.query && (ignoreFragment || first.fragment === second.fragment);
+export function isEqual(first: URI | undefined, second: URI | undefined, ignoreFragment: boolean = false): boolean {
+ return exturiBiasedIgnorePathCase.isEqual(first, second, ignoreFragment);
}
@@ -147,16 +207,8 @@ export function isEqual(first: URI | undefined, second: URI | undefined, ignoreP
* @param ignorePathCasing Ignore casing when comparing path component (defaults mostly to `true`)
* @param ignoreFragment Ignore the fragment (defaults to `false`)
*/
-export function isEqualOrParent(base: URI, parentCandidate: URI, ignorePathCasing: boolean = _ignorePathCasingGuess(base), ignoreFragment: boolean = false): boolean {
- if (base.scheme === parentCandidate.scheme) {
- if (base.scheme === Schemas.file) {
- return extpath.isEqualOrParent(originalFSPath(base), originalFSPath(parentCandidate), ignorePathCasing) && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);
- }
- if (isEqualAuthority(base.authority, parentCandidate.authority)) {
- return extpath.isEqualOrParent(base.path, parentCandidate.path, ignorePathCasing, '/') && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);
- }
- }
- return false;
+export function isEqualOrParent(base: URI, parentCandidate: URI, ignoreFragment: boolean = false): boolean {
+ return exturiBiasedIgnorePathCase.isEqualOrParent(base, parentCandidate, ignoreFragment);
}
@@ -300,28 +352,8 @@ export function addTrailingPathSeparator(resource: URI, sep: string = paths.sep)
* Returns a relative path between two URIs. If the URIs don't have the same schema or authority, `undefined` is returned.
* The returned relative path always uses forward slashes.
*/
-export function relativePath(from: URI, to: URI, ignorePathCasing = _ignorePathCasingGuess(from)): string | undefined {
- if (from.scheme !== to.scheme || !isEqualAuthority(from.authority, to.authority)) {
- return undefined;
- }
- if (from.scheme === Schemas.file) {
- const relativePath = paths.relative(originalFSPath(from), originalFSPath(to));
- return isWindows ? extpath.toSlashes(relativePath) : relativePath;
- }
- let fromPath = from.path || '/', toPath = to.path || '/';
- if (ignorePathCasing) {
- // make casing of fromPath match toPath
- let i = 0;
- for (const len = Math.min(fromPath.length, toPath.length); i < len; i++) {
- if (fromPath.charCodeAt(i) !== toPath.charCodeAt(i)) {
- if (fromPath.charAt(i).toLowerCase() !== toPath.charAt(i).toLowerCase()) {
- break;
- }
- }
- }
- fromPath = toPath.substr(0, i) + fromPath.substr(i);
- }
- return paths.posix.relative(fromPath, toPath);
+export function relativePath(from: URI, to: URI): string | undefined {
+ return exturiBiasedIgnorePathCase.relativePath(from, to);
}
/**
diff --git a/src/vs/base/test/common/resources.test.ts b/src/vs/base/test/common/resources.test.ts
index eff29b06bca..1e0d4496e26 100644
--- a/src/vs/base/test/common/resources.test.ts
+++ b/src/vs/base/test/common/resources.test.ts
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
-import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath, addTrailingPathSeparator, getComparisonKey, exturi } from 'vs/base/common/resources';
+import { dirname, basename, distinctParents, joinPath, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath, addTrailingPathSeparator, extUri, extUriIgnorePathCase } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { isWindows } from 'vs/base/common/platform';
import { toSlashes } from 'vs/base/common/extpath';
@@ -235,16 +235,19 @@ suite('Resources', () => {
}
});
- function assertEqualURI(actual: URI, expected: URI, message?: string) {
- if (!isEqual(expected, actual, undefined, false)) {
+ function assertEqualURI(actual: URI, expected: URI, message?: string, ignoreCase?: boolean) {
+ let util = ignoreCase ? extUriIgnorePathCase : extUri;
+ if (!util.isEqual(expected, actual)) {
assert.equal(actual.toString(), expected.toString(), message);
}
}
function assertRelativePath(u1: URI, u2: URI, expectedPath: string | undefined, ignoreJoin?: boolean, ignoreCase?: boolean) {
- assert.equal(relativePath(u1, u2, ignoreCase), expectedPath, `from ${u1.toString()} to ${u2.toString()}`);
+ let util = ignoreCase ? extUriIgnorePathCase : extUri;
+
+ assert.equal(util.relativePath(u1, u2), expectedPath, `from ${u1.toString()} to ${u2.toString()}`);
if (expectedPath !== undefined && !ignoreJoin) {
- assertEqualURI(removeTrailingPathSeparator(joinPath(u1, expectedPath)), removeTrailingPathSeparator(u2), 'joinPath on relativePath should be equal');
+ assertEqualURI(removeTrailingPathSeparator(joinPath(u1, expectedPath)), removeTrailingPathSeparator(u2), 'joinPath on relativePath should be equal', ignoreCase);
}
}
@@ -347,13 +350,16 @@ suite('Resources', () => {
});
function assertIsEqual(u1: URI, u2: URI, ignoreCase: boolean | undefined, expected: boolean) {
- assert.equal(isEqual(u1, u2, ignoreCase), expected, `${u1.toString()}${expected ? '===' : '!=='}${u2.toString()}`);
+
+ let util = ignoreCase ? extUriIgnorePathCase : extUri;
+
+ assert.equal(util.isEqual(u1, u2), expected, `${u1.toString()}${expected ? '===' : '!=='}${u2.toString()}`);
+ assert.equal(util.compare(u1, u2) === 0, expected);
+ assert.equal(util.getComparisonKey(u1) === util.getComparisonKey(u2), expected, `comparison keys ${u1.toString()}, ${u2.toString()}`);
+ assert.equal(util.isEqualOrParent(u1, u2), expected, `isEqualOrParent ${u1.toString()}, ${u2.toString()}`);
if (!ignoreCase) {
- assert.equal(exturi.compare(u1, u2) === 0, expected);
assert.equal(u1.toString() === u2.toString(), expected);
}
- assert.equal(getComparisonKey(u1, ignoreCase) === getComparisonKey(u2, ignoreCase), expected, `comparison keys ${u1.toString()}, ${u2.toString()}`);
- assert.equal(isEqualOrParent(u1, u2, ignoreCase), expected, `isEqualOrParent ${u1.toString()}, ${u2.toString()}`);
}
@@ -393,34 +399,35 @@ suite('Resources', () => {
});
test('isEqualOrParent', () => {
+
let fileURI = isWindows ? URI.file('c:\\foo\\bar') : URI.file('/foo/bar');
let fileURI2 = isWindows ? URI.file('c:\\foo') : URI.file('/foo');
let fileURI2b = isWindows ? URI.file('C:\\Foo\\') : URI.file('/Foo/');
- assert.equal(isEqualOrParent(fileURI, fileURI, true), true, '1');
- assert.equal(isEqualOrParent(fileURI, fileURI, false), true, '2');
- assert.equal(isEqualOrParent(fileURI, fileURI2, true), true, '3');
- assert.equal(isEqualOrParent(fileURI, fileURI2, false), true, '4');
- assert.equal(isEqualOrParent(fileURI, fileURI2b, true), true, '5');
- assert.equal(isEqualOrParent(fileURI, fileURI2b, false), false, '6');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI, fileURI), true, '1');
+ assert.equal(extUri.isEqualOrParent(fileURI, fileURI), true, '2');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI, fileURI2), true, '3');
+ assert.equal(extUri.isEqualOrParent(fileURI, fileURI2), true, '4');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI, fileURI2b), true, '5');
+ assert.equal(extUri.isEqualOrParent(fileURI, fileURI2b), false, '6');
- assert.equal(isEqualOrParent(fileURI2, fileURI, false), false, '7');
- assert.equal(isEqualOrParent(fileURI2b, fileURI2, true), true, '8');
+ assert.equal(extUri.isEqualOrParent(fileURI2, fileURI), false, '7');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI2b, fileURI2), true, '8');
let fileURI3 = URI.parse('foo://server:453/foo/bar/goo');
let fileURI4 = URI.parse('foo://server:453/foo/');
let fileURI5 = URI.parse('foo://server:453/foo');
- assert.equal(isEqualOrParent(fileURI3, fileURI3, true), true, '11');
- assert.equal(isEqualOrParent(fileURI3, fileURI3, false), true, '12');
- assert.equal(isEqualOrParent(fileURI3, fileURI4, true), true, '13');
- assert.equal(isEqualOrParent(fileURI3, fileURI4, false), true, '14');
- assert.equal(isEqualOrParent(fileURI3, fileURI, true), false, '15');
- assert.equal(isEqualOrParent(fileURI5, fileURI5, true), true, '16');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI3, fileURI3, true), true, '11');
+ assert.equal(extUri.isEqualOrParent(fileURI3, fileURI3), true, '12');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI3, fileURI4, true), true, '13');
+ assert.equal(extUri.isEqualOrParent(fileURI3, fileURI4), true, '14');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI3, fileURI, true), false, '15');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI5, fileURI5, true), true, '16');
let fileURI6 = URI.parse('foo://server:453/foo?q=1');
let fileURI7 = URI.parse('foo://server:453/foo/bar?q=1');
- assert.equal(isEqualOrParent(fileURI6, fileURI5, true), false, '17');
- assert.equal(isEqualOrParent(fileURI6, fileURI6, true), true, '18');
- assert.equal(isEqualOrParent(fileURI7, fileURI6, true), true, '19');
- assert.equal(isEqualOrParent(fileURI7, fileURI5, true), false, '20');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI6, fileURI5), false, '17');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI6, fileURI6), true, '18');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI7, fileURI6), true, '19');
+ assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI7, fileURI5), false, '20');
});
});
diff --git a/src/vs/editor/contrib/gotoSymbol/referencesModel.ts b/src/vs/editor/contrib/gotoSymbol/referencesModel.ts
index d79ffa61c0c..5c4bbe4d021 100644
--- a/src/vs/editor/contrib/gotoSymbol/referencesModel.ts
+++ b/src/vs/editor/contrib/gotoSymbol/referencesModel.ts
@@ -5,7 +5,7 @@
import { localize } from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
-import { basename, exturi } from 'vs/base/common/resources';
+import { basename, extUri } from 'vs/base/common/resources';
import { IDisposable, dispose, IReference, DisposableStore } from 'vs/base/common/lifecycle';
import * as strings from 'vs/base/common/strings';
import { URI } from 'vs/base/common/uri';
@@ -151,7 +151,7 @@ export class ReferencesModel implements IDisposable {
let current: FileReferences | undefined;
for (let link of links) {
- if (!current || !exturi.isEqual(current.uri, link.uri, true)) {
+ if (!current || !extUri.isEqual(current.uri, link.uri, true)) {
// new group
current = new FileReferences(this, link.uri);
this.groups.push(current);
@@ -281,6 +281,6 @@ export class ReferencesModel implements IDisposable {
}
private static _compareReferences(a: Location, b: Location): number {
- return exturi.compare(a.uri, b.uri) || Range.compareRangesUsingStarts(a.range, b.range);
+ return extUri.compare(a.uri, b.uri) || Range.compareRangesUsingStarts(a.range, b.range);
}
}
diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts
index 073855d2890..b2fc3bd05bd 100644
--- a/src/vs/platform/files/common/fileService.ts
+++ b/src/vs/platform/files/common/fileService.ts
@@ -7,7 +7,7 @@ import { Disposable, IDisposable, toDisposable, dispose, DisposableStore } from
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED, hasFileReadStreamCapability, IFileSystemProviderWithFileReadStreamCapability, ensureFileSystemProviderError, IFileSystemProviderCapabilitiesChangeEvent } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
-import { isAbsolutePath, dirname, basename, joinPath, isEqual, isEqualOrParent } from 'vs/base/common/resources';
+import { isAbsolutePath, dirname, basename, joinPath, isEqual, ExtUri } from 'vs/base/common/resources';
import { localize } from 'vs/nls';
import { TernarySearchTree } from 'vs/base/common/map';
import { isNonEmptyArray, coalesce } from 'vs/base/common/arrays';
@@ -674,15 +674,16 @@ export class FileService extends Disposable implements IFileService {
// Check if source is equal or parent to target (requires providers to be the same)
if (sourceProvider === targetProvider) {
const isPathCaseSensitive = !!(sourceProvider.capabilities & FileSystemProviderCapabilities.PathCaseSensitive);
+ const extUri = new ExtUri(_ => !isPathCaseSensitive);
if (!isPathCaseSensitive) {
- isSameResourceWithDifferentPathCase = isEqual(source, target, true /* ignore case */);
+ isSameResourceWithDifferentPathCase = extUri.isEqual(source, target);
}
if (isSameResourceWithDifferentPathCase && mode === 'copy') {
throw new Error(localize('unableToMoveCopyError1', "Unable to copy when source '{0}' is same as target '{1}' with different path case on a case insensitive file system", this.resourceForError(source), this.resourceForError(target)));
}
- if (!isSameResourceWithDifferentPathCase && isEqualOrParent(target, source, !isPathCaseSensitive)) {
+ if (!isSameResourceWithDifferentPathCase && extUri.isEqualOrParent(target, source)) {
throw new Error(localize('unableToMoveCopyError2', "Unable to move/copy when source '{0}' is parent of target '{1}'.", this.resourceForError(source), this.resourceForError(target)));
}
}
@@ -700,7 +701,8 @@ export class FileService extends Disposable implements IFileService {
// it as it would delete the source as well. In this case we have to throw
if (sourceProvider === targetProvider) {
const isPathCaseSensitive = !!(sourceProvider.capabilities & FileSystemProviderCapabilities.PathCaseSensitive);
- if (isEqualOrParent(source, target, !isPathCaseSensitive)) {
+ const extUri = new ExtUri(_ => !isPathCaseSensitive);
+ if (extUri.isEqualOrParent(source, target)) {
throw new Error(localize('unableToMoveCopyError4', "Unable to move/copy '{0}' into '{1}' since a file would replace the folder it is contained in.", this.resourceForError(source), this.resourceForError(target)));
}
}
diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts
index 368de57eda5..7863a8c2c12 100644
--- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts
+++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts
@@ -11,7 +11,7 @@ import { tail } from 'vs/base/common/arrays';
import { timeout } from 'vs/base/common/async';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
-import { isEqual } from 'vs/base/common/resources';
+import { extUri } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import 'vs/css!./media/breadcrumbscontrol';
import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
@@ -71,7 +71,7 @@ class Item extends BreadcrumbsItem {
return false;
}
if (this.element instanceof FileElement && other.element instanceof FileElement) {
- return (isEqual(this.element.uri, other.element.uri, false) &&
+ return (extUri.isEqual(this.element.uri, other.element.uri) &&
this.options.showFileIcons === other.options.showFileIcons &&
this.options.showSymbolIcons === other.options.showSymbolIcons);
}
diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts
index 0b321ee1f68..ce447754ab1 100644
--- a/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts
+++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkEditPreview.ts
@@ -20,7 +20,7 @@ import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model';
import { ConflictDetector } from 'vs/workbench/services/bulkEdit/browser/conflicts';
import { ResourceMap } from 'vs/base/common/map';
import { localize } from 'vs/nls';
-import { exturi } from 'vs/base/common/resources';
+import { extUri } from 'vs/base/common/resources';
export class CheckedStates<T extends object> {
@@ -210,13 +210,13 @@ export class BulkFileOperations {
}
const insert = (uri: URI, map: Map<string, BulkFileOperation>) => {
- let key = exturi.getComparisonKey(uri, true);
+ let key = extUri.getComparisonKey(uri, true);
let operation = map.get(key);
// rename
if (!operation && newToOldUri.has(uri)) {
uri = newToOldUri.get(uri)!;
- key = exturi.getComparisonKey(uri, true);
+ key = extUri.getComparisonKey(uri, true);
operation = map.get(key);
}
diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts
index 457b02dc588..97ee108e43c 100644
--- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts
+++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts
@@ -43,7 +43,6 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { IAsyncDataTreeViewState } from 'vs/base/browser/ui/tree/asyncDataTree';
import { FuzzyScore } from 'vs/base/common/filters';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
-import { isEqualOrParent } from 'vs/base/common/resources';
import { values } from 'vs/base/common/map';
import { first } from 'vs/base/common/arrays';
import { withNullAsUndefined } from 'vs/base/common/types';
@@ -56,6 +55,7 @@ import { Color } from 'vs/base/common/color';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IOpenerService } from 'vs/platform/opener/common/opener';
+import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
interface IExplorerViewColors extends IColorMapping {
listDropBackground?: ColorValue | undefined;
@@ -171,6 +171,7 @@ export class ExplorerView extends ViewPane {
@IStorageService private readonly storageService: IStorageService,
@IClipboardService private clipboardService: IClipboardService,
@IFileService private readonly fileService: IFileService,
+ @IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
@IOpenerService openerService: IOpenerService,
) {
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
@@ -652,8 +653,7 @@ export class ExplorerView extends ViewPane {
}
// Expand all stats in the parent chain.
- const ignoreCase = !this.fileService.hasCapability(resource, FileSystemProviderCapabilities.PathCaseSensitive);
- let item: ExplorerItem | undefined = this.explorerService.roots.filter(i => isEqualOrParent(resource, i.resource, ignoreCase))
+ let item: ExplorerItem | undefined = this.explorerService.roots.filter(i => this.uriIdentityService.extUri.isEqualOrParent(resource, i.resource))
// Take the root that is the closest to the stat #72299
.sort((first, second) => second.resource.path.length - first.resource.path.length)[0];
@@ -663,7 +663,7 @@ export class ExplorerView extends ViewPane {
} catch (e) {
return this.selectResource(resource, reveal, retry + 1);
}
- item = first(values(item.children), i => isEqualOrParent(resource, i.resource, ignoreCase));
+ item = first(values(item.children), i => this.uriIdentityService.extUri.isEqualOrParent(resource, i.resource));
}
if (item) {
diff --git a/src/vs/workbench/contrib/markers/browser/markersModel.ts b/src/vs/workbench/contrib/markers/browser/markersModel.ts
index ce39a395416..1d93da1a803 100644
--- a/src/vs/workbench/contrib/markers/browser/markersModel.ts
+++ b/src/vs/workbench/contrib/markers/browser/markersModel.ts
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { basename, exturi } from 'vs/base/common/resources';
+import { basename, extUri } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { Range, IRange } from 'vs/editor/common/core/range';
import { IMarker, MarkerSeverity, IRelatedInformation, IMarkerData } from 'vs/platform/markers/common/markers';
@@ -15,7 +15,7 @@ import { withUndefinedAsNull } from 'vs/base/common/types';
export function compareMarkersByUri(a: IMarker, b: IMarker) {
- return exturi.compare(a.resource, b.resource);
+ return extUri.compare(a.resource, b.resource);
}
function compareResourceMarkers(a: ResourceMarkers, b: ResourceMarkers): number {
@@ -148,14 +148,14 @@ export class MarkersModel {
}
getResourceMarkers(resource: URI): ResourceMarkers | null {
- return withUndefinedAsNull(this.resourcesByUri.get(exturi.getComparisonKey(resource, true)));
+ return withUndefinedAsNull(this.resourcesByUri.get(extUri.getComparisonKey(resource, true)));
}
setResourceMarkers(resourcesMarkers: [URI, IMarker[]][]): void {
const change: MarkerChangesEvent = { added: new Set(), removed: new Set(), updated: new Set() };
for (const [resource, rawMarkers] of resourcesMarkers) {
- const key = exturi.getComparisonKey(resource, true);
+ const key = extUri.getComparisonKey(resource, true);
let resourceMarkers = this.resourcesByUri.get(key);
if (isNonEmptyArray(rawMarkers)) {
diff --git a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts
index af9dd35731e..82c70a6acd4 100644
--- a/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts
+++ b/src/vs/workbench/services/dialogs/browser/simpleFileDialog.ts
@@ -403,7 +403,7 @@ export class SimpleFileDialog {
this.filePickBox.validationMessage = undefined;
const filePickBoxUri = this.filePickBoxValue();
let updated: UpdateResult = UpdateResult.NotUpdated;
- if (!resources.isEqual(this.currentFolder, filePickBoxUri, true)) {
+ if (!resources.extUriIgnorePathCase.isEqual(this.currentFolder, filePickBoxUri)) {
updated = await this.tryUpdateItems(value, filePickBoxUri);
}
if (updated === UpdateResult.NotUpdated) {
@@ -541,7 +541,7 @@ export class SimpleFileDialog {
value = this.pathFromUri(valueUri);
await this.updateItems(valueUri, true);
return UpdateResult.Updated;
- } else if (!resources.isEqual(this.currentFolder, valueUri, true) && (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true)))) {
+ } else if (!resources.extUriIgnorePathCase.isEqual(this.currentFolder, valueUri) && (this.endsWithSlash(value) || (!resources.extUriIgnorePathCase.isEqual(this.currentFolder, resources.dirname(valueUri)) && resources.extUriIgnorePathCase.isEqualOrParent(this.currentFolder, resources.dirname(valueUri))))) {
let stat: IFileStat | undefined;
try {
stat = await this.fileService.resolve(valueUri);
@@ -560,7 +560,7 @@ export class SimpleFileDialog {
return UpdateResult.InvalidPath;
} else {
const inputUriDirname = resources.dirname(valueUri);
- if (!resources.isEqual(resources.removeTrailingPathSeparator(this.currentFolder), inputUriDirname, true)) {
+ if (!resources.extUriIgnorePathCase.isEqual(resources.removeTrailingPathSeparator(this.currentFolder), inputUriDirname)) {
let statWithoutTrailing: IFileStat | undefined;
try {
statWithoutTrailing = await this.fileService.resolve(inputUriDirname);
@@ -865,7 +865,7 @@ export class SimpleFileDialog {
private createBackItem(currFolder: URI): FileQuickPickItem | null {
const fileRepresentationCurr = this.currentFolder.with({ scheme: Schemas.file });
const fileRepresentationParent = resources.dirname(fileRepresentationCurr);
- if (!resources.isEqual(fileRepresentationCurr, fileRepresentationParent, true)) {
+ if (!resources.extUriIgnorePathCase.isEqual(fileRepresentationCurr, fileRepresentationParent)) {
const parentFolder = resources.dirname(currFolder);
return { label: '..', uri: resources.addTrailingPathSeparator(parentFolder, this.separator), isFolder: true };
}
diff --git a/src/vs/workbench/services/log/common/keyValueLogProvider.ts b/src/vs/workbench/services/log/common/keyValueLogProvider.ts
index da0fdb3f167..60bc79cf3c0 100644
--- a/src/vs/workbench/services/log/common/keyValueLogProvider.ts
+++ b/src/vs/workbench/services/log/common/keyValueLogProvider.ts
@@ -8,7 +8,7 @@ import { IFileSystemProviderWithFileReadWriteCapability, FileSystemProviderCapab
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { Event, Emitter } from 'vs/base/common/event';
import { VSBuffer } from 'vs/base/common/buffer';
-import { isEqualOrParent, joinPath, relativePath } from 'vs/base/common/resources';
+import { joinPath, extUri } from 'vs/base/common/resources';
import { values } from 'vs/base/common/map';
import { localize } from 'vs/nls';
@@ -65,8 +65,8 @@ export abstract class KeyValueLogProvider extends Disposable implements IFileSys
const files: Map<string, [string, FileType]> = new Map<string, [string, FileType]>();
for (const key of keys) {
const keyResource = this.toResource(key);
- if (isEqualOrParent(keyResource, resource, false)) {
- const path = relativePath(resource, keyResource, false);
+ if (extUri.isEqualOrParent(keyResource, resource)) {
+ const path = extUri.relativePath(resource, keyResource);
if (path) {
const keySegments = path.split('/');
files.set(keySegments[0], [keySegments[0], keySegments.length === 1 ? FileType.File : FileType.Directory]);
diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts
index be50b353deb..4b8997b29e9 100644
--- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts
+++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts
@@ -23,7 +23,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IWorkingCopyFileService, WorkingCopyFileEvent } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
import { ITextSnapshot, ITextBufferFactory } from 'vs/editor/common/model';
-import { joinPath, isEqualOrParent, isEqual } from 'vs/base/common/resources';
+import { joinPath, isEqualOrParent, isEqual, extUri } from 'vs/base/common/resources';
import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
@@ -142,7 +142,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE
for (const model of this.models) {
const resource = model.resource;
- if (isEqualOrParent(resource, e.target, false /* do not ignorecase, see https://github.com/Microsoft/vscode/issues/56384 */)) {
+ if (extUri.isEqualOrParent(resource, e.target/* do not ignorecase, see https://github.com/Microsoft/vscode/issues/56384 */)) {
targetModels.push(model);
}