mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 20:13:32 +01:00
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:
@@ -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 });
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
Reference in New Issue
Block a user