Path: blob/main/src/vs/workbench/common/editor/editorInput.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Emitter } from '../../../base/common/event.js';6import { URI } from '../../../base/common/uri.js';7import { EditorInputCapabilities, Verbosity, GroupIdentifier, ISaveOptions, IRevertOptions, IMoveResult, IEditorDescriptor, IEditorPane, IUntypedEditorInput, EditorResourceAccessor, AbstractEditorInput, isEditorInput, IEditorIdentifier } from '../editor.js';8import { isEqual } from '../../../base/common/resources.js';9import { ConfirmResult } from '../../../platform/dialogs/common/dialogs.js';10import { IMarkdownString } from '../../../base/common/htmlContent.js';11import { IDisposable } from '../../../base/common/lifecycle.js';12import { ThemeIcon } from '../../../base/common/themables.js';1314export interface IEditorCloseHandler {1516/**17* If `true`, will call into the `confirm` method to ask for confirmation18* before closing the editor.19*/20showConfirm(): boolean;2122/**23* Allows an editor to control what should happen when the editor24* (or a list of editor of the same kind) is being closed.25*26* By default a file specific dialog will open if the editor is27* dirty and not in the process of saving.28*29* If the editor is not dealing with files or another condition30* should be used besides dirty state, this method should be31* implemented to show a different dialog.32*33* @param editors All editors of the same kind that are being closed. Should be used34* to show a combined dialog.35*/36confirm(editors: ReadonlyArray<IEditorIdentifier>): Promise<ConfirmResult>;37}3839export interface IUntypedEditorOptions {4041/**42* Implementations should try to preserve as much43* view state as possible from the typed input based44* on the group the editor is opened.45*/46readonly preserveViewState?: GroupIdentifier;4748/**49* Implementations should preserve the original50* resource of the typed input and not alter51* it.52*/53readonly preserveResource?: boolean;54}5556/**57* Editor inputs are lightweight objects that can be passed to the workbench API to open inside the editor part.58* Each editor input is mapped to an editor that is capable of opening it through the Platform facade.59*/60export abstract class EditorInput extends AbstractEditorInput {6162protected readonly _onDidChangeDirty = this._register(new Emitter<void>());63protected readonly _onDidChangeLabel = this._register(new Emitter<void>());64protected readonly _onDidChangeCapabilities = this._register(new Emitter<void>());6566private readonly _onWillDispose = this._register(new Emitter<void>());6768/**69* Triggered when this input changes its dirty state.70*/71readonly onDidChangeDirty = this._onDidChangeDirty.event;7273/**74* Triggered when this input changes its label75*/76readonly onDidChangeLabel = this._onDidChangeLabel.event;7778/**79* Triggered when this input changes its capabilities.80*/81readonly onDidChangeCapabilities = this._onDidChangeCapabilities.event;8283/**84* Triggered when this input is about to be disposed.85*/86readonly onWillDispose = this._onWillDispose.event;8788/**89* Optional: subclasses can override to implement90* custom confirmation on close behavior.91*/92readonly closeHandler?: IEditorCloseHandler;9394/**95* Unique type identifier for this input. Every editor input of the96* same class should share the same type identifier. The type identifier97* is used for example for serialising/deserialising editor inputs98* via the serialisers of the `EditorInputFactoryRegistry`.99*/100abstract get typeId(): string;101102/**103* Returns the optional associated resource of this input.104*105* This resource should be unique for all editors of the same106* kind and input and is often used to identify the editor input among107* others.108*109* **Note:** DO NOT use this property for anything but identity110* checks. DO NOT use this property to present as label to the user.111* Please refer to `EditorResourceAccessor` documentation in that case.112*/113abstract get resource(): URI | undefined;114115/**116* Identifies the type of editor this input represents117* This ID is registered with the {@link EditorResolverService} to allow118* for resolving an untyped input to a typed one119*/120get editorId(): string | undefined {121return undefined;122}123124/**125* The capabilities of the input.126*/127get capabilities(): EditorInputCapabilities {128return EditorInputCapabilities.Readonly;129}130131/**132* Figure out if the input has the provided capability.133*/134hasCapability(capability: EditorInputCapabilities): boolean {135if (capability === EditorInputCapabilities.None) {136return this.capabilities === EditorInputCapabilities.None;137}138139return (this.capabilities & capability) !== 0;140}141142isReadonly(): boolean | IMarkdownString {143return this.hasCapability(EditorInputCapabilities.Readonly);144}145146/**147* Returns the display name of this input.148*/149getName(): string {150return `Editor ${this.typeId}`;151}152153/**154* Returns the display description of this input.155*/156getDescription(verbosity?: Verbosity): string | undefined {157return undefined;158}159160/**161* Returns the display title of this input.162*/163getTitle(verbosity?: Verbosity): string {164return this.getName();165}166167/**168* Returns the extra classes to apply to the label of this input.169*/170getLabelExtraClasses(): string[] {171return [];172}173174/**175* Returns the aria label to be read out by a screen reader.176*/177getAriaLabel(): string {178return this.getTitle(Verbosity.SHORT);179}180181/**182* Returns the icon which represents this editor input.183* If undefined, the default icon will be used.184*/185getIcon(): ThemeIcon | undefined {186return undefined;187}188189/**190* Returns a descriptor suitable for telemetry events.191*192* Subclasses should extend if they can contribute.193*/194getTelemetryDescriptor(): { [key: string]: unknown } {195/* __GDPR__FRAGMENT__196"EditorTelemetryDescriptor" : {197"typeId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }198}199*/200return { typeId: this.typeId };201}202203/**204* Returns if this input is dirty or not.205*/206isDirty(): boolean {207return false;208}209210/**211* Returns if the input has unsaved changes.212*/213isModified(): boolean {214return this.isDirty();215}216217/**218* Returns if this input is currently being saved or soon to be219* saved. Based on this assumption the editor may for example220* decide to not signal the dirty state to the user assuming that221* the save is scheduled to happen anyway.222*/223isSaving(): boolean {224return false;225}226227/**228* Returns a type of `IDisposable` that represents the resolved input.229* Subclasses should override to provide a meaningful model or return230* `null` if the editor does not require a model.231*232* The `options` parameter are passed down from the editor when the233* input is resolved as part of it.234*/235async resolve(): Promise<IDisposable | null> {236return null;237}238239/**240* Saves the editor. The provided groupId helps implementors241* to e.g. preserve view state of the editor and re-open it242* in the correct group after saving.243*244* @returns the resulting editor input (typically the same) of245* this operation or `undefined` to indicate that the operation246* failed or was canceled.247*/248async save(group: GroupIdentifier, options?: ISaveOptions): Promise<EditorInput | IUntypedEditorInput | undefined> {249return this;250}251252/**253* Saves the editor to a different location. The provided `group`254* helps implementors to e.g. preserve view state of the editor255* and re-open it in the correct group after saving.256*257* @returns the resulting editor input (typically a different one)258* of this operation or `undefined` to indicate that the operation259* failed or was canceled.260*/261async saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise<EditorInput | IUntypedEditorInput | undefined> {262return this;263}264265/**266* Reverts this input from the provided group.267*/268async revert(group: GroupIdentifier, options?: IRevertOptions): Promise<void> { }269270/**271* Called to determine how to handle a resource that is renamed that matches272* the editors resource (or is a child of).273*274* Implementors are free to not implement this method to signal no intent275* to participate. If an editor is returned though, it will replace the276* current one with that editor and optional options.277*/278async rename(group: GroupIdentifier, target: URI): Promise<IMoveResult | undefined> {279return undefined;280}281282/**283* Returns a copy of the current editor input. Used when we can't just reuse the input284*/285copy(): EditorInput {286return this;287}288289/**290* Indicates if this editor can be moved to another group. By default291* editors can freely be moved around groups. If an editor cannot be292* moved, a message should be returned to show to the user.293*294* @returns `true` if the editor can be moved to the target group, or295* a string with a message to show to the user if the editor cannot be296* moved.297*/298canMove(sourceGroup: GroupIdentifier, targetGroup: GroupIdentifier): true | string {299return true;300}301302/**303* Returns if the other object matches this input.304*/305matches(otherInput: EditorInput | IUntypedEditorInput): boolean {306307// Typed inputs: via === check308if (isEditorInput(otherInput)) {309return this === otherInput;310}311312// Untyped inputs: go into properties313const otherInputEditorId = otherInput.options?.override;314315// If the overrides are both defined and don't match that means they're separate inputs316if (this.editorId !== otherInputEditorId && otherInputEditorId !== undefined && this.editorId !== undefined) {317return false;318}319320return isEqual(this.resource, EditorResourceAccessor.getCanonicalUri(otherInput));321}322323/**324* If a editor was registered onto multiple editor panes, this method325* will be asked to return the preferred one to use.326*327* @param editorPanes a list of editor pane descriptors that are candidates328* for the editor to open in.329*/330prefersEditorPane<T extends IEditorDescriptor<IEditorPane>>(editorPanes: T[]): T | undefined {331return editorPanes.at(0);332}333334/**335* Returns a representation of this typed editor input as untyped336* resource editor input that e.g. can be used to serialize the337* editor input into a form that it can be restored.338*339* May return `undefined` if an untyped representation is not supported.340*/341toUntyped(options?: IUntypedEditorOptions): IUntypedEditorInput | undefined {342return undefined;343}344345/**346* Returns if this editor is disposed.347*/348isDisposed(): boolean {349return this._store.isDisposed;350}351352override dispose(): void {353if (!this.isDisposed()) {354this._onWillDispose.fire();355}356357super.dispose();358}359}360361362