diff --git a/src/vs/platform/uriDisplay/common/uriDisplay.ts b/src/vs/platform/uriDisplay/common/uriDisplay.ts index ac49935e2dbcd62c0e87a3c1c11611eb14bac339..c98168c70635a031587708ebdced7eac360dc71f 100644 --- a/src/vs/platform/uriDisplay/common/uriDisplay.ts +++ b/src/vs/platform/uriDisplay/common/uriDisplay.ts @@ -12,6 +12,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { isEqual, basenameOrAuthority } from 'vs/base/common/resources'; import { isLinux, isWindows } from 'vs/base/common/platform'; import { tildify, normalizeDriveLetter } from 'vs/base/common/labels'; +import { ltrim } from 'vs/base/common/strings'; export interface IUriDisplayService { _serviceBrand: any; @@ -21,18 +22,20 @@ export interface IUriDisplayService { export interface UriDisplayRules { label: string; // myLabel:/${path} - separator: '/' | '\\' | undefined; + separator: '/' | '\\' | ''; tildify?: boolean; normalizeDriveLetter?: boolean; } const URI_DISPLAY_SERVICE_ID = 'uriDisplay'; +const sepRegexp = /\//g; +const labelMatchingRegexp = /\$\{scheme\}|\$\{authority\}|\$\{path\}/g; function hasDriveLetter(path: string): boolean { return isWindows && path && path[1] === ':'; } -class UriDisplayService implements IUriDisplayService { +export class UriDisplayService implements IUriDisplayService { _serviceBrand: any; private formaters = new Map(); @@ -46,28 +49,33 @@ class UriDisplayService implements IUriDisplayService { if (!resource) { return undefined; } + const formater = this.formaters.get(resource.scheme); + if (!formater) { + return resource.with({ query: null, fragment: null }).toString(true); + } if (relative) { - const hasMultipleRoots = this.contextService.getWorkspace().folders.length > 1; const baseResource = this.contextService.getWorkspaceFolder(resource); - - let pathLabel: string; - if (isEqual(baseResource.uri, resource, !isLinux)) { - pathLabel = ''; // no label if paths are identical - } else { - const baseResourceLabel = this.formatUri(baseResource.uri); - pathLabel = this.formatUri(resource).substring(baseResourceLabel.length); - } - - if (hasMultipleRoots) { - const rootName = (baseResource && baseResource.name) ? baseResource.name : basenameOrAuthority(baseResource.uri); - pathLabel = pathLabel ? (rootName + ' • ' + pathLabel) : rootName; // always show root basename if there are multiple + if (baseResource) { + let relativeLabel: string; + if (isEqual(baseResource.uri, resource, !isLinux)) { + relativeLabel = ''; // no label if resources are identical + } else { + const baseResourceLabel = this.formatUri(baseResource.uri, formater); + relativeLabel = ltrim(this.formatUri(resource, formater).substring(baseResourceLabel.length), formater.separator); + } + + const hasMultipleRoots = this.contextService.getWorkspace().folders.length > 1; + if (hasMultipleRoots) { + const rootName = (baseResource && baseResource.name) ? baseResource.name : basenameOrAuthority(baseResource.uri); + relativeLabel = relativeLabel ? (rootName + ' • ' + relativeLabel) : rootName; // always show root basename if there are multiple + } + + return relativeLabel; } - - return pathLabel; } - return this.formatUri(resource); + return this.formatUri(resource, formater); } registerFormater(scheme: string, formater: UriDisplayRules): IDisposable { @@ -78,26 +86,26 @@ class UriDisplayService implements IUriDisplayService { }; } - private formatUri(resource: URI): string { - const formater = this.formaters.get(resource.scheme); - if (!formater) { - return resource.with({ query: null, fragment: null }).toString(true); - } - - // TODO@isidor transform - let label = resource.path; + private formatUri(resource: URI, formater: UriDisplayRules): string { + let label = formater.label.replace(labelMatchingRegexp, match => { + switch (match) { + case '${scheme}': return resource.scheme; + case '${authority}': return resource.authority; + case '${path}': return resource.path; + default: return ''; + } + }); // convert c:\something => C:\something if (formater.normalizeDriveLetter && hasDriveLetter(label)) { label = normalizeDriveLetter(label); } - // normalize and tildify (macOS, Linux only) if (formater.tildify) { label = tildify(label, this.environmentService.userHome); } - return label; + return label.replace(sepRegexp, formater.separator); } } diff --git a/src/vs/platform/uriDisplay/test/uriDisplay.test.ts b/src/vs/platform/uriDisplay/test/uriDisplay.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f20db873babbf633dbd13f69576ff57ed9a85d9f --- /dev/null +++ b/src/vs/platform/uriDisplay/test/uriDisplay.test.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { IUriDisplayService, UriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay'; +import { TestEnvironmentService, TestContextService } from 'vs/workbench/test/workbenchTestServices'; +import { Schemas } from 'vs/base/common/network'; +import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; +import URI from 'vs/base/common/uri'; +import { nativeSep } from 'vs/base/common/paths'; +import { isWindows } from 'vs/base/common/platform'; + +suite('URI Display', () => { + + let uriDisplayService: IUriDisplayService; + + setup(() => { + uriDisplayService = new UriDisplayService(TestEnvironmentService, new TestContextService()); + }); + + test('file scheme', function () { + uriDisplayService.registerFormater(Schemas.file, { + label: '${path}', + separator: nativeSep, + tildify: !isWindows, + normalizeDriveLetter: isWindows + }); + + const uri1 = TestWorkspace.folders[0].uri.with({ path: TestWorkspace.folders[0].uri.path.concat('/a/b/c/d') }); + assert.equal(uriDisplayService.getLabel(uri1, true), isWindows ? 'a\\b\\c\\d' : 'a/b/c/d'); + assert.equal(uriDisplayService.getLabel(uri1, false), isWindows ? '\\testWorkspace\\a\\b\\c\\d' : '/testWorkspace/a/b/c/d'); + + const uri2 = URI.file('c:\\1/2/3'); + assert.equal(uriDisplayService.getLabel(uri2, false), isWindows ? 'C:\\1\\2\\3' : '/c:\\1/2/3'); + }); + + test('custom scheme', function () { + uriDisplayService.registerFormater(Schemas.vscode, { + label: 'LABEL/${path}/${authority}/END', + separator: '/', + tildify: true, + normalizeDriveLetter: true + }); + + const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5'); + assert.equal(uriDisplayService.getLabel(uri1, false), 'LABEL//1/2/3/4/5/microsoft.com/END'); + }); +});