Clean up multi root labels (#102051)

* Change labels of URI's in multi-root workspaces to be
[RootName] • [Path From RootPaath to File]
rather than
[RootName] • [basename RootPath]/[Path From RootPath to File]
in cases where the root has an explicit name and
[RootName] • [Path From RootName to File]
in cases where the root's name is defaulted to basename

* Fixup cases where context added after path.
(073398241b)

* Remove unused

* Additional test case
This commit is contained in:
Jackson Kearl
2020-07-10 10:44:17 -07:00
committed by GitHub
parent a25e2dbb56
commit 138e255728
2 changed files with 82 additions and 12 deletions

View File

@@ -12,7 +12,7 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWo
import { Registry } from 'vs/platform/registry/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { isEqual, basenameOrAuthority, basename, joinPath, dirname } from 'vs/base/common/resources';
import { basenameOrAuthority, basename, joinPath, dirname } from 'vs/base/common/resources';
import { tildify, getPathLabel } from 'vs/base/common/labels';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting, IFormatterChangeEvent } from 'vs/platform/label/common/label';
@@ -141,21 +141,18 @@ export class LabelService extends Disposable implements ILabelService {
const baseResource = this.contextService?.getWorkspaceFolder(resource);
if (options.relative && baseResource) {
const rootName = baseResource?.name ?? basenameOrAuthority(baseResource.uri);
const baseResourceLabel = this.formatUri(baseResource.uri, formatting, options.noPrefix);
let relativeLabel = this.formatUri(resource, formatting, options.noPrefix);
let relativeLabel: string;
if (isEqual(baseResource.uri, resource)) {
relativeLabel = ''; // no label if resources are identical
} else {
const baseResourceLabel = this.formatUri(baseResource.uri, formatting, options.noPrefix);
relativeLabel = this.formatUri(resource, formatting, options.noPrefix).substring(baseResourceLabel.lastIndexOf(formatting.separator) + 1);
if (relativeLabel.startsWith(rootName)) {
relativeLabel = relativeLabel.substring(rootName.length + (relativeLabel[rootName.length] === formatting.separator ? 1 : 0));
}
let overlap = 0;
while (relativeLabel[overlap] && relativeLabel[overlap] === baseResourceLabel[overlap]) { overlap++; }
if (!relativeLabel[overlap] || relativeLabel[overlap] === formatting.separator) {
relativeLabel = relativeLabel.substring(1 + overlap);
}
const hasMultipleRoots = this.contextService.getWorkspace().folders.length > 1;
if (hasMultipleRoots && !options.noPrefix) {
const rootName = baseResource?.name ?? basenameOrAuthority(baseResource.uri);
relativeLabel = relativeLabel ? (rootName + ' • ' + relativeLabel) : rootName; // always show root basename if there are multiple
}

View File

@@ -3,14 +3,15 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as resources from 'vs/base/common/resources';
import * as assert from 'assert';
import { TestEnvironmentService, TestPathService } from 'vs/workbench/test/browser/workbenchTestServices';
import { URI } from 'vs/base/common/uri';
import { LabelService } from 'vs/workbench/services/label/common/labelService';
import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
import { Workspace, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
suite('URI Label', () => {
let labelService: LabelService;
setup(() => {
@@ -156,3 +157,75 @@ suite('URI Label', () => {
assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABEL: /END');
});
});
suite('multi-root worksapce', () => {
let labelService: LabelService;
setup(() => {
const sources = URI.file('folder1/src');
const tests = URI.file('folder1/test');
const other = URI.file('folder2');
labelService = new LabelService(
TestEnvironmentService,
new TestContextService(
new Workspace('test-workspaace', [
new WorkspaceFolder({ uri: sources, index: 0, name: 'Sources' }, { uri: sources.toString() }),
new WorkspaceFolder({ uri: tests, index: 1, name: 'Tests' }, { uri: tests.toString() }),
new WorkspaceFolder({ uri: other, index: 2, name: resources.basename(other) }, { uri: other.toString() }),
])),
new TestPathService());
});
test('labels of files in multiroot workspaces are the foldername folloed by offset from the folder', () => {
labelService.registerFormatter({
scheme: 'file',
formatting: {
label: '${authority}${path}',
separator: '/',
tildify: false,
normalizeDriveLetter: false,
authorityPrefix: '//',
workspaceSuffix: ''
}
});
const tests = {
'folder1/src/file': 'Sources • file',
'folder1/src/folder/file': 'Sources • folder/file',
'folder1/src': 'Sources',
'folder1/other': '/folder1/other',
'folder2/other': 'folder2 • other',
};
Object.entries(tests).forEach(([path, label]) => {
const generated = labelService.getUriLabel(URI.file(path), { relative: true });
assert.equal(generated, label);
});
});
test('labels with context after path', () => {
labelService.registerFormatter({
scheme: 'file',
formatting: {
label: '${path} (${scheme})',
separator: '/',
}
});
const tests = {
'folder1/src/file': 'Sources • file (file)',
'folder1/src/folder/file': 'Sources • folder/file (file)',
'folder1/src': 'Sources',
'folder1/other': '/folder1/other (file)',
'folder2/other': 'folder2 • other (file)',
};
Object.entries(tests).forEach(([path, label]) => {
const generated = labelService.getUriLabel(URI.file(path), { relative: true });
assert.equal(generated, label, path);
});
});
});