feat: allow using formatting parts in the workplace suffix (#148850)

* feat: allow using formatting parts in the workplace suffix

* Revert "feat: allow using formatting parts in the workplace suffix"

This reverts commit a228e03ad6.

* feat: cache label formatters

* fix: tests
This commit is contained in:
Connor Peet
2022-05-09 13:11:24 -07:00
committed by GitHub
parent c37378d4a3
commit a365dbaf5c
8 changed files with 114 additions and 15 deletions

View File

@@ -17,13 +17,15 @@ import { tildify, getPathLabel } from 'vs/base/common/labels';
import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting, IFormatterChangeEvent } from 'vs/platform/label/common/label';
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { match } from 'vs/base/common/glob';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import { OperatingSystem, OS } from 'vs/base/common/platform';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { Schemas } from 'vs/base/common/network';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { Memento } from 'vs/workbench/common/memento';
const resourceLabelFormattersExtPoint = ExtensionsRegistry.registerExtensionPoint<ResourceLabelFormatter[]>({
extensionPoint: 'resourceLabelFormatters',
@@ -102,15 +104,24 @@ class ResourceLabelFormattersHandler implements IWorkbenchContribution {
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ResourceLabelFormattersHandler, LifecyclePhase.Restored);
const FORMATTER_CACHE_SIZE = 50;
interface IStoredFormatters {
formatters?: ResourceLabelFormatter[];
i?: number;
}
export class LabelService extends Disposable implements ILabelService {
declare readonly _serviceBrand: undefined;
private formatters: ResourceLabelFormatter[] = [];
private formatters: ResourceLabelFormatter[];
private readonly _onDidChangeFormatters = this._register(new Emitter<IFormatterChangeEvent>({ leakWarningThreshold: 400 }));
readonly onDidChangeFormatters = this._onDidChangeFormatters.event;
private readonly storedFormattersMemento: Memento;
private readonly storedFormatters: IStoredFormatters;
private os: OperatingSystem;
private userHome: URI | undefined;
@@ -118,7 +129,9 @@ export class LabelService extends Disposable implements ILabelService {
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IPathService private readonly pathService: IPathService,
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
@IStorageService storageService: IStorageService,
@ILifecycleService lifecycleService: ILifecycleService,
) {
super();
@@ -129,6 +142,10 @@ export class LabelService extends Disposable implements ILabelService {
this.os = OS;
this.userHome = pathService.defaultUriScheme === Schemas.file ? this.pathService.userHome({ preferLocal: true }) : undefined;
const memento = this.storedFormattersMemento = new Memento('cachedResourceFormatters', storageService);
this.storedFormatters = memento.getMemento(StorageScope.GLOBAL, StorageTarget.USER);
this.formatters = this.storedFormatters?.formatters || [];
// Remote environment is potentially long running
this.resolveRemoteEnvironment();
}
@@ -334,6 +351,28 @@ export class LabelService extends Disposable implements ILabelService {
return formatter?.workspaceTooltip;
}
registerCachedFormatter(formatter: ResourceLabelFormatter): IDisposable {
const list = this.storedFormatters.formatters ??= [];
let replace = list.findIndex(f => f.scheme === formatter.scheme && f.authority === formatter.authority);
if (replace === -1 && list.length >= FORMATTER_CACHE_SIZE) {
replace = FORMATTER_CACHE_SIZE - 1; // at max capacity, replace the last element
}
if (replace === -1) {
list.unshift(formatter);
} else {
for (let i = replace; i > 0; i--) {
list[i] = list[i - 1];
}
list[0] = formatter;
}
this.storedFormattersMemento.saveMemento();
return this.registerFormatter(formatter);
}
registerFormatter(formatter: ResourceLabelFormatter): IDisposable {
this.formatters.push(formatter);
this._onDidChangeFormatters.fire({ scheme: formatter.scheme });

View File

@@ -5,19 +5,24 @@
import * as resources from 'vs/base/common/resources';
import * as assert from 'assert';
import { TestEnvironmentService, TestPathService, TestRemoteAgentService } from 'vs/workbench/test/browser/workbenchTestServices';
import { TestEnvironmentService, TestLifecycleService, TestPathService, TestRemoteAgentService } 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 { TestContextService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
import { WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { Workspace } from 'vs/platform/workspace/test/common/testWorkspace';
import { isWindows } from 'vs/base/common/platform';
import { StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { Memento } from 'vs/workbench/common/memento';
import { ResourceLabelFormatter } from 'vs/platform/label/common/label';
suite('URI Label', () => {
let labelService: LabelService;
let storageService: TestStorageService;
setup(() => {
labelService = new LabelService(TestEnvironmentService, new TestContextService(), new TestPathService(), new TestRemoteAgentService());
storageService = new TestStorageService();
labelService = new LabelService(TestEnvironmentService, new TestContextService(), new TestPathService(), new TestRemoteAgentService(), storageService, new TestLifecycleService());
});
test('custom scheme', function () {
@@ -158,6 +163,41 @@ suite('URI Label', () => {
const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5');
assert.strictEqual(labelService.getUriLabel(uri1, { relative: false }), 'LABEL: /END');
});
test('label caching', () => {
const m = new Memento('cachedResourceFormatters', storageService).getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE);
const makeFormatter = (scheme: string): ResourceLabelFormatter => ({ formatting: { label: `\${path} (${scheme})`, separator: '/' }, scheme });
assert.deepStrictEqual(m, {});
// registers a new formatter:
labelService.registerCachedFormatter(makeFormatter('a'));
assert.deepStrictEqual(m, { formatters: [makeFormatter('a')] });
// registers a 2nd formatter:
labelService.registerCachedFormatter(makeFormatter('b'));
assert.deepStrictEqual(m, { formatters: [makeFormatter('b'), makeFormatter('a')] });
// promotes a formatter on re-register:
labelService.registerCachedFormatter(makeFormatter('a'));
assert.deepStrictEqual(m, { formatters: [makeFormatter('a'), makeFormatter('b')] });
// no-ops if already in first place:
labelService.registerCachedFormatter(makeFormatter('a'));
assert.deepStrictEqual(m, { formatters: [makeFormatter('a'), makeFormatter('b')] });
// limits the cache:
for (let i = 0; i < 100; i++) {
labelService.registerCachedFormatter(makeFormatter(`i${i}`));
}
let expected: ResourceLabelFormatter[] = [];
for (let i = 50; i < 100; i++) {
expected.unshift(makeFormatter(`i${i}`));
}
assert.deepStrictEqual(m, { formatters: expected });
delete (m as any).formatters;
});
});
@@ -178,7 +218,9 @@ suite('multi-root workspace', () => {
new WorkspaceFolder({ uri: other, index: 2, name: resources.basename(other) }),
])),
new TestPathService(),
new TestRemoteAgentService()
new TestRemoteAgentService(),
new TestStorageService(),
new TestLifecycleService()
);
});
@@ -263,7 +305,9 @@ suite('multi-root workspace', () => {
new WorkspaceFolder({ uri: rootFolder, index: 0, name: 'FSProotFolder' }),
])),
new TestPathService(undefined, rootFolder.scheme),
new TestRemoteAgentService()
new TestRemoteAgentService(),
new TestStorageService(),
new TestLifecycleService()
);
const generated = labelService.getUriLabel(URI.parse('myscheme://myauthority/some/folder/test.txt'), { relative: true });
@@ -288,7 +332,9 @@ suite('workspace at FSP root', () => {
new WorkspaceFolder({ uri: rootFolder, index: 0, name: 'FSProotFolder' }),
])),
new TestPathService(),
new TestRemoteAgentService()
new TestRemoteAgentService(),
new TestStorageService(),
new TestLifecycleService()
);
labelService.registerFormatter({
scheme: 'myscheme',

View File

@@ -9,16 +9,16 @@ import { URI } from 'vs/base/common/uri';
import { sep } from 'vs/base/common/path';
import { isWindows } from 'vs/base/common/platform';
import { LabelService } from 'vs/workbench/services/label/common/labelService';
import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
import { TestContextService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
import { TestNativePathService, TestEnvironmentService } from 'vs/workbench/test/electron-browser/workbenchTestServices';
import { TestRemoteAgentService } from 'vs/workbench/test/browser/workbenchTestServices';
import { TestLifecycleService, TestRemoteAgentService } from 'vs/workbench/test/browser/workbenchTestServices';
suite('URI Label', () => {
let labelService: LabelService;
setup(() => {
labelService = new LabelService(TestEnvironmentService, new TestContextService(), new TestNativePathService(), new TestRemoteAgentService());
labelService = new LabelService(TestEnvironmentService, new TestContextService(), new TestNativePathService(), new TestRemoteAgentService(), new TestStorageService(), new TestLifecycleService());
});
test('file scheme', function () {