labels - handle file service changes better (fix #91833)

This commit is contained in:
Benjamin Pasero 2020-03-02 11:06:59 +01:00
parent f33d982fd5
commit f2502971b5
9 changed files with 56 additions and 38 deletions

View file

@ -36,7 +36,7 @@ import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingReso
import { IKeybindingItem, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
import { ILabelService, ResourceLabelFormatter } from 'vs/platform/label/common/label';
import { ILabelService, ResourceLabelFormatter, IFormatterChangeEvent } from 'vs/platform/label/common/label';
import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification';
import { IProgressRunner, IEditorProgressService } from 'vs/platform/progress/common/progress';
import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@ -713,8 +713,7 @@ export class SimpleUriLabelService implements ILabelService {
_serviceBrand: undefined;
private readonly _onDidRegisterFormatter = new Emitter<void>();
public readonly onDidChangeFormatters: Event<void> = this._onDidRegisterFormatter.event;
public readonly onDidChangeFormatters: Event<IFormatterChangeEvent> = Event.None;
public getUriLabel(resource: URI, options?: { relative?: boolean, forceNoTildify?: boolean }): string {
if (resource.scheme === 'file') {

View file

@ -26,7 +26,11 @@ export interface ILabelService {
getHostLabel(scheme: string, authority?: string): string;
getSeparator(scheme: string, authority?: string): '/' | '\\';
registerFormatter(formatter: ResourceLabelFormatter): IDisposable;
onDidChangeFormatters: Event<void>;
onDidChangeFormatters: Event<IFormatterChangeEvent>;
}
export interface IFormatterChangeEvent {
scheme: string;
}
export interface ResourceLabelFormatter {

View file

@ -137,14 +137,14 @@ export class ResourceLabels extends Disposable {
}));
// notify when label formatters change
this._register(this.labelService.onDidChangeFormatters(() => {
this._widgets.forEach(widget => widget.notifyFormattersChange());
this._register(this.labelService.onDidChangeFormatters(e => {
this._widgets.forEach(widget => widget.notifyFormattersChange(e.scheme));
}));
// notify when untitled labels change
this.textFileService.untitled.onDidChangeLabel(model => {
this._register(this.textFileService.untitled.onDidChangeLabel(model => {
this._widgets.forEach(widget => widget.notifyUntitledLabelChange(model.resource));
});
}));
}
get(index: number): IResourceLabel {
@ -311,8 +311,10 @@ class ResourceLabelWidget extends IconLabel {
this.render(true);
}
notifyFormattersChange(): void {
this.render(false);
notifyFormattersChange(scheme: string): void {
if (this.label?.resource?.scheme === scheme) {
this.render(false);
}
}
notifyUntitledLabelChange(resource: URI): void {

View file

@ -40,9 +40,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
import { IFileService } from 'vs/platform/files/common/files';
import { withNullAsUndefined, assertAllDefined, assertIsDefined } from 'vs/base/common/types';
import { ILabelService } from 'vs/platform/label/common/label';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { basenameOrAuthority } from 'vs/base/common/resources';
import { RunOnceScheduler } from 'vs/base/common/async';
interface IEditorInputLabel {
name?: string;
@ -85,10 +85,9 @@ export class TabsTitleControl extends TitleControl {
@IExtensionService extensionService: IExtensionService,
@IConfigurationService configurationService: IConfigurationService,
@IFileService fileService: IFileService,
@ILabelService labelService: ILabelService,
@IEditorService private readonly editorService: EditorServiceImpl
) {
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService, labelService);
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService);
this.tabResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER));
this.closeOneEditorAction = this._register(this.instantiationService.createInstance(CloseOneEditorAction, CloseOneEditorAction.ID, CloseOneEditorAction.LABEL));
@ -392,10 +391,16 @@ export class TabsTitleControl extends TitleControl {
this.layout(this.dimension);
}
private updateEditorLabelAggregator = this._register(new RunOnceScheduler(() => this.updateEditorLabels(), 0));
updateEditorLabel(editor: IEditorInput): void {
// Update all labels to account for changes to tab labels
this.updateEditorLabels();
// Since this method may be called a lot of times from
// individual editors, we collect all those requests and
// then run the update once because we have to update
// all opened tabs in the group at once.
this.updateEditorLabelAggregator.schedule();
}
updateEditorLabels(): void {

View file

@ -40,7 +40,6 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { IFileService } from 'vs/platform/files/common/files';
import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types';
import { ILabelService } from 'vs/platform/label/common/label';
import { isFirefox } from 'vs/base/browser/browser';
export interface IToolbarActions {
@ -82,8 +81,7 @@ export abstract class TitleControl extends Themable {
@IThemeService themeService: IThemeService,
@IExtensionService private readonly extensionService: IExtensionService,
@IConfigurationService protected configurationService: IConfigurationService,
@IFileService private readonly fileService: IFileService,
@ILabelService private readonly labelService: ILabelService
@IFileService private readonly fileService: IFileService
) {
super(themeService);
@ -97,8 +95,9 @@ export abstract class TitleControl extends Themable {
}
private registerListeners(): void {
// Update actions toolbar when extension register that may contribute them
this._register(this.extensionService.onDidRegisterExtensions(() => this.updateEditorActionsToolbar()));
this._register(this.labelService.onDidChangeFormatters(() => this.updateEditorLabels()));
}
protected abstract create(parent: HTMLElement): void;

View file

@ -86,7 +86,7 @@ export class TitlebarPart extends Part implements ITitleService {
private readonly properties: ITitleProperties = { isPure: true, isAdmin: false };
private readonly activeEditorListeners = this._register(new DisposableStore());
private titleUpdater: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.doUpdateTitle(), 0));
private readonly titleUpdater = this._register(new RunOnceScheduler(() => this.doUpdateTitle(), 0));
private contextMenu: IMenu;

View file

@ -609,8 +609,20 @@ export abstract class TextResourceEditorInput extends EditorInput {
protected registerListeners(): void {
// Clear label memoizer on certain events that have impact
this._register(this.labelService.onDidChangeFormatters(() => TextResourceEditorInput.MEMOIZER.clear()));
this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(() => TextResourceEditorInput.MEMOIZER.clear()));
this._register(this.labelService.onDidChangeFormatters(e => this.onLabelEvent(e.scheme)));
this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onLabelEvent(e.scheme)));
this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onLabelEvent(e.scheme)));
}
private onLabelEvent(scheme: string): void {
if (scheme === this.resource.scheme) {
// Clear any cached labels from before
TextResourceEditorInput.MEMOIZER.clear();
// Trigger recompute of label
this._onDidChangeLabel.fire();
}
}
getName(): string {
@ -685,10 +697,6 @@ export abstract class TextResourceEditorInput extends EditorInput {
return false; // untitled is never readonly
}
if (!this.fileService.canHandleResource(this.resource)) {
return true; // resources without file support are always readonly
}
return this.fileService.hasCapability(this.resource, FileSystemProviderCapabilities.Readonly);
}

View file

@ -39,7 +39,7 @@ import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browse
import { ExtensionIdentifier, IExtensionContributions, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ILabelService } from 'vs/platform/label/common/label';
import { ILabelService, IFormatterChangeEvent } from 'vs/platform/label/common/label';
import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService';
import { IProductService } from 'vs/platform/product/common/productService';
import { Schemas } from 'vs/base/common/network';
@ -92,7 +92,7 @@ suite('ExtensionsActions Test', () => {
}());
instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
instantiationService.stub(ILabelService, { onDidChangeFormatters: new Emitter<void>().event });
instantiationService.stub(ILabelService, { onDidChangeFormatters: new Emitter<IFormatterChangeEvent>().event });
instantiationService.set(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService));
instantiationService.stub(IURLService, URLService);

View file

@ -5,9 +5,9 @@
import { localize } from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import * as paths from 'vs/base/common/path';
import { Event, Emitter } from 'vs/base/common/event';
import { Emitter } from 'vs/base/common/event';
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/registry/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
@ -16,7 +16,7 @@ import { isEqual, basenameOrAuthority, basename, joinPath, dirname } from 'vs/ba
import { tildify, getPathLabel } from 'vs/base/common/labels';
import { ltrim, endsWith } from 'vs/base/common/strings';
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier, isUntitledWorkspace } from 'vs/platform/workspaces/common/workspaces';
import { ILabelService, ResourceLabelFormatter, ResourceLabelFormatting } from 'vs/platform/label/common/label';
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/platform/lifecycle/common/lifecycle';
@ -89,19 +89,20 @@ class ResourceLabelFormattersHandler implements IWorkbenchContribution {
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ResourceLabelFormattersHandler, LifecyclePhase.Restored);
export class LabelService implements ILabelService {
export class LabelService extends Disposable implements ILabelService {
_serviceBrand: undefined;
private formatters: ResourceLabelFormatter[] = [];
private readonly _onDidChangeFormatters = new Emitter<void>();
private readonly _onDidChangeFormatters = this._register(new Emitter<IFormatterChangeEvent>());
readonly onDidChangeFormatters = this._onDidChangeFormatters.event;
constructor(
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
) { }
get onDidChangeFormatters(): Event<void> {
return this._onDidChangeFormatters.event;
) {
super();
}
findFormatting(resource: URI): ResourceLabelFormatting | undefined {
@ -226,12 +227,12 @@ export class LabelService implements ILabelService {
registerFormatter(formatter: ResourceLabelFormatter): IDisposable {
this.formatters.push(formatter);
this._onDidChangeFormatters.fire();
this._onDidChangeFormatters.fire({ scheme: formatter.scheme });
return {
dispose: () => {
this.formatters = this.formatters.filter(f => f !== formatter);
this._onDidChangeFormatters.fire();
this._onDidChangeFormatters.fire({ scheme: formatter.scheme });
}
};
}