Merge pull request #54951 from Microsoft/isidorn/uriLabelProvider

uriLabelProvider
This commit is contained in:
Isidor Nikolic 2018-07-26 17:40:32 +02:00 committed by GitHub
commit db9ce80baf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 184 additions and 1 deletions

View file

@ -0,0 +1,114 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import URI from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
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 } from 'vs/base/common/labels';
import { ltrim } from 'vs/base/common/strings';
export interface IUriDisplayService {
_serviceBrand: any;
getLabel(resource: URI, relative: boolean): string;
registerFormater(schema: string, formater: UriDisplayRules): IDisposable;
}
export interface UriDisplayRules {
label: string; // myLabel:/${path}
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[2] === ':';
}
export class UriDisplayService implements IUriDisplayService {
_serviceBrand: any;
private formaters = new Map<string, UriDisplayRules>();
constructor(
@IEnvironmentService private environmentService: IEnvironmentService,
@IWorkspaceContextService private contextService: IWorkspaceContextService
) { }
getLabel(resource: URI, relative: boolean): string {
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 baseResource = this.contextService.getWorkspaceFolder(resource);
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 this.formatUri(resource, formater);
}
registerFormater(scheme: string, formater: UriDisplayRules): IDisposable {
this.formaters.set(scheme, formater);
return {
dispose: () => this.formaters.delete(scheme)
};
}
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 = label.charAt(1).toUpperCase() + label.substr(2);
}
if (formater.tildify) {
label = tildify(label, this.environmentService.userHome);
}
return label.replace(sepRegexp, formater.separator);
}
}
// register service
export const IUriDisplayService = createDecorator<IUriDisplayService>(URI_DISPLAY_SERVICE_ID);
registerSingleton(IUriDisplayService, UriDisplayService);

View file

@ -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 ? 'C:\\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');
});
});

View file

@ -12,7 +12,7 @@ import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/
import { Registry } from 'vs/platform/registry/common/platform';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IEditorInputFactory, EditorInput, IFileEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files';
import { VIEWLET_ID, SortOrderConfiguration, FILE_EDITOR_INPUT_ID } from 'vs/workbench/parts/files/common/files';
@ -34,6 +34,9 @@ import { DataUriEditorInput } from 'vs/workbench/common/editor/dataUriEditorInpu
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
import { Schemas } from 'vs/base/common/network';
import { nativeSep } from 'vs/base/common/paths';
// Viewlet Action
export class OpenExplorerViewletAction extends ToggleViewletAction {
@ -50,6 +53,18 @@ export class OpenExplorerViewletAction extends ToggleViewletAction {
}
}
class FileUriDisplayContribution implements IWorkbenchContribution {
constructor(@IUriDisplayService uriDisplayService: IUriDisplayService) {
uriDisplayService.registerFormater(Schemas.file, {
label: '${path}',
separator: nativeSep,
tildify: !platform.isWindows,
normalizeDriveLetter: platform.isWindows
});
}
}
// Register Viewlet
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(new ViewletDescriptor(
ExplorerViewlet,
@ -156,6 +171,10 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
// Register Dirty Files Tracker
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesTracker, LifecyclePhase.Starting);
// Register uri display for file uris
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileUriDisplayContribution, LifecyclePhase.Starting);
// Configuration
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);