提交 62c5e45b 编写于 作者: M Martin Aeschlimann

Use `resources` instead of `paths` for dirname, basename, joinPath, normalizePath, isAbsolutePath

上级 60ef4f5d
......@@ -19,9 +19,12 @@ export const sep = '/';
export const nativeSep = isWindows ? '\\' : '/';
/**
* @param path the path to get the dirname from
* @param separator the separator to use
* @returns the directory name of a path.
*
*/
export function dirname(path: string): string {
export function dirname(path: string, separator = nativeSep): string {
const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\');
if (idx === 0) {
return '.';
......@@ -31,8 +34,8 @@ export function dirname(path: string): string {
return dirname(path.substring(0, path.length - 1));
} else {
let res = path.substring(0, ~idx);
if (isWindows && res[res.length - 1] === ':') {
res += nativeSep; // make sure drive letters end with backslash
if (isWindows && res.length === 2 && res[res.length - 1] === ':') {
res += separator; // make sure drive letters end with backslash
}
return res;
}
......
......@@ -22,13 +22,13 @@ export function hasToIgnoreCase(resource: URI): boolean {
}
export function basenameOrAuthority(resource: URI): string {
return basename_urlpath(resource.path) || resource.authority;
return basename(resource) || resource.authority;
}
export function isEqualOrParent(resource: URI, candidate: URI, ignoreCase?: boolean): boolean {
if (resource.scheme === candidate.scheme && resource.authority === candidate.authority) {
if (resource.scheme === 'file') {
return paths.isEqualOrParent(resource.fsPath, candidate.fsPath, ignoreCase);
if (resource.scheme === Schemas.file) {
return paths.isEqualOrParent(resource.path, candidate.path, ignoreCase);
}
return paths.isEqualOrParent(resource.path, candidate.path, ignoreCase, '/');
......@@ -55,47 +55,59 @@ export function isEqual(first: URI, second: URI, ignoreCase?: boolean): boolean
}
export function basename(resource: URI): string {
if (resource.scheme === 'file') {
return paths.basename(resource.fsPath);
}
return basename_urlpath(resource.path);
return paths.basename(resource.path);
}
/**
* Return a URI representing the directory of a URI path.
*
* @param resource The input URI.
* @returns The URI representing the directory of the input URI.
*/
export function dirname(resource: URI): URI {
if (resource.scheme === 'file') {
return URI.file(paths.dirname(resource.fsPath));
}
let dirname = dirname_urlpath(resource.path);
let dirname = paths.dirname(resource.path, '/');
if (resource.authority && dirname.length && dirname.charCodeAt(0) !== CharCode.Slash) {
return null; // If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character
return null; // If a URI contains an authority component, then the path component must either be empty or begin with a CharCode.Slash ("/") character
}
return resource.with({
path: dirname
});
}
/**
* Join a URI path with a path fragment and normalizes the resulting path.
*
* @param resource The input URI.
* @param pathFragment The path fragment to add to the URI path.
* @returns The resulting URI.
*/
export function joinPath(resource: URI, pathFragment: string): URI {
if (resource.scheme === 'file') {
return URI.file(paths.join(resource.path || '/', pathFragment));
}
const joinedPath = paths.join(resource.path || '/', pathFragment);
return resource.with({
path: joinedPath
});
}
let path = resource.path || '';
let last = path.charCodeAt(path.length - 1);
let next = pathFragment.charCodeAt(0);
if (last !== CharCode.Slash) {
if (next !== CharCode.Slash) {
path += '/';
}
} else {
if (next === CharCode.Slash) {
pathFragment = pathFragment.substr(1);
}
}
/**
* Normalizes the path part of a URI: Resolves `.` and `..` elements with directory names.
*
* @param resource The URI to normalize the path.
* @returns The URI with the normalized path.
*/
export function normalizePath(resource: URI): URI {
const normalizedPath = paths.normalize(resource.path, false);
return resource.with({
path: path + pathFragment
path: normalizedPath
});
}
/**
* Returns true if the URI path is absolute.
*/
export function isAbsolutePath(resource: URI): boolean {
return paths.isAbsolute(resource.path);
}
export function distinctParents<T>(items: T[], resourceAccessor: (item: T) => URI): T[] {
const distinctParents: T[] = [];
for (let i = 0; i < items.length; i++) {
......@@ -115,27 +127,3 @@ export function distinctParents<T>(items: T[], resourceAccessor: (item: T) => UR
return distinctParents;
}
function dirname_urlpath(path: string): string {
const idx = ~path.lastIndexOf('/');
if (idx === 0) {
return '';
} else if (~idx === 0) {
return path[0];
} else if (~idx === path.length - 1) {
return dirname_urlpath(path.substring(0, path.length - 1));
} else {
return path.substring(0, ~idx);
}
}
function basename_urlpath(path: string): string {
const idx = ~path.lastIndexOf('/');
if (idx === 0) {
return path;
} else if (~idx === path.length - 1) {
return basename_urlpath(path.substring(0, path.length - 1));
} else {
return path.substr(~idx + 1);
}
}
......@@ -5,7 +5,7 @@
'use strict';
import * as assert from 'assert';
import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase } from 'vs/base/common/resources';
import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath } from 'vs/base/common/resources';
import URI from 'vs/base/common/uri';
import { isWindows } from 'vs/base/common/platform';
......@@ -52,7 +52,6 @@ suite('Resources', () => {
assert.equal(dirname(URI.file('/some/file/test.txt')).toString(), 'file:///some/file');
assert.equal(dirname(URI.file('/some/file/')).toString(), 'file:///some');
assert.equal(dirname(URI.file('/some/file')).toString(), 'file:///some');
assert.equal(dirname(URI.file('/some/file')).toString(), 'file:///some');
}
assert.equal(dirname(URI.parse('foo://a/some/file/test.txt')).toString(), 'foo://a/some/file');
assert.equal(dirname(URI.parse('foo://a/some/file/')).toString(), 'foo://a/some');
......@@ -65,22 +64,21 @@ suite('Resources', () => {
test('basename', () => {
if (isWindows) {
assert.equal(basename(URI.file('c:\\some\\file\\test.txt')).toString(), 'test.txt');
assert.equal(basename(URI.file('c:\\some\\file')).toString(), 'file');
assert.equal(basename(URI.file('c:\\some\\file\\')).toString(), 'file');
assert.equal(basename(URI.file('c:\\some\\file\\test.txt')), 'test.txt');
assert.equal(basename(URI.file('c:\\some\\file')), 'file');
assert.equal(basename(URI.file('c:\\some\\file\\')), 'file');
} else {
assert.equal(basename(URI.file('/some/file/test.txt')).toString(), 'test.txt');
assert.equal(basename(URI.file('/some/file/')).toString(), 'file');
assert.equal(basename(URI.file('/some/file')).toString(), 'file');
assert.equal(basename(URI.file('/some')).toString(), 'some');
assert.equal(basename(URI.file('/some/file/test.txt')), 'test.txt');
assert.equal(basename(URI.file('/some/file/')), 'file');
assert.equal(basename(URI.file('/some/file')), 'file');
assert.equal(basename(URI.file('/some')), 'some');
}
assert.equal(basename(URI.parse('foo://a/some/file/test.txt')).toString(), 'test.txt');
assert.equal(basename(URI.parse('foo://a/some/file/')).toString(), 'file');
assert.equal(basename(URI.parse('foo://a/some/file')).toString(), 'file');
assert.equal(basename(URI.parse('foo://a/some')).toString(), 'some');
// does not explode (https://github.com/Microsoft/vscode/issues/41987)
dirname(URI.from({ scheme: 'file', authority: '/users/someone/portal.h' }));
assert.equal(basename(URI.parse('foo://a/some/file/test.txt')), 'test.txt');
assert.equal(basename(URI.parse('foo://a/some/file/')), 'file');
assert.equal(basename(URI.parse('foo://a/some/file')), 'file');
assert.equal(basename(URI.parse('foo://a/some')), 'some');
assert.equal(basename(URI.parse('foo://a/')), '');
assert.equal(basename(URI.parse('foo://a')), '');
});
test('joinPath', () => {
......@@ -89,22 +87,78 @@ suite('Resources', () => {
assert.equal(joinPath(URI.file('c:\\foo\\bar\\'), 'file.js').toString(), 'file:///c%3A/foo/bar/file.js');
assert.equal(joinPath(URI.file('c:\\foo\\bar\\'), '/file.js').toString(), 'file:///c%3A/foo/bar/file.js');
assert.equal(joinPath(URI.file('c:\\'), '/file.js').toString(), 'file:///c%3A/file.js');
assert.equal(joinPath(URI.file('c:\\'), 'bar/file.js').toString(), 'file:///c%3A/bar/file.js');
assert.equal(joinPath(URI.file('c:\\foo'), './file.js').toString(), 'file:///c%3A/foo/file.js');
assert.equal(joinPath(URI.file('c:\\foo'), '/./file.js').toString(), 'file:///c%3A/foo/file.js');
assert.equal(joinPath(URI.file('c:\\foo'), '../file.js').toString(), 'file:///c%3A/file.js');
assert.equal(joinPath(URI.file('c:\\foo\\.'), '../file.js').toString(), 'file:///c%3A/file.js');
} else {
assert.equal(joinPath(URI.file('/foo/bar'), '/file.js').toString(), 'file:///foo/bar/file.js');
assert.equal(joinPath(URI.file('/foo/bar'), 'file.js').toString(), 'file:///foo/bar/file.js');
assert.equal(joinPath(URI.file('/foo/bar/'), '/file.js').toString(), 'file:///foo/bar/file.js');
assert.equal(joinPath(URI.file('/'), '/file.js').toString(), 'file:///file.js');
assert.equal(joinPath(URI.file('/foo/bar'), './file.js').toString(), 'file:///foo/bar/file.js');
assert.equal(joinPath(URI.file('/foo/bar'), '/./file.js').toString(), 'file:///foo/bar/file.js');
assert.equal(joinPath(URI.file('/foo/bar'), '../file.js').toString(), 'file:///foo/file.js');
}
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), 'file.js').toString(), 'foo://a/foo/bar/file.js');
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
assert.equal(joinPath(URI.parse('foo://a/'), '/file.js').toString(), 'foo://a/file.js');
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), './file.js').toString(), 'foo://a/foo/bar/file.js');
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '/./file.js').toString(), 'foo://a/foo/bar/file.js');
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '../file.js').toString(), 'foo://a/foo/file.js');
assert.equal(
joinPath(URI.from({ scheme: 'myScheme', authority: 'authority', path: '/path', query: 'query', fragment: 'fragment' }), '/file.js').toString(),
'myScheme://authority/path/file.js?query#fragment');
});
test('normalizePath', () => {
if (isWindows) {
assert.equal(normalizePath(URI.file('c:\\foo\\.\\bar')).toString(), 'file:///c%3A/foo/bar');
assert.equal(normalizePath(URI.file('c:\\foo\\.')).toString(), 'file:///c%3A/foo');
assert.equal(normalizePath(URI.file('c:\\foo\\.\\')).toString(), 'file:///c%3A/foo/');
assert.equal(normalizePath(URI.file('c:\\foo\\..')).toString(), 'file:///c%3A/');
assert.equal(normalizePath(URI.file('c:\\foo\\..\\bar')).toString(), 'file:///c%3A/bar');
assert.equal(normalizePath(URI.file('c:\\foo\\..\\..\\bar')).toString(), 'file:///c%3A/bar');
assert.equal(normalizePath(URI.file('c:\\foo\\foo\\..\\..\\bar')).toString(), 'file:///c%3A/bar');
assert.equal(normalizePath(URI.file('c:\\foo\\foo\\.\\..\\..\\bar')).toString(), 'file:///c%3A/bar');
assert.equal(normalizePath(URI.file('c:\\foo\\foo\\.\\..\\some\\..\\bar')).toString(), 'file:///c%3A/foo/bar');
} else {
assert.equal(normalizePath(URI.file('/foo/./bar')).toString(), 'file:///foo/bar');
assert.equal(normalizePath(URI.file('/foo/.')).toString(), 'file:///foo');
assert.equal(normalizePath(URI.file('/foo/./')).toString(), 'file:///foo/');
assert.equal(normalizePath(URI.file('/foo/..')).toString(), 'file:///');
assert.equal(normalizePath(URI.file('/foo/../bar')).toString(), 'file:///bar');
assert.equal(normalizePath(URI.file('/foo/../../bar')).toString(), 'file:///bar');
assert.equal(normalizePath(URI.file('/foo/foo/../../bar')).toString(), 'file:///bar');
assert.equal(normalizePath(URI.file('/foo/foo/./../../bar')).toString(), 'file:///bar');
assert.equal(normalizePath(URI.file('/foo/foo/./../some/../bar')).toString(), 'file:///foo/bar');
}
assert.equal(normalizePath(URI.parse('foo://a/foo/./bar')).toString(), 'foo://a/foo/bar');
assert.equal(normalizePath(URI.parse('foo://a/foo/.')).toString(), 'foo://a/foo');
assert.equal(normalizePath(URI.parse('foo://a/foo/./')).toString(), 'foo://a/foo/');
assert.equal(normalizePath(URI.parse('foo://a/foo/..')).toString(), 'foo://a/');
assert.equal(normalizePath(URI.parse('foo://a/foo/../bar')).toString(), 'foo://a/bar');
assert.equal(normalizePath(URI.parse('foo://a/foo/../../bar')).toString(), 'foo://a/bar');
assert.equal(normalizePath(URI.parse('foo://a/foo/foo/../../bar')).toString(), 'foo://a/bar');
assert.equal(normalizePath(URI.parse('foo://a/foo/foo/./../../bar')).toString(), 'foo://a/bar');
assert.equal(normalizePath(URI.parse('foo://a/foo/foo/./../some/../bar')).toString(), 'foo://a/foo/bar');
});
test('isAbsolute', () => {
if (isWindows) {
assert.equal(isAbsolutePath(URI.file('c:\\foo\\')), true);
assert.equal(isAbsolutePath(URI.file('bar')), true); // URI normalizes all file URIs to be absolute
} else {
assert.equal(isAbsolutePath(URI.file('/foo/bar')), true);
assert.equal(isAbsolutePath(URI.file('bar')), true); // URI normalizes all file URIs to be absolute
}
assert.equal(isAbsolutePath(URI.parse('foo:foo')), false);
assert.equal(isAbsolutePath(URI.parse('foo://a/foo/.')), true);
});
test('isEqual', () => {
let fileURI = URI.file('/foo/bar');
let fileURI2 = URI.file('/foo/Bar');
......
......@@ -6,11 +6,11 @@
import URI from 'vs/base/common/uri';
import * as dom from 'vs/base/browser/dom';
import * as resources from 'vs/base/common/resources';
import { parse } from 'vs/base/common/marshalling';
import { Schemas } from 'vs/base/common/network';
import { TPromise } from 'vs/base/common/winjs.base';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { normalize } from 'vs/base/common/paths';
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
......@@ -79,7 +79,7 @@ export class OpenerService implements IOpenerService {
return TPromise.as(undefined);
} else if (resource.scheme === Schemas.file) {
resource = resource.with({ path: normalize(resource.path) }); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954)
resource = resources.normalizePath(resource); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954)
}
promise = this._editorService.openCodeEditor({ resource, options: { selection, } }, this._editorService.getFocusedCodeEditor(), options && options.openToSide);
}
......
......@@ -234,7 +234,7 @@ export class WorkspaceFolder implements IWorkspaceFolder {
}
toResource(relativePath: string): URI {
return this.uri.with({ path: paths.join(this.uri.path, relativePath) });
return resources.joinPath(this.uri, relativePath);
}
toJSON(): IWorkspaceFolderData {
......@@ -278,7 +278,7 @@ function toUri(path: string, relativeTo: URI): URI {
return URI.file(path);
}
if (relativeTo) {
return relativeTo.with({ path: paths.join(relativeTo.path, path) });
return resources.joinPath(relativeTo, path);
}
}
return null;
......
......@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { posix, relative, join } from 'path';
import { relative, join } from 'path';
import { delta as arrayDelta } from 'vs/base/common/arrays';
import { Emitter, Event } from 'vs/base/common/event';
import { TernarySearchTree } from 'vs/base/common/map';
import { normalize } from 'vs/base/common/paths';
import { isLinux } from 'vs/base/common/platform';
import { basenameOrAuthority, isEqual } from 'vs/base/common/resources';
import { basenameOrAuthority, isEqual, dirname } from 'vs/base/common/resources';
import { compare } from 'vs/base/common/strings';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
......@@ -124,7 +124,7 @@ class ExtHostWorkspaceImpl extends Workspace {
getWorkspaceFolder(uri: URI, resolveParent?: boolean): vscode.WorkspaceFolder {
if (resolveParent && this._structure.get(uri.toString())) {
// `uri` is a workspace folder so we check for its parent
uri = uri.with({ path: posix.dirname(uri.path) });
uri = dirname(uri);
}
return this._structure.findSubstr(uri.toString());
}
......
......@@ -12,8 +12,7 @@ import { size } from 'vs/base/common/collections';
import { onUnexpectedError } from 'vs/base/common/errors';
import { debounceEvent, Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import * as paths from 'vs/base/common/paths';
import { isEqual } from 'vs/base/common/resources';
import { isEqual, dirname } from 'vs/base/common/resources';
import URI from 'vs/base/common/uri';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IPosition } from 'vs/editor/common/core/position';
......@@ -117,7 +116,7 @@ export class EditorBreadcrumbsModel {
break;
}
info.path.unshift(new FileElement(uri, info.path.length === 0 ? FileKind.FILE : FileKind.FOLDER));
uri = uri.with({ path: paths.dirname(uri.path) });
uri = dirname(uri);
}
if (info.folder && workspaceService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
......
......@@ -19,7 +19,6 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import * as paths from 'vs/base/common/paths';
import { isMacintosh, isLinux, language } from 'vs/base/common/platform';
import { IQuickOpenService, IFilePickOpenEntry, ISeparator, IPickOpenAction, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen';
import * as browser from 'vs/base/browser/browser';
......@@ -723,7 +722,7 @@ export abstract class BaseOpenRecentAction extends Action {
if (isSingleFolderWorkspaceIdentifier(workspace)) {
resource = workspace;
label = getWorkspaceLabel(workspace, environmentService, uriDisplayService);
description = uriDisplayService.getLabel(resource.with({ path: paths.dirname(resource.path) }));
description = uriDisplayService.getLabel(dirname(resource));
} else if (isWorkspaceIdentifier(workspace)) {
resource = URI.file(workspace.configPath);
label = getWorkspaceLabel(workspace, environmentService, uriDisplayService);
......
......@@ -10,7 +10,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import * as strings from 'vs/base/common/strings';
import * as objects from 'vs/base/common/objects';
import uri from 'vs/base/common/uri';
import * as paths from 'vs/base/common/paths';
import * as resources from 'vs/base/common/resources';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { ITextModel } from 'vs/editor/common/model';
import { IEditor } from 'vs/workbench/common/editor';
......@@ -390,7 +390,7 @@ class Launch implements ILaunch {
}
public get uri(): uri {
return this.workspace.uri.with({ path: paths.join(this.workspace.uri.path, '/.vscode/launch.json') });
return resources.joinPath(this.workspace.uri, '/.vscode/launch.json');
}
public get name(): string {
......
......@@ -38,7 +38,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { groupBy } from 'vs/base/common/collections';
import { Schemas } from 'vs/base/common/network';
import { posix } from 'path';
import * as resources from 'vs/base/common/resources';
interface IExtensionStateProvider<T> {
(extension: Extension): T;
......@@ -131,7 +131,7 @@ class Extension implements IExtension {
private get localIconUrl(): string {
if (this.local && this.local.manifest.icon) {
return this.local.location.with({ path: posix.join(this.local.location.path, this.local.manifest.icon) }).toString();
return resources.joinPath(this.local.location, this.local.manifest.icon).toString();
}
return null;
}
......
......@@ -7,7 +7,7 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import URI from 'vs/base/common/uri';
import * as paths from 'vs/base/common/paths';
import * as resources from 'vs/base/common/resources';
import { IEditorViewState } from 'vs/editor/common/editorCommon';
import { toResource, SideBySideEditorInput, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor';
import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
......@@ -149,7 +149,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
// 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 && paths.isEqualOrParent(resource.fsPath, movedTo.fsPath, !isLinux /* ignorecase */) && resource.fsPath.indexOf(movedTo.fsPath) === 0) {
if (movedTo && resources.isEqualOrParent(resource, movedTo, resources.hasToIgnoreCase(resource)) && resource.path.indexOf(movedTo.path) === 0) {
return;
}
......@@ -157,7 +157,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
if (arg1 instanceof FileChangesEvent) {
matches = arg1.contains(resource, FileChangeType.DELETED);
} else {
matches = paths.isEqualOrParent(resource.fsPath, arg1.fsPath, !isLinux /* ignorecase */);
matches = resources.isEqualOrParent(resource, arg1, resources.hasToIgnoreCase(resource));
}
if (!matches) {
......@@ -224,13 +224,13 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
const resource = input.getResource();
// Update Editor if file (or any parent of the input) got renamed or moved
if (paths.isEqualOrParent(resource.fsPath, oldResource.fsPath, !isLinux /* ignorecase */)) {
if (resources.isEqualOrParent(resource, oldResource, resources.hasToIgnoreCase(resource))) {
let reopenFileResource: URI;
if (oldResource.toString() === resource.toString()) {
reopenFileResource = newResource; // file got moved
} else {
const index = this.getIndexOfPath(resource.path, oldResource.path);
reopenFileResource = newResource.with({ path: paths.join(newResource.path, resource.path.substr(index + oldResource.path.length + 1)) }); // parent folder got moved
reopenFileResource = resources.joinPath(newResource, resource.path.substr(index + oldResource.path.length + 1)); // parent folder got moved
}
// Reopen
......
......@@ -157,7 +157,7 @@ export class ExplorerItem {
// 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 resources.isEqualOrParent(r, stat.resource, !isLinux /* ignorecase */);
return resources.isEqualOrParent(r, stat.resource, resources.hasToIgnoreCase(r));
}));
// Recurse into children
......@@ -311,7 +311,7 @@ export class ExplorerItem {
}
private updateResource(recursive: boolean): void {
this.resource = this.parent.resource.with({ path: paths.join(this.parent.resource.path, this.name) });
this.resource = resources.joinPath(this.parent.resource, this.name);
if (recursive) {
if (this.isDirectory && this.children) {
......
......@@ -14,7 +14,6 @@ import { sequence, ITask, always } from 'vs/base/common/async';
import * as paths from 'vs/base/common/paths';
import * as resources from 'vs/base/common/resources';
import URI from 'vs/base/common/uri';
import { posix } from 'path';
import * as errors from 'vs/base/common/errors';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import * as strings from 'vs/base/common/strings';
......@@ -300,7 +299,7 @@ class RenameFileAction extends BaseRenameAction {
public runAction(newName: string): TPromise<any> {
const parentResource = this.element.parent.resource;
const targetResource = parentResource.with({ path: paths.join(parentResource.path, newName) });
const targetResource = resources.joinPath(parentResource, newName);
return this.textFileService.move(this.element.resource, targetResource);
}
......@@ -496,7 +495,7 @@ class CreateFileAction extends BaseCreateAction {
public runAction(fileName: string): TPromise<any> {
const resource = this.element.parent.resource;
return this.fileService.createFile(resource.with({ path: paths.join(resource.path, fileName) })).then(stat => {
return this.fileService.createFile(resources.joinPath(resource, fileName)).then(stat => {
return this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } });
}, (error) => {
this.onErrorWithRetry(error, () => this.runAction(fileName));
......@@ -523,7 +522,7 @@ class CreateFolderAction extends BaseCreateAction {
public runAction(fileName: string): TPromise<any> {
const resource = this.element.parent.resource;
return this.fileService.createFolder(resource.with({ path: paths.join(resource.path, fileName) })).then(null, (error) => {
return this.fileService.createFolder(resources.joinPath(resource, fileName)).then(null, (error) => {
this.onErrorWithRetry(error, () => this.runAction(fileName));
});
}
......@@ -784,9 +783,9 @@ export class AddFilesAction extends BaseFileAction {
this._updateEnablement();
}
public run(resources: URI[]): TPromise<any> {
public run(resourcesToAdd: URI[]): TPromise<any> {
const addPromise = TPromise.as(null).then(() => {
if (resources && resources.length > 0) {
if (resourcesToAdd && resourcesToAdd.length > 0) {
// Find parent to add to
let targetElement: ExplorerItem;
......@@ -811,8 +810,8 @@ export class AddFilesAction extends BaseFileAction {
});
let overwritePromise: TPromise<IConfirmationResult> = TPromise.as({ confirmed: true });
if (resources.some(resource => {
return targetNames.has(isLinux ? paths.basename(resource.fsPath) : paths.basename(resource.fsPath).toLowerCase());
if (resourcesToAdd.some(resource => {
return targetNames.has(!resources.hasToIgnoreCase(resource) ? resources.basename(resource) : resources.basename(resource).toLowerCase());
})) {
const confirm: IConfirmation = {
message: nls.localize('confirmOverwrite', "A file or folder with the same name already exists in the destination folder. Do you want to replace it?"),
......@@ -831,10 +830,10 @@ export class AddFilesAction extends BaseFileAction {
// Run add in sequence
const addPromisesFactory: ITask<TPromise<void>>[] = [];
resources.forEach(resource => {
resourcesToAdd.forEach(resource => {
addPromisesFactory.push(() => {
const sourceFile = resource;
const targetFile = targetElement.resource.with({ path: paths.join(targetElement.resource.path, paths.basename(sourceFile.path)) });
const targetFile = resources.joinPath(targetElement.resource, resources.basename(sourceFile));
// if the target exists and is dirty, make sure to revert it. otherwise the dirty contents
// of the target file would replace the contents of the added file. since we already
......@@ -845,11 +844,11 @@ export class AddFilesAction extends BaseFileAction {
}
return revertPromise.then(() => {
const target = targetElement.resource.with({ path: posix.join(targetElement.resource.path, posix.basename(sourceFile.path)) });
const target = resources.joinPath(targetElement.resource, resources.basename(sourceFile));
return this.fileService.copyFile(sourceFile, target, true).then(stat => {
// if we only add one file, just open it directly
if (resources.length === 1) {
if (resourcesToAdd.length === 1) {
this.editorService.openEditor({ resource: stat.resource, options: { pinned: true } });
}
}, error => this.onError(error));
......@@ -1020,14 +1019,14 @@ export class DuplicateFileAction extends BaseFileAction {
function findValidPasteFileTarget(targetFolder: ExplorerItem, fileToPaste: { resource: URI, isDirectory?: boolean }): URI {
let name = resources.basenameOrAuthority(fileToPaste.resource);
let candidate = targetFolder.resource.with({ path: paths.join(targetFolder.resource.path, name) });
let candidate = resources.joinPath(targetFolder.resource, name);
while (true) {
if (!targetFolder.root.find(candidate)) {
break;
}
name = incrementFileName(name, fileToPaste.isDirectory);
candidate = targetFolder.resource.with({ path: paths.join(targetFolder.resource.path, name) });
candidate = resources.joinPath(targetFolder.resource, name);
}
return candidate;
......@@ -1545,7 +1544,7 @@ export class CompareWithClipboardAction extends Action {
this.registrationDisposal = this.textModelService.registerTextModelContentProvider(CompareWithClipboardAction.SCHEME, provider);
}
const name = paths.basename(resource.fsPath);
const name = resources.basename(resource);
const editorLabel = nls.localize('clipboardComparisonLabel', "Clipboard ↔ {0}", name);
const cleanUp = () => {
......
......@@ -279,7 +279,7 @@ export class FileRenderer implements IRenderer {
const parent = stat.name ? resources.dirname(stat.resource) : stat.resource;
const value = stat.name || '';
label.setFile(parent.with({ path: paths.join(parent.path, value || ' ') }), labelOptions); // Use icon for ' ' if name is empty.
label.setFile(resources.joinPath(parent, value || ' '), labelOptions); // Use icon for ' ' if name is empty.
// Input field for name
const inputBox = new InputBox(label.element, this.contextViewService, {
......@@ -291,7 +291,7 @@ export class FileRenderer implements IRenderer {
const styler = attachInputBoxStyler(inputBox, this.themeService);
inputBox.onDidChange(value => {
label.setFile(parent.with({ path: paths.join(parent.path, value || ' ') }), labelOptions); // update label icon while typing!
label.setFile(resources.joinPath(parent, value || ' '), labelOptions); // update label icon while typing!
});
const lastDot = value.lastIndexOf('.');
......@@ -1058,7 +1058,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop {
}
// Otherwise move
const targetResource = target.resource.with({ path: paths.join(target.resource.path, source.name) });
const targetResource = resources.joinPath(target.resource, source.name);
return this.textFileService.move(source.resource, targetResource).then(null, error => {
......
......@@ -9,6 +9,7 @@ import { ILink } from 'vs/editor/common/modes';
import { TPromise } from 'vs/base/common/winjs.base';
import URI from 'vs/base/common/uri';
import * as paths from 'vs/base/common/paths';
import * as resources from 'vs/base/common/resources';
import * as strings from 'vs/base/common/strings';
import * as arrays from 'vs/base/common/arrays';
import { Range } from 'vs/editor/common/core/range';
......@@ -70,7 +71,7 @@ export class OutputLinkComputer {
const resourceCreator: IResourceCreator = {
toResource: (folderRelativePath: string): URI => {
if (typeof folderRelativePath === 'string') {
return folderUri.with({ path: paths.join(folderUri.path, folderRelativePath) });
return resources.joinPath(folderUri, folderRelativePath);
}
return null;
......
......@@ -11,6 +11,7 @@ import * as collections from 'vs/base/common/collections';
import * as strings from 'vs/base/common/strings';
import * as glob from 'vs/base/common/glob';
import * as paths from 'vs/base/common/paths';
import * as resources from 'vs/base/common/resources';
import uri from 'vs/base/common/uri';
import { untildify } from 'vs/base/common/labels';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
......@@ -274,18 +275,18 @@ export class QueryBuilder {
if (this.workspaceContextService.getWorkbenchState() === WorkbenchState.FOLDER) { // TODO: @Sandy Try checking workspace folders length instead.
const workspaceUri = this.workspaceContextService.getWorkspace().folders[0].uri;
return [workspaceUri.with({ path: paths.normalize(paths.join(workspaceUri.path, searchPath)) })];
return [resources.joinPath(workspaceUri, searchPath)];
} else if (searchPath === './') {
return []; // ./ or ./**/foo makes sense for single-folder but not multi-folder workspaces
} else {
const relativeSearchPathMatch = searchPath.match(/\.[\/\\]([^\/\\]+)([\/\\].+)?/);
if (relativeSearchPathMatch) {
const searchPathRoot = relativeSearchPathMatch[1];
const matchingRoots = this.workspaceContextService.getWorkspace().folders.filter(folder => paths.basename(folder.uri.fsPath) === searchPathRoot || folder.name === searchPathRoot);
const matchingRoots = this.workspaceContextService.getWorkspace().folders.filter(folder => resources.basename(folder.uri) === searchPathRoot || folder.name === searchPathRoot);
if (matchingRoots.length) {
return matchingRoots.map(root => {
return relativeSearchPathMatch[2] ?
root.uri.with({ path: paths.normalize(paths.join(root.uri.path, relativeSearchPathMatch[2])) }) :
resources.joinPath(root.uri, relativeSearchPathMatch[2]) :
root.uri;
});
} else {
......
......@@ -125,7 +125,7 @@ export class WorkspaceConfiguration extends Disposable {
}
function isFolderConfigurationFile(resource: URI): boolean {
const name = paths.basename(resource.path);
const name = resources.basename(resource);
return [`${FOLDER_SETTINGS_NAME}.json`, `${TASKS_CONFIGURATION_KEY}.json`, `${LAUNCH_CONFIGURATION_KEY}.json`].some(p => p === name);// only workspace config files
}
......@@ -193,7 +193,7 @@ export abstract class AbstractFolderConfiguration extends Disposable implements
private parseContents(contents: { resource: URI, value: string }[]): void {
for (const content of contents) {
const name = paths.basename(content.resource.path);
const name = resources.basename(content.resource);
if (name === `${FOLDER_SETTINGS_NAME}.json`) {
this._folderSettingsModelParser.parse(content.value);
} else {
......@@ -216,7 +216,7 @@ export class NodeBasedFolderConfiguration extends AbstractFolderConfiguration {
constructor(folder: URI, configFolderRelativePath: string, workbenchState: WorkbenchState) {
super(folder, workbenchState);
this.folderConfigurationPath = URI.file(paths.join(this.folder.fsPath, configFolderRelativePath));
this.folderConfigurationPath = resources.joinPath(folder, configFolderRelativePath);
}
protected loadFolderConfigurationContents(): TPromise<{ resource: URI, value: string }[]> {
......@@ -249,7 +249,7 @@ export class NodeBasedFolderConfiguration extends AbstractFolderConfiguration {
c({
resource,
isDirectory: true,
children: children.map(child => { return { resource: URI.file(paths.join(resource.fsPath, child)) }; })
children: children.map(child => { return { resource: resources.joinPath(resource, child) }; })
});
}
});
......@@ -265,7 +265,7 @@ export class FileServiceBasedFolderConfiguration extends AbstractFolderConfigura
constructor(folder: URI, private configFolderRelativePath: string, workbenchState: WorkbenchState, private fileService: IFileService, from?: AbstractFolderConfiguration) {
super(folder, workbenchState, from);
this.folderConfigurationPath = folder.with({ path: paths.join(this.folder.path, configFolderRelativePath) });
this.folderConfigurationPath = resources.joinPath(folder, configFolderRelativePath);
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50));
this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e)));
}
......@@ -296,7 +296,7 @@ export class FileServiceBasedFolderConfiguration extends AbstractFolderConfigura
for (let i = 0, len = events.length; i < len; i++) {
const resource = events[i].resource;
const basename = paths.basename(resource.path);
const basename = resources.basename(resource);
const isJson = paths.extname(basename) === '.json';
const isDeletedSettingsFolder = (events[i].type === FileChangeType.DELETED && basename === this.configFolderRelativePath);
......
......@@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { posix } from 'path';
import { flatten, isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { TernarySearchTree, keys } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
import * as resources from 'vs/base/common/resources';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDecodeStreamOptions, toDecodeStream, encodeStream } from 'vs/base/node/encoding';
......@@ -42,7 +42,7 @@ function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse
const [resource, stat] = tuple;
const fileStat: IFileStat = {
resource,
name: posix.basename(resource.path),
name: resources.basename(resource),
isDirectory: (stat.type & FileType.Directory) !== 0,
isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0,
isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly),
......@@ -58,7 +58,7 @@ function toIFileStat(provider: IFileSystemProvider, tuple: [URI, IStat], recurse
// resolve children if requested
return TPromise.join(entries.map(tuple => {
const [name, type] = tuple;
const childResource = resource.with({ path: posix.join(resource.path, name) });
const childResource = resources.joinPath(resource, name);
return toIFileStat(provider, [childResource, new TypeOnlyStat(type)], recurse);
})).then(children => {
fileStat.children = children;
......@@ -261,7 +261,7 @@ export class RemoteFileService extends FileService {
private _withProvider(resource: URI): TPromise<IFileSystemProvider> {
if (!posix.isAbsolute(resource.path)) {
if (!resources.isAbsolutePath(resource)) {
throw new FileOperationError(
localize('invalidPath', "The path of resource '{0}' must be absolute", resource.toString(true)),
FileOperationResult.FILE_INVALID_PATH
......@@ -434,12 +434,12 @@ export class RemoteFileService extends FileService {
break; // we have hit a directory -> good
} catch (e) {
// ENOENT
basenames.push(posix.basename(directory.path));
directory = directory.with({ path: posix.dirname(directory.path) });
basenames.push(resources.basename(directory));
directory = resources.dirname(directory);
}
}
for (let i = basenames.length - 1; i >= 0; i--) {
directory = directory.with({ path: posix.join(directory.path, basenames[i]) });
directory = resources.joinPath(directory, basenames[i]);
await provider.mkdir(directory);
}
}
......@@ -458,7 +458,7 @@ export class RemoteFileService extends FileService {
return this._withProvider(resource).then(RemoteFileService._throwIfFileSystemIsReadonly).then(provider => {
return RemoteFileService._mkdirp(provider, resource.with({ path: posix.dirname(resource.path) })).then(() => {
return RemoteFileService._mkdirp(provider, resources.dirname(resource)).then(() => {
const encoding = this.encoding.getWriteEncoding(resource);
return this._writeFile(provider, resource, new StringSnapshot(content), encoding, { create: true, overwrite: Boolean(options && options.overwrite) });
});
......@@ -479,7 +479,7 @@ export class RemoteFileService extends FileService {
return super.updateContent(resource, value, options);
} else {
return this._withProvider(resource).then(RemoteFileService._throwIfFileSystemIsReadonly).then(provider => {
return RemoteFileService._mkdirp(provider, resource.with({ path: posix.dirname(resource.path) })).then(() => {
return RemoteFileService._mkdirp(provider, resources.dirname(resource)).then(() => {
const snapshot = typeof value === 'string' ? new StringSnapshot(value) : value;
return this._writeFile(provider, resource, snapshot, options && options.encoding, { create: true, overwrite: true });
});
......@@ -537,7 +537,7 @@ export class RemoteFileService extends FileService {
return super.createFolder(resource);
} else {
return this._withProvider(resource).then(RemoteFileService._throwIfFileSystemIsReadonly).then(provider => {
return RemoteFileService._mkdirp(provider, resource.with({ path: posix.dirname(resource.path) })).then(() => {
return RemoteFileService._mkdirp(provider, resources.dirname(resource)).then(() => {
return provider.mkdir(resource).then(() => {
return this.resolveFile(resource);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册