Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/common/editor/editorInput.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Emitter } from '../../../base/common/event.js';
7
import { URI } from '../../../base/common/uri.js';
8
import { EditorInputCapabilities, Verbosity, GroupIdentifier, ISaveOptions, IRevertOptions, IMoveResult, IEditorDescriptor, IEditorPane, IUntypedEditorInput, EditorResourceAccessor, AbstractEditorInput, isEditorInput, IEditorIdentifier } from '../editor.js';
9
import { isEqual } from '../../../base/common/resources.js';
10
import { ConfirmResult } from '../../../platform/dialogs/common/dialogs.js';
11
import { IMarkdownString } from '../../../base/common/htmlContent.js';
12
import { IDisposable } from '../../../base/common/lifecycle.js';
13
import { ThemeIcon } from '../../../base/common/themables.js';
14
15
export interface IEditorCloseHandler {
16
17
/**
18
* If `true`, will call into the `confirm` method to ask for confirmation
19
* before closing the editor.
20
*/
21
showConfirm(): boolean;
22
23
/**
24
* Allows an editor to control what should happen when the editor
25
* (or a list of editor of the same kind) is being closed.
26
*
27
* By default a file specific dialog will open if the editor is
28
* dirty and not in the process of saving.
29
*
30
* If the editor is not dealing with files or another condition
31
* should be used besides dirty state, this method should be
32
* implemented to show a different dialog.
33
*
34
* @param editors All editors of the same kind that are being closed. Should be used
35
* to show a combined dialog.
36
*/
37
confirm(editors: ReadonlyArray<IEditorIdentifier>): Promise<ConfirmResult>;
38
}
39
40
export interface IUntypedEditorOptions {
41
42
/**
43
* Implementations should try to preserve as much
44
* view state as possible from the typed input based
45
* on the group the editor is opened.
46
*/
47
readonly preserveViewState?: GroupIdentifier;
48
49
/**
50
* Implementations should preserve the original
51
* resource of the typed input and not alter
52
* it.
53
*/
54
readonly preserveResource?: boolean;
55
}
56
57
/**
58
* Editor inputs are lightweight objects that can be passed to the workbench API to open inside the editor part.
59
* Each editor input is mapped to an editor that is capable of opening it through the Platform facade.
60
*/
61
export abstract class EditorInput extends AbstractEditorInput {
62
63
protected readonly _onDidChangeDirty = this._register(new Emitter<void>());
64
protected readonly _onDidChangeLabel = this._register(new Emitter<void>());
65
protected readonly _onDidChangeCapabilities = this._register(new Emitter<void>());
66
67
private readonly _onWillDispose = this._register(new Emitter<void>());
68
69
/**
70
* Triggered when this input changes its dirty state.
71
*/
72
readonly onDidChangeDirty = this._onDidChangeDirty.event;
73
74
/**
75
* Triggered when this input changes its label
76
*/
77
readonly onDidChangeLabel = this._onDidChangeLabel.event;
78
79
/**
80
* Triggered when this input changes its capabilities.
81
*/
82
readonly onDidChangeCapabilities = this._onDidChangeCapabilities.event;
83
84
/**
85
* Triggered when this input is about to be disposed.
86
*/
87
readonly onWillDispose = this._onWillDispose.event;
88
89
/**
90
* Optional: subclasses can override to implement
91
* custom confirmation on close behavior.
92
*/
93
readonly closeHandler?: IEditorCloseHandler;
94
95
/**
96
* Unique type identifier for this input. Every editor input of the
97
* same class should share the same type identifier. The type identifier
98
* is used for example for serialising/deserialising editor inputs
99
* via the serialisers of the `EditorInputFactoryRegistry`.
100
*/
101
abstract get typeId(): string;
102
103
/**
104
* Returns the optional associated resource of this input.
105
*
106
* This resource should be unique for all editors of the same
107
* kind and input and is often used to identify the editor input among
108
* others.
109
*
110
* **Note:** DO NOT use this property for anything but identity
111
* checks. DO NOT use this property to present as label to the user.
112
* Please refer to `EditorResourceAccessor` documentation in that case.
113
*/
114
abstract get resource(): URI | undefined;
115
116
/**
117
* Identifies the type of editor this input represents
118
* This ID is registered with the {@link EditorResolverService} to allow
119
* for resolving an untyped input to a typed one
120
*/
121
get editorId(): string | undefined {
122
return undefined;
123
}
124
125
/**
126
* The capabilities of the input.
127
*/
128
get capabilities(): EditorInputCapabilities {
129
return EditorInputCapabilities.Readonly;
130
}
131
132
/**
133
* Figure out if the input has the provided capability.
134
*/
135
hasCapability(capability: EditorInputCapabilities): boolean {
136
if (capability === EditorInputCapabilities.None) {
137
return this.capabilities === EditorInputCapabilities.None;
138
}
139
140
return (this.capabilities & capability) !== 0;
141
}
142
143
isReadonly(): boolean | IMarkdownString {
144
return this.hasCapability(EditorInputCapabilities.Readonly);
145
}
146
147
/**
148
* Returns the display name of this input.
149
*/
150
getName(): string {
151
return `Editor ${this.typeId}`;
152
}
153
154
/**
155
* Returns the display description of this input.
156
*/
157
getDescription(verbosity?: Verbosity): string | undefined {
158
return undefined;
159
}
160
161
/**
162
* Returns the display title of this input.
163
*/
164
getTitle(verbosity?: Verbosity): string {
165
return this.getName();
166
}
167
168
/**
169
* Returns the extra classes to apply to the label of this input.
170
*/
171
getLabelExtraClasses(): string[] {
172
return [];
173
}
174
175
/**
176
* Returns the aria label to be read out by a screen reader.
177
*/
178
getAriaLabel(): string {
179
return this.getTitle(Verbosity.SHORT);
180
}
181
182
/**
183
* Returns the icon which represents this editor input.
184
* If undefined, the default icon will be used.
185
*/
186
getIcon(): ThemeIcon | undefined {
187
return undefined;
188
}
189
190
/**
191
* Returns a descriptor suitable for telemetry events.
192
*
193
* Subclasses should extend if they can contribute.
194
*/
195
getTelemetryDescriptor(): { [key: string]: unknown } {
196
/* __GDPR__FRAGMENT__
197
"EditorTelemetryDescriptor" : {
198
"typeId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
199
}
200
*/
201
return { typeId: this.typeId };
202
}
203
204
/**
205
* Returns if this input is dirty or not.
206
*/
207
isDirty(): boolean {
208
return false;
209
}
210
211
/**
212
* Returns if the input has unsaved changes.
213
*/
214
isModified(): boolean {
215
return this.isDirty();
216
}
217
218
/**
219
* Returns if this input is currently being saved or soon to be
220
* saved. Based on this assumption the editor may for example
221
* decide to not signal the dirty state to the user assuming that
222
* the save is scheduled to happen anyway.
223
*/
224
isSaving(): boolean {
225
return false;
226
}
227
228
/**
229
* Returns a type of `IDisposable` that represents the resolved input.
230
* Subclasses should override to provide a meaningful model or return
231
* `null` if the editor does not require a model.
232
*
233
* The `options` parameter are passed down from the editor when the
234
* input is resolved as part of it.
235
*/
236
async resolve(): Promise<IDisposable | null> {
237
return null;
238
}
239
240
/**
241
* Saves the editor. The provided groupId helps implementors
242
* to e.g. preserve view state of the editor and re-open it
243
* in the correct group after saving.
244
*
245
* @returns the resulting editor input (typically the same) of
246
* this operation or `undefined` to indicate that the operation
247
* failed or was canceled.
248
*/
249
async save(group: GroupIdentifier, options?: ISaveOptions): Promise<EditorInput | IUntypedEditorInput | undefined> {
250
return this;
251
}
252
253
/**
254
* Saves the editor to a different location. The provided `group`
255
* helps implementors to e.g. preserve view state of the editor
256
* and re-open it in the correct group after saving.
257
*
258
* @returns the resulting editor input (typically a different one)
259
* of this operation or `undefined` to indicate that the operation
260
* failed or was canceled.
261
*/
262
async saveAs(group: GroupIdentifier, options?: ISaveOptions): Promise<EditorInput | IUntypedEditorInput | undefined> {
263
return this;
264
}
265
266
/**
267
* Reverts this input from the provided group.
268
*/
269
async revert(group: GroupIdentifier, options?: IRevertOptions): Promise<void> { }
270
271
/**
272
* Called to determine how to handle a resource that is renamed that matches
273
* the editors resource (or is a child of).
274
*
275
* Implementors are free to not implement this method to signal no intent
276
* to participate. If an editor is returned though, it will replace the
277
* current one with that editor and optional options.
278
*/
279
async rename(group: GroupIdentifier, target: URI): Promise<IMoveResult | undefined> {
280
return undefined;
281
}
282
283
/**
284
* Returns a copy of the current editor input. Used when we can't just reuse the input
285
*/
286
copy(): EditorInput {
287
return this;
288
}
289
290
/**
291
* Indicates if this editor can be moved to another group. By default
292
* editors can freely be moved around groups. If an editor cannot be
293
* moved, a message should be returned to show to the user.
294
*
295
* @returns `true` if the editor can be moved to the target group, or
296
* a string with a message to show to the user if the editor cannot be
297
* moved.
298
*/
299
canMove(sourceGroup: GroupIdentifier, targetGroup: GroupIdentifier): true | string {
300
return true;
301
}
302
303
/**
304
* Returns if the other object matches this input.
305
*/
306
matches(otherInput: EditorInput | IUntypedEditorInput): boolean {
307
308
// Typed inputs: via === check
309
if (isEditorInput(otherInput)) {
310
return this === otherInput;
311
}
312
313
// Untyped inputs: go into properties
314
const otherInputEditorId = otherInput.options?.override;
315
316
// If the overrides are both defined and don't match that means they're separate inputs
317
if (this.editorId !== otherInputEditorId && otherInputEditorId !== undefined && this.editorId !== undefined) {
318
return false;
319
}
320
321
return isEqual(this.resource, EditorResourceAccessor.getCanonicalUri(otherInput));
322
}
323
324
/**
325
* If a editor was registered onto multiple editor panes, this method
326
* will be asked to return the preferred one to use.
327
*
328
* @param editorPanes a list of editor pane descriptors that are candidates
329
* for the editor to open in.
330
*/
331
prefersEditorPane<T extends IEditorDescriptor<IEditorPane>>(editorPanes: T[]): T | undefined {
332
return editorPanes.at(0);
333
}
334
335
/**
336
* Returns a representation of this typed editor input as untyped
337
* resource editor input that e.g. can be used to serialize the
338
* editor input into a form that it can be restored.
339
*
340
* May return `undefined` if an untyped representation is not supported.
341
*/
342
toUntyped(options?: IUntypedEditorOptions): IUntypedEditorInput | undefined {
343
return undefined;
344
}
345
346
/**
347
* Returns if this editor is disposed.
348
*/
349
isDisposed(): boolean {
350
return this._store.isDisposed;
351
}
352
353
override dispose(): void {
354
if (!this.isDisposed()) {
355
this._onWillDispose.fire();
356
}
357
358
super.dispose();
359
}
360
}
361
362