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