Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/simulation/fixtures/edit/issue-7996/codeEditorWidget.ts
13405 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 * as dom from '../../../../base/browser/dom.js';
7
import { IKeyboardEvent } from '../../../../base/browser/keyboardEvent.js';
8
import { IMouseWheelEvent } from '../../../../base/browser/mouseEvent.js';
9
import { Color } from '../../../../base/common/color.js';
10
import { onUnexpectedError } from '../../../../base/common/errors.js';
11
import { Emitter, EmitterOptions, Event, EventDeliveryQueue, createEventDeliveryQueue } from '../../../../base/common/event.js';
12
import { hash } from '../../../../base/common/hash.js';
13
import { Disposable, DisposableStore, IDisposable, dispose } from '../../../../base/common/lifecycle.js';
14
import { Schemas } from '../../../../base/common/network.js';
15
import * as nls from '../../../../nls.js';
16
import { IAccessibilityService } from '../../../../platform/accessibility/common/accessibility.js';
17
import { MenuId } from '../../../../platform/actions/common/actions.js';
18
import { ICommandService } from '../../../../platform/commands/common/commands.js';
19
import { ContextKeyValue, IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
20
import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
21
import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';
22
import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js';
23
import { editorErrorForeground, editorHintForeground, editorInfoForeground, editorWarningForeground } from '../../../../platform/theme/common/colorRegistry.js';
24
import { IThemeService, registerThemingParticipant } from '../../../../platform/theme/common/themeService.js';
25
import { IEditorConfiguration } from '../../../common/config/editorConfiguration.js';
26
import { ConfigurationChangedEvent, EditorLayoutInfo, EditorOption, FindComputedEditorOptionValueById, IComputedEditorOptions, IEditorOptions, filterValidationDecorations } from '../../../common/config/editorOptions.js';
27
import { CursorColumns } from '../../../common/core/cursorColumns.js';
28
import { IDimension } from '../../../common/core/dimension.js';
29
import { editorUnnecessaryCodeOpacity } from '../../../common/core/editorColorRegistry.js';
30
import { IPosition, Position } from '../../../common/core/position.js';
31
import { IRange, Range } from '../../../common/core/range.js';
32
import { ISelection, Selection } from '../../../common/core/selection.js';
33
import { IWordAtPosition } from '../../../common/core/wordHelper.js';
34
import { WordOperations } from '../../../common/cursor/cursorWordOperations.js';
35
import { CursorChangeReason, ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from '../../../common/cursorEvents.js';
36
import { InternalEditorAction } from '../../../common/editorAction.js';
37
import * as editorCommon from '../../../common/editorCommon.js';
38
import { EditorContextKeys } from '../../../common/editorContextKeys.js';
39
import { ILanguageConfigurationService } from '../../../common/languages/languageConfigurationRegistry.js';
40
import { EndOfLinePreference, IAttachedView, ICursorStateComputer, IIdentifiedSingleEditOperation, IModelDecoration, IModelDecorationOptions, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from '../../../common/model.js';
41
import { ClassName } from '../../../common/model/intervalTree.js';
42
import { ModelDecorationOptions } from '../../../common/model/textModel.js';
43
import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
44
import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from '../../../common/textModelEvents.js';
45
import { VerticalRevealType } from '../../../common/viewEvents.js';
46
import { IEditorWhitespace, IViewModel } from '../../../common/viewModel.js';
47
import { MonospaceLineBreaksComputerFactory } from '../../../common/viewModel/monospaceLineBreaksComputer.js';
48
import { ViewModel } from '../../../common/viewModel/viewModelImpl.js';
49
import { OutgoingViewModelEventKind } from '../../../common/viewModelEventDispatcher.js';
50
import { applyFontInfo } from '../../config/domFontInfo.js';
51
import { EditorConfiguration, IEditorConstructionOptions } from '../../config/editorConfiguration.js';
52
import { TabFocus } from '../../config/tabFocus.js';
53
import * as editorBrowser from '../../editorBrowser.js';
54
import { EditorExtensionsRegistry, IEditorContributionDescription } from '../../editorExtensions.js';
55
import { ICodeEditorService } from '../../services/codeEditorService.js';
56
import '../../services/markerDecorations.js';
57
import { IContentWidgetData, IGlyphMarginWidgetData, IOverlayWidgetData, View } from '../../view.js';
58
import { DOMLineBreaksComputerFactory } from '../../view/domLineBreaksComputer.js';
59
import { ICommandDelegate } from '../../view/viewController.js';
60
import { ViewUserInputEvents } from '../../view/viewUserInputEvents.js';
61
import { CodeEditorContributions } from './codeEditorContributions.js';
62
import './editor.css';
63
64
export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeEditor {
65
66
private static readonly dropIntoEditorDecorationOptions = ModelDecorationOptions.register({
67
description: 'workbench-dnd-target',
68
className: 'dnd-target'
69
});
70
71
//#region Eventing
72
73
private readonly _deliveryQueue = createEventDeliveryQueue();
74
protected readonly _contributions: CodeEditorContributions = this._register(new CodeEditorContributions());
75
76
private readonly _onDidDispose: Emitter<void> = this._register(new Emitter<void>());
77
public readonly onDidDispose: Event<void> = this._onDidDispose.event;
78
79
private readonly _onDidChangeModelContent: Emitter<IModelContentChangedEvent> = this._register(new Emitter<IModelContentChangedEvent>({ deliveryQueue: this._deliveryQueue }));
80
public readonly onDidChangeModelContent: Event<IModelContentChangedEvent> = this._onDidChangeModelContent.event;
81
82
private readonly _onDidChangeModelLanguage: Emitter<IModelLanguageChangedEvent> = this._register(new Emitter<IModelLanguageChangedEvent>({ deliveryQueue: this._deliveryQueue }));
83
public readonly onDidChangeModelLanguage: Event<IModelLanguageChangedEvent> = this._onDidChangeModelLanguage.event;
84
85
private readonly _onDidChangeModelLanguageConfiguration: Emitter<IModelLanguageConfigurationChangedEvent> = this._register(new Emitter<IModelLanguageConfigurationChangedEvent>({ deliveryQueue: this._deliveryQueue }));
86
public readonly onDidChangeModelLanguageConfiguration: Event<IModelLanguageConfigurationChangedEvent> = this._onDidChangeModelLanguageConfiguration.event;
87
88
private readonly _onDidChangeModelOptions: Emitter<IModelOptionsChangedEvent> = this._register(new Emitter<IModelOptionsChangedEvent>({ deliveryQueue: this._deliveryQueue }));
89
public readonly onDidChangeModelOptions: Event<IModelOptionsChangedEvent> = this._onDidChangeModelOptions.event;
90
91
private readonly _onDidChangeModelDecorations: Emitter<IModelDecorationsChangedEvent> = this._register(new Emitter<IModelDecorationsChangedEvent>({ deliveryQueue: this._deliveryQueue }));
92
public readonly onDidChangeModelDecorations: Event<IModelDecorationsChangedEvent> = this._onDidChangeModelDecorations.event;
93
94
private readonly _onDidChangeModelTokens: Emitter<IModelTokensChangedEvent> = this._register(new Emitter<IModelTokensChangedEvent>({ deliveryQueue: this._deliveryQueue }));
95
public readonly onDidChangeModelTokens: Event<IModelTokensChangedEvent> = this._onDidChangeModelTokens.event;
96
97
private readonly _onDidChangeConfiguration: Emitter<ConfigurationChangedEvent> = this._register(new Emitter<ConfigurationChangedEvent>({ deliveryQueue: this._deliveryQueue }));
98
public readonly onDidChangeConfiguration: Event<ConfigurationChangedEvent> = this._onDidChangeConfiguration.event;
99
100
protected readonly _onWillChangeModel: Emitter<editorCommon.IModelChangedEvent> = this._register(new Emitter<editorCommon.IModelChangedEvent>({ deliveryQueue: this._deliveryQueue }));
101
public readonly onWillChangeModel: Event<editorCommon.IModelChangedEvent> = this._onWillChangeModel.event;
102
103
protected readonly _onDidChangeModel: Emitter<editorCommon.IModelChangedEvent> = this._register(new Emitter<editorCommon.IModelChangedEvent>({ deliveryQueue: this._deliveryQueue }));
104
public readonly onDidChangeModel: Event<editorCommon.IModelChangedEvent> = this._onDidChangeModel.event;
105
106
private readonly _onDidChangeCursorPosition: Emitter<ICursorPositionChangedEvent> = this._register(new Emitter<ICursorPositionChangedEvent>({ deliveryQueue: this._deliveryQueue }));
107
public readonly onDidChangeCursorPosition: Event<ICursorPositionChangedEvent> = this._onDidChangeCursorPosition.event;
108
109
private readonly _onDidChangeCursorSelection: Emitter<ICursorSelectionChangedEvent> = this._register(new Emitter<ICursorSelectionChangedEvent>({ deliveryQueue: this._deliveryQueue }));
110
public readonly onDidChangeCursorSelection: Event<ICursorSelectionChangedEvent> = this._onDidChangeCursorSelection.event;
111
112
private readonly _onDidAttemptReadOnlyEdit: Emitter<void> = this._register(new InteractionEmitter<void>(this._contributions, this._deliveryQueue));
113
public readonly onDidAttemptReadOnlyEdit: Event<void> = this._onDidAttemptReadOnlyEdit.event;
114
115
private readonly _onDidLayoutChange: Emitter<EditorLayoutInfo> = this._register(new Emitter<EditorLayoutInfo>({ deliveryQueue: this._deliveryQueue }));
116
public readonly onDidLayoutChange: Event<EditorLayoutInfo> = this._onDidLayoutChange.event;
117
118
private readonly _editorTextFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter({ deliveryQueue: this._deliveryQueue }));
119
public readonly onDidFocusEditorText: Event<void> = this._editorTextFocus.onDidChangeToTrue;
120
public readonly onDidBlurEditorText: Event<void> = this._editorTextFocus.onDidChangeToFalse;
121
122
private readonly _editorWidgetFocus: BooleanEventEmitter = this._register(new BooleanEventEmitter({ deliveryQueue: this._deliveryQueue }));
123
public readonly onDidFocusEditorWidget: Event<void> = this._editorWidgetFocus.onDidChangeToTrue;
124
public readonly onDidBlurEditorWidget: Event<void> = this._editorWidgetFocus.onDidChangeToFalse;
125
126
private readonly _onWillType: Emitter<string> = this._register(new InteractionEmitter<string>(this._contributions, this._deliveryQueue));
127
public readonly onWillType = this._onWillType.event;
128
129
private readonly _onDidType: Emitter<string> = this._register(new InteractionEmitter<string>(this._contributions, this._deliveryQueue));
130
public readonly onDidType = this._onDidType.event;
131
132
private readonly _onDidCompositionStart: Emitter<void> = this._register(new InteractionEmitter<void>(this._contributions, this._deliveryQueue));
133
public readonly onDidCompositionStart = this._onDidCompositionStart.event;
134
135
private readonly _onDidCompositionEnd: Emitter<void> = this._register(new InteractionEmitter<void>(this._contributions, this._deliveryQueue));
136
public readonly onDidCompositionEnd = this._onDidCompositionEnd.event;
137
138
private readonly _onDidPaste: Emitter<editorBrowser.IPasteEvent> = this._register(new InteractionEmitter<editorBrowser.IPasteEvent>(this._contributions, this._deliveryQueue));
139
public readonly onDidPaste = this._onDidPaste.event;
140
141
private readonly _onMouseUp: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new InteractionEmitter<editorBrowser.IEditorMouseEvent>(this._contributions, this._deliveryQueue));
142
public readonly onMouseUp: Event<editorBrowser.IEditorMouseEvent> = this._onMouseUp.event;
143
144
private readonly _onMouseDown: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new InteractionEmitter<editorBrowser.IEditorMouseEvent>(this._contributions, this._deliveryQueue));
145
public readonly onMouseDown: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDown.event;
146
147
private readonly _onMouseDrag: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new InteractionEmitter<editorBrowser.IEditorMouseEvent>(this._contributions, this._deliveryQueue));
148
public readonly onMouseDrag: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDrag.event;
149
150
private readonly _onMouseDrop: Emitter<editorBrowser.IPartialEditorMouseEvent> = this._register(new InteractionEmitter<editorBrowser.IPartialEditorMouseEvent>(this._contributions, this._deliveryQueue));
151
public readonly onMouseDrop: Event<editorBrowser.IPartialEditorMouseEvent> = this._onMouseDrop.event;
152
153
private readonly _onMouseDropCanceled: Emitter<void> = this._register(new InteractionEmitter<void>(this._contributions, this._deliveryQueue));
154
public readonly onMouseDropCanceled: Event<void> = this._onMouseDropCanceled.event;
155
156
private readonly _onDropIntoEditor = this._register(new InteractionEmitter<{ readonly position: IPosition; readonly event: DragEvent }>(this._contributions, this._deliveryQueue));
157
public readonly onDropIntoEditor = this._onDropIntoEditor.event;
158
159
private readonly _onContextMenu: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new InteractionEmitter<editorBrowser.IEditorMouseEvent>(this._contributions, this._deliveryQueue));
160
public readonly onContextMenu: Event<editorBrowser.IEditorMouseEvent> = this._onContextMenu.event;
161
162
private readonly _onMouseMove: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new InteractionEmitter<editorBrowser.IEditorMouseEvent>(this._contributions, this._deliveryQueue));
163
public readonly onMouseMove: Event<editorBrowser.IEditorMouseEvent> = this._onMouseMove.event;
164
165
private readonly _onMouseLeave: Emitter<editorBrowser.IPartialEditorMouseEvent> = this._register(new InteractionEmitter<editorBrowser.IPartialEditorMouseEvent>(this._contributions, this._deliveryQueue));
166
public readonly onMouseLeave: Event<editorBrowser.IPartialEditorMouseEvent> = this._onMouseLeave.event;
167
168
private readonly _onMouseWheel: Emitter<IMouseWheelEvent> = this._register(new InteractionEmitter<IMouseWheelEvent>(this._contributions, this._deliveryQueue));
169
public readonly onMouseWheel: Event<IMouseWheelEvent> = this._onMouseWheel.event;
170
171
private readonly _onKeyUp: Emitter<IKeyboardEvent> = this._register(new InteractionEmitter<IKeyboardEvent>(this._contributions, this._deliveryQueue));
172
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
173
174
private readonly _onKeyDown: Emitter<IKeyboardEvent> = this._register(new InteractionEmitter<IKeyboardEvent>(this._contributions, this._deliveryQueue));
175
public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;
176
177
private readonly _onDidContentSizeChange: Emitter<editorCommon.IContentSizeChangedEvent> = this._register(new Emitter<editorCommon.IContentSizeChangedEvent>({ deliveryQueue: this._deliveryQueue }));
178
public readonly onDidContentSizeChange: Event<editorCommon.IContentSizeChangedEvent> = this._onDidContentSizeChange.event;
179
180
private readonly _onDidScrollChange: Emitter<editorCommon.IScrollEvent> = this._register(new Emitter<editorCommon.IScrollEvent>({ deliveryQueue: this._deliveryQueue }));
181
public readonly onDidScrollChange: Event<editorCommon.IScrollEvent> = this._onDidScrollChange.event;
182
183
private readonly _onDidChangeViewZones: Emitter<void> = this._register(new Emitter<void>({ deliveryQueue: this._deliveryQueue }));
184
public readonly onDidChangeViewZones: Event<void> = this._onDidChangeViewZones.event;
185
186
private readonly _onDidChangeHiddenAreas: Emitter<void> = this._register(new Emitter<void>({ deliveryQueue: this._deliveryQueue }));
187
public readonly onDidChangeHiddenAreas: Event<void> = this._onDidChangeHiddenAreas.event;
188
189
private _updateCounter = 0;
190
191
private readonly _onBeginUpdate: Emitter<void> = this._register(new Emitter<void>());
192
public readonly onBeginUpdate: Event<void> = this._onBeginUpdate.event;
193
194
private readonly _onEndUpdate: Emitter<void> = this._register(new Emitter<void>());
195
public readonly onEndUpdate: Event<void> = this._onEndUpdate.event;
196
197
//#endregion
198
199
public get isSimpleWidget(): boolean {
200
return this._configuration.isSimpleWidget;
201
}
202
203
public get contextMenuId(): MenuId {
204
return this._configuration.contextMenuId;
205
}
206
207
private readonly _telemetryData?: object;
208
209
private readonly _domElement: HTMLElement;
210
private readonly _overflowWidgetsDomNode: HTMLElement | undefined;
211
private readonly _id: number;
212
private readonly _configuration: IEditorConfiguration;
213
private _contributionsDisposable: IDisposable | undefined;
214
215
protected readonly _actions = new Map<string, editorCommon.IEditorAction>();
216
217
// --- Members logically associated to a model
218
protected _modelData: ModelData | null;
219
220
protected readonly _instantiationService: IInstantiationService;
221
protected readonly _contextKeyService: IContextKeyService;
222
get contextKeyService() { return this._contextKeyService; }
223
private readonly _notificationService: INotificationService;
224
protected readonly _codeEditorService: ICodeEditorService;
225
private readonly _commandService: ICommandService;
226
private readonly _themeService: IThemeService;
227
228
private readonly _focusTracker: CodeEditorWidgetFocusTracker;
229
230
private _contentWidgets: { [key: string]: IContentWidgetData };
231
private _overlayWidgets: { [key: string]: IOverlayWidgetData };
232
private _glyphMarginWidgets: { [key: string]: IGlyphMarginWidgetData };
233
234
/**
235
* map from "parent" decoration type to live decoration ids.
236
*/
237
private _decorationTypeKeysToIds: { [decorationTypeKey: string]: string[] };
238
private _decorationTypeSubtypes: { [decorationTypeKey: string]: { [subtype: string]: boolean } };
239
240
private _bannerDomNode: HTMLElement | null = null;
241
242
private _dropIntoEditorDecorations: EditorDecorationsCollection = this.createDecorationsCollection();
243
244
constructor(
245
domElement: HTMLElement,
246
_options: Readonly<IEditorConstructionOptions>,
247
codeEditorWidgetOptions: ICodeEditorWidgetOptions,
248
@IInstantiationService instantiationService: IInstantiationService,
249
@ICodeEditorService codeEditorService: ICodeEditorService,
250
@ICommandService commandService: ICommandService,
251
@IContextKeyService contextKeyService: IContextKeyService,
252
@IThemeService themeService: IThemeService,
253
@INotificationService notificationService: INotificationService,
254
@IAccessibilityService accessibilityService: IAccessibilityService,
255
@ILanguageConfigurationService private readonly languageConfigurationService: ILanguageConfigurationService,
256
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
257
) {
258
super();
259
codeEditorService.willCreateCodeEditor();
260
261
const options = { ..._options };
262
263
this._domElement = domElement;
264
this._overflowWidgetsDomNode = options.overflowWidgetsDomNode;
265
delete options.overflowWidgetsDomNode;
266
this._id = (++EDITOR_ID);
267
this._decorationTypeKeysToIds = {};
268
this._decorationTypeSubtypes = {};
269
this._telemetryData = codeEditorWidgetOptions.telemetryData;
270
271
this._configuration = this._register(this._createConfiguration(codeEditorWidgetOptions.isSimpleWidget || false,
272
codeEditorWidgetOptions.contextMenuId ?? (codeEditorWidgetOptions.isSimpleWidget ? MenuId.SimpleEditorContext : MenuId.EditorContext),
273
options, accessibilityService));
274
this._register(this._configuration.onDidChange((e) => {
275
this._onDidChangeConfiguration.fire(e);
276
277
const options = this._configuration.options;
278
if (e.hasChanged(EditorOption.layoutInfo)) {
279
const layoutInfo = options.get(EditorOption.layoutInfo);
280
this._onDidLayoutChange.fire(layoutInfo);
281
}
282
}));
283
284
this._contextKeyService = this._register(contextKeyService.createScoped(this._domElement));
285
this._notificationService = notificationService;
286
this._codeEditorService = codeEditorService;
287
this._commandService = commandService;
288
this._themeService = themeService;
289
this._register(new EditorContextKeysManager(this, this._contextKeyService));
290
this._register(new EditorModeContext(this, this._contextKeyService, languageFeaturesService));
291
292
this._instantiationService = this._register(instantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService])));
293
294
this._modelData = null;
295
296
this._focusTracker = new CodeEditorWidgetFocusTracker(domElement, this._overflowWidgetsDomNode);
297
this._register(this._focusTracker.onChange(() => {
298
this._editorWidgetFocus.setValue(this._focusTracker.hasFocus());
299
}));
300
301
this._contentWidgets = {};
302
this._overlayWidgets = {};
303
this._glyphMarginWidgets = {};
304
305
let contributions: IEditorContributionDescription[];
306
if (Array.isArray(codeEditorWidgetOptions.contributions)) {
307
contributions = codeEditorWidgetOptions.contributions;
308
} else {
309
contributions = EditorExtensionsRegistry.getEditorContributions();
310
}
311
this._contributions.initialize(this, contributions, this._instantiationService);
312
313
for (const action of EditorExtensionsRegistry.getEditorActions()) {
314
if (this._actions.has(action.id)) {
315
onUnexpectedError(new Error(`Cannot have two actions with the same id ${action.id}`));
316
continue;
317
}
318
const internalAction = new InternalEditorAction(
319
action.id,
320
action.label,
321
action.alias,
322
action.metadata,
323
action.precondition ?? undefined,
324
(args: unknown): Promise<void> => {
325
return this._instantiationService.invokeFunction((accessor) => {
326
return Promise.resolve(action.runEditorCommand(accessor, this, args));
327
});
328
},
329
this._contextKeyService
330
);
331
this._actions.set(internalAction.id, internalAction);
332
}
333
334
const isDropIntoEnabled = () => {
335
return !this._configuration.options.get(EditorOption.readOnly)
336
&& this._configuration.options.get(EditorOption.dropIntoEditor).enabled;
337
};
338
339
this._register(new dom.DragAndDropObserver(this._domElement, {
340
onDragOver: e => {
341
if (!isDropIntoEnabled()) {
342
return;
343
}
344
345
const target = this.getTargetAtClientPoint(e.clientX, e.clientY);
346
if (target?.position) {
347
this.showDropIndicatorAt(target.position);
348
}
349
},
350
onDrop: async e => {
351
if (!isDropIntoEnabled()) {
352
return;
353
}
354
355
this.removeDropIndicator();
356
357
if (!e.dataTransfer) {
358
return;
359
}
360
361
const target = this.getTargetAtClientPoint(e.clientX, e.clientY);
362
if (target?.position) {
363
this._onDropIntoEditor.fire({ position: target.position, event: e });
364
}
365
},
366
onDragLeave: () => {
367
this.removeDropIndicator();
368
},
369
onDragEnd: () => {
370
this.removeDropIndicator();
371
},
372
}));
373
374
this._codeEditorService.addCodeEditor(this);
375
}
376
377
public writeScreenReaderContent(reason: string): void {
378
this._modelData?.view.writeScreenReaderContent(reason);
379
}
380
381
protected _createConfiguration(isSimpleWidget: boolean, contextMenuId: MenuId, options: Readonly<IEditorConstructionOptions>, accessibilityService: IAccessibilityService): EditorConfiguration {
382
return new EditorConfiguration(isSimpleWidget, contextMenuId, options, this._domElement, accessibilityService);
383
}
384
385
public getId(): string {
386
return this.getEditorType() + ':' + this._id;
387
}
388
389
public getEditorType(): string {
390
return editorCommon.EditorType.ICodeEditor;
391
}
392
393
public override dispose(): void {
394
this._codeEditorService.removeCodeEditor(this);
395
396
this._focusTracker.dispose();
397
this._actions.clear();
398
this._contentWidgets = {};
399
this._overlayWidgets = {};
400
401
this._removeDecorationTypes();
402
this._postDetachModelCleanup(this._detachModel());
403
404
this._onDidDispose.fire();
405
406
super.dispose();
407
}
408
409
public invokeWithinContext<T>(fn: (accessor: ServicesAccessor) => T): T {
410
return this._instantiationService.invokeFunction(fn);
411
}
412
413
public updateOptions(newOptions: Readonly<IEditorOptions> | undefined): void {
414
this._configuration.updateOptions(newOptions || {});
415
}
416
417
public getOptions(): IComputedEditorOptions {
418
return this._configuration.options;
419
}
420
421
public getOption<T extends EditorOption>(id: T): FindComputedEditorOptionValueById<T> {
422
return this._configuration.options.get(id);
423
}
424
425
public getRawOptions(): IEditorOptions {
426
return this._configuration.getRawOptions();
427
}
428
429
public getOverflowWidgetsDomNode(): HTMLElement | undefined {
430
return this._overflowWidgetsDomNode;
431
}
432
433
public getConfiguredWordAtPosition(position: Position): IWordAtPosition | null {
434
if (!this._modelData) {
435
return null;
436
}
437
return WordOperations.getWordAtPosition(this._modelData.model, this._configuration.options.get(EditorOption.wordSeparators), this._configuration.options.get(EditorOption.wordSegmenterLocales), position);
438
}
439
440
public getValue(options: { preserveBOM: boolean; lineEnding: string } | null = null): string {
441
if (!this._modelData) {
442
return '';
443
}
444
445
const preserveBOM: boolean = (options && options.preserveBOM) ? true : false;
446
let eolPreference = EndOfLinePreference.TextDefined;
447
if (options && options.lineEnding && options.lineEnding === '\n') {
448
eolPreference = EndOfLinePreference.LF;
449
} else if (options && options.lineEnding && options.lineEnding === '\r\n') {
450
eolPreference = EndOfLinePreference.CRLF;
451
}
452
return this._modelData.model.getValue(eolPreference, preserveBOM);
453
}
454
455
public setValue(newValue: string): void {
456
try {
457
this._beginUpdate();
458
if (!this._modelData) {
459
return;
460
}
461
this._modelData.model.setValue(newValue);
462
} finally {
463
this._endUpdate();
464
}
465
}
466
467
public getModel(): ITextModel | null {
468
if (!this._modelData) {
469
return null;
470
}
471
return this._modelData.model;
472
}
473
474
public setModel(_model: ITextModel | editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null = null): void {
475
try {
476
this._beginUpdate();
477
const model = <ITextModel | null>_model;
478
if (this._modelData === null && model === null) {
479
// Current model is the new model
480
return;
481
}
482
if (this._modelData && this._modelData.model === model) {
483
// Current model is the new model
484
return;
485
}
486
487
const e: editorCommon.IModelChangedEvent = {
488
oldModelUrl: this._modelData?.model.uri || null,
489
newModelUrl: model?.uri || null
490
};
491
this._onWillChangeModel.fire(e);
492
493
const hasTextFocus = this.hasTextFocus();
494
const detachedModel = this._detachModel();
495
this._attachModel(model);
496
if (hasTextFocus && this.hasModel()) {
497
this.focus();
498
}
499
500
this._removeDecorationTypes();
501
this._onDidChangeModel.fire(e);
502
this._postDetachModelCleanup(detachedModel);
503
504
this._contributionsDisposable = this._contributions.onAfterModelAttached();
505
} finally {
506
this._endUpdate();
507
}
508
}
509
510
private _removeDecorationTypes(): void {
511
this._decorationTypeKeysToIds = {};
512
if (this._decorationTypeSubtypes) {
513
for (const decorationType in this._decorationTypeSubtypes) {
514
const subTypes = this._decorationTypeSubtypes[decorationType];
515
for (const subType in subTypes) {
516
this._removeDecorationType(decorationType + '-' + subType);
517
}
518
}
519
this._decorationTypeSubtypes = {};
520
}
521
}
522
523
public getVisibleRanges(): Range[] {
524
if (!this._modelData) {
525
return [];
526
}
527
return this._modelData.viewModel.getVisibleRanges();
528
}
529
530
public getVisibleRangesPlusViewportAboveBelow(): Range[] {
531
if (!this._modelData) {
532
return [];
533
}
534
return this._modelData.viewModel.getVisibleRangesPlusViewportAboveBelow();
535
}
536
537
public getWhitespaces(): IEditorWhitespace[] {
538
if (!this._modelData) {
539
return [];
540
}
541
return this._modelData.viewModel.viewLayout.getWhitespaces();
542
}
543
544
private static _getVerticalOffsetAfterPosition(modelData: ModelData, modelLineNumber: number, modelColumn: number, includeViewZones: boolean): number {
545
const modelPosition = modelData.model.validatePosition({
546
lineNumber: modelLineNumber,
547
column: modelColumn
548
});
549
const viewPosition = modelData.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
550
return modelData.viewModel.viewLayout.getVerticalOffsetAfterLineNumber(viewPosition.lineNumber, includeViewZones);
551
}
552
553
public getTopForLineNumber(lineNumber: number, includeViewZones: boolean = false): number {
554
if (!this._modelData) {
555
return -1;
556
}
557
return CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, lineNumber, 1, includeViewZones);
558
}
559
560
public getTopForPosition(lineNumber: number, column: number): number {
561
if (!this._modelData) {
562
return -1;
563
}
564
return CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, lineNumber, column, false);
565
}
566
567
private static _getVerticalOffsetForPosition(modelData: ModelData, modelLineNumber: number, modelColumn: number, includeViewZones: boolean = false): number {
568
const modelPosition = modelData.model.validatePosition({
569
lineNumber: modelLineNumber,
570
column: modelColumn
571
});
572
const viewPosition = modelData.viewModel.coordinatesConverter.convertModelPositionToViewPosition(modelPosition);
573
return modelData.viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber, includeViewZones);
574
}
575
576
public getBottomForLineNumber(lineNumber: number, includeViewZones: boolean = false): number {
577
if (!this._modelData) {
578
return -1;
579
}
580
const maxCol = this._modelData.model.getLineMaxColumn(lineNumber);
581
return CodeEditorWidget._getVerticalOffsetAfterPosition(this._modelData, lineNumber, maxCol, includeViewZones);
582
}
583
584
public setHiddenAreas(ranges: IRange[], source?: unknown): void {
585
this._modelData?.viewModel.setHiddenAreas(ranges.map(r => Range.lift(r)), source);
586
}
587
588
public getVisibleColumnFromPosition(rawPosition: IPosition): number {
589
if (!this._modelData) {
590
return rawPosition.column;
591
}
592
593
const position = this._modelData.model.validatePosition(rawPosition);
594
const tabSize = this._modelData.model.getOptions().tabSize;
595
596
return CursorColumns.visibleColumnFromColumn(this._modelData.model.getLineContent(position.lineNumber), position.column, tabSize) + 1;
597
}
598
599
public getStatusbarColumn(rawPosition: IPosition): number {
600
if (!this._modelData) {
601
return rawPosition.column;
602
}
603
604
const position = this._modelData.model.validatePosition(rawPosition);
605
const tabSize = this._modelData.model.getOptions().tabSize;
606
607
return CursorColumns.toStatusbarColumn(this._modelData.model.getLineContent(position.lineNumber), position.column, tabSize);
608
}
609
610
public getPosition(): Position | null {
611
if (!this._modelData) {
612
return null;
613
}
614
return this._modelData.viewModel.getPosition();
615
}
616
617
public setPosition(position: IPosition, source: string = 'api'): void {
618
if (!this._modelData) {
619
return;
620
}
621
if (!Position.isIPosition(position)) {
622
throw new Error('Invalid arguments');
623
}
624
this._modelData.viewModel.setSelections(source, [{
625
selectionStartLineNumber: position.lineNumber,
626
selectionStartColumn: position.column,
627
positionLineNumber: position.lineNumber,
628
positionColumn: position.column
629
}]);
630
}
631
632
private _sendRevealRange(modelRange: Range, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {
633
if (!this._modelData) {
634
return;
635
}
636
if (!Range.isIRange(modelRange)) {
637
throw new Error('Invalid arguments');
638
}
639
const validatedModelRange = this._modelData.model.validateRange(modelRange);
640
const viewRange = this._modelData.viewModel.coordinatesConverter.convertModelRangeToViewRange(validatedModelRange);
641
642
this._modelData.viewModel.revealRange('api', revealHorizontal, viewRange, verticalType, scrollType);
643
}
644
645
public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
646
this._revealLine(lineNumber, VerticalRevealType.Simple, scrollType);
647
}
648
649
public revealLineInCenter(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
650
this._revealLine(lineNumber, VerticalRevealType.Center, scrollType);
651
}
652
653
public revealLineInCenterIfOutsideViewport(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
654
this._revealLine(lineNumber, VerticalRevealType.CenterIfOutsideViewport, scrollType);
655
}
656
657
public revealLineNearTop(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
658
this._revealLine(lineNumber, VerticalRevealType.NearTop, scrollType);
659
}
660
661
private _revealLine(lineNumber: number, revealType: VerticalRevealType, scrollType: editorCommon.ScrollType): void {
662
if (typeof lineNumber !== 'number') {
663
throw new Error('Invalid arguments');
664
}
665
666
this._sendRevealRange(
667
new Range(lineNumber, 1, lineNumber, 1),
668
revealType,
669
false,
670
scrollType
671
);
672
}
673
674
public revealPosition(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
675
this._revealPosition(
676
position,
677
VerticalRevealType.Simple,
678
true,
679
scrollType
680
);
681
}
682
683
public revealPositionInCenter(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
684
this._revealPosition(
685
position,
686
VerticalRevealType.Center,
687
true,
688
scrollType
689
);
690
}
691
692
public revealPositionInCenterIfOutsideViewport(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
693
this._revealPosition(
694
position,
695
VerticalRevealType.CenterIfOutsideViewport,
696
true,
697
scrollType
698
);
699
}
700
701
public revealPositionNearTop(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
702
this._revealPosition(
703
position,
704
VerticalRevealType.NearTop,
705
true,
706
scrollType
707
);
708
}
709
710
private _revealPosition(position: IPosition, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {
711
if (!Position.isIPosition(position)) {
712
throw new Error('Invalid arguments');
713
}
714
715
this._sendRevealRange(
716
new Range(position.lineNumber, position.column, position.lineNumber, position.column),
717
verticalType,
718
revealHorizontal,
719
scrollType
720
);
721
}
722
723
public getSelection(): Selection | null {
724
if (!this._modelData) {
725
return null;
726
}
727
return this._modelData.viewModel.getSelection();
728
}
729
730
public getSelections(): Selection[] | null {
731
if (!this._modelData) {
732
return null;
733
}
734
return this._modelData.viewModel.getSelections();
735
}
736
737
public setSelection(range: IRange, source?: string): void;
738
public setSelection(editorRange: Range, source?: string): void;
739
public setSelection(selection: ISelection, source?: string): void;
740
public setSelection(editorSelection: Selection, source?: string): void;
741
public setSelection(something: any, source: string = 'api'): void {
742
const isSelection = Selection.isISelection(something);
743
const isRange = Range.isIRange(something);
744
745
if (!isSelection && !isRange) {
746
throw new Error('Invalid arguments');
747
}
748
749
if (isSelection) {
750
this._setSelectionImpl(<ISelection>something, source);
751
} else if (isRange) {
752
// act as if it was an IRange
753
const selection: ISelection = {
754
selectionStartLineNumber: something.startLineNumber,
755
selectionStartColumn: something.startColumn,
756
positionLineNumber: something.endLineNumber,
757
positionColumn: something.endColumn
758
};
759
this._setSelectionImpl(selection, source);
760
}
761
}
762
763
private _setSelectionImpl(sel: ISelection, source: string): void {
764
if (!this._modelData) {
765
return;
766
}
767
const selection = new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn);
768
this._modelData.viewModel.setSelections(source, [selection]);
769
}
770
771
public revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
772
this._revealLines(
773
startLineNumber,
774
endLineNumber,
775
VerticalRevealType.Simple,
776
scrollType
777
);
778
}
779
780
public revealLinesInCenter(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
781
this._revealLines(
782
startLineNumber,
783
endLineNumber,
784
VerticalRevealType.Center,
785
scrollType
786
);
787
}
788
789
public revealLinesInCenterIfOutsideViewport(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
790
this._revealLines(
791
startLineNumber,
792
endLineNumber,
793
VerticalRevealType.CenterIfOutsideViewport,
794
scrollType
795
);
796
}
797
798
public revealLinesNearTop(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
799
this._revealLines(
800
startLineNumber,
801
endLineNumber,
802
VerticalRevealType.NearTop,
803
scrollType
804
);
805
}
806
807
private _revealLines(startLineNumber: number, endLineNumber: number, verticalType: VerticalRevealType, scrollType: editorCommon.ScrollType): void {
808
if (typeof startLineNumber !== 'number' || typeof endLineNumber !== 'number') {
809
throw new Error('Invalid arguments');
810
}
811
812
this._sendRevealRange(
813
new Range(startLineNumber, 1, endLineNumber, 1),
814
verticalType,
815
false,
816
scrollType
817
);
818
}
819
820
public revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void {
821
this._revealRange(
822
range,
823
revealVerticalInCenter ? VerticalRevealType.Center : VerticalRevealType.Simple,
824
revealHorizontal,
825
scrollType
826
);
827
}
828
829
public revealRangeInCenter(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
830
this._revealRange(
831
range,
832
VerticalRevealType.Center,
833
true,
834
scrollType
835
);
836
}
837
838
public revealRangeInCenterIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
839
this._revealRange(
840
range,
841
VerticalRevealType.CenterIfOutsideViewport,
842
true,
843
scrollType
844
);
845
}
846
847
public revealRangeNearTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
848
this._revealRange(
849
range,
850
VerticalRevealType.NearTop,
851
true,
852
scrollType
853
);
854
}
855
856
public revealRangeNearTopIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
857
this._revealRange(
858
range,
859
VerticalRevealType.NearTopIfOutsideViewport,
860
true,
861
scrollType
862
);
863
}
864
865
public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
866
this._revealRange(
867
range,
868
VerticalRevealType.Top,
869
true,
870
scrollType
871
);
872
}
873
874
private _revealRange(range: IRange, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {
875
if (!Range.isIRange(range)) {
876
throw new Error('Invalid arguments');
877
}
878
879
this._sendRevealRange(
880
Range.lift(range),
881
verticalType,
882
revealHorizontal,
883
scrollType
884
);
885
}
886
887
public setSelections(ranges: readonly ISelection[], source: string = 'api', reason = CursorChangeReason.NotSet): void {
888
if (!this._modelData) {
889
return;
890
}
891
if (!ranges || ranges.length === 0) {
892
throw new Error('Invalid arguments');
893
}
894
for (let i = 0, len = ranges.length; i < len; i++) {
895
if (!Selection.isISelection(ranges[i])) {
896
throw new Error('Invalid arguments');
897
}
898
}
899
this._modelData.viewModel.setSelections(source, ranges, reason);
900
}
901
902
public getContentWidth(): number {
903
if (!this._modelData) {
904
return -1;
905
}
906
return this._modelData.viewModel.viewLayout.getContentWidth();
907
}
908
909
public getScrollWidth(): number {
910
if (!this._modelData) {
911
return -1;
912
}
913
return this._modelData.viewModel.viewLayout.getScrollWidth();
914
}
915
public getScrollLeft(): number {
916
if (!this._modelData) {
917
return -1;
918
}
919
return this._modelData.viewModel.viewLayout.getCurrentScrollLeft();
920
}
921
922
public getContentHeight(): number {
923
if (!this._modelData) {
924
return -1;
925
}
926
return this._modelData.viewModel.viewLayout.getContentHeight();
927
}
928
929
public getScrollHeight(): number {
930
if (!this._modelData) {
931
return -1;
932
}
933
return this._modelData.viewModel.viewLayout.getScrollHeight();
934
}
935
public getScrollTop(): number {
936
if (!this._modelData) {
937
return -1;
938
}
939
return this._modelData.viewModel.viewLayout.getCurrentScrollTop();
940
}
941
942
public setScrollLeft(newScrollLeft: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Immediate): void {
943
if (!this._modelData) {
944
return;
945
}
946
if (typeof newScrollLeft !== 'number') {
947
throw new Error('Invalid arguments');
948
}
949
this._modelData.viewModel.viewLayout.setScrollPosition({
950
scrollLeft: newScrollLeft
951
}, scrollType);
952
}
953
public setScrollTop(newScrollTop: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Immediate): void {
954
if (!this._modelData) {
955
return;
956
}
957
if (typeof newScrollTop !== 'number') {
958
throw new Error('Invalid arguments');
959
}
960
this._modelData.viewModel.viewLayout.setScrollPosition({
961
scrollTop: newScrollTop
962
}, scrollType);
963
}
964
public setScrollPosition(position: editorCommon.INewScrollPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Immediate): void {
965
if (!this._modelData) {
966
return;
967
}
968
this._modelData.viewModel.viewLayout.setScrollPosition(position, scrollType);
969
}
970
public hasPendingScrollAnimation(): boolean {
971
if (!this._modelData) {
972
return false;
973
}
974
return this._modelData.viewModel.viewLayout.hasPendingScrollAnimation();
975
}
976
977
public saveViewState(): editorCommon.ICodeEditorViewState | null {
978
if (!this._modelData) {
979
return null;
980
}
981
const contributionsState = this._contributions.saveViewState();
982
const cursorState = this._modelData.viewModel.saveCursorState();
983
const viewState = this._modelData.viewModel.saveState();
984
return {
985
cursorState: cursorState,
986
viewState: viewState,
987
contributionsState: contributionsState
988
};
989
}
990
991
public restoreViewState(s: editorCommon.IEditorViewState | null): void {
992
if (!this._modelData || !this._modelData.hasRealView) {
993
return;
994
}
995
const codeEditorState = s as editorCommon.ICodeEditorViewState | null;
996
if (codeEditorState && codeEditorState.cursorState && codeEditorState.viewState) {
997
const cursorState = <any>codeEditorState.cursorState;
998
if (Array.isArray(cursorState)) {
999
if (cursorState.length > 0) {
1000
this._modelData.viewModel.restoreCursorState(<editorCommon.ICursorState[]>cursorState);
1001
}
1002
} else {
1003
// Backwards compatibility
1004
this._modelData.viewModel.restoreCursorState([<editorCommon.ICursorState>cursorState]);
1005
}
1006
1007
this._contributions.restoreViewState(codeEditorState.contributionsState || {});
1008
const reducedState = this._modelData.viewModel.reduceRestoreState(codeEditorState.viewState);
1009
this._modelData.view.restoreState(reducedState);
1010
}
1011
}
1012
1013
public handleInitialized(): void {
1014
this._getViewModel()?.visibleLinesStabilized();
1015
}
1016
1017
public onVisible(): void {
1018
this._modelData?.view.refreshFocusState();
1019
}
1020
1021
public onHide(): void {
1022
this._modelData?.view.refreshFocusState();
1023
this._focusTracker.refreshState();
1024
}
1025
1026
public getContribution<T extends editorCommon.IEditorContribution>(id: string): T | null {
1027
return this._contributions.get(id) as T | null;
1028
}
1029
1030
public getActions(): editorCommon.IEditorAction[] {
1031
return Array.from(this._actions.values());
1032
}
1033
1034
public getSupportedActions(): editorCommon.IEditorAction[] {
1035
let result = this.getActions();
1036
1037
result = result.filter(action => action.isSupported());
1038
1039
return result;
1040
}
1041
1042
public getAction(id: string): editorCommon.IEditorAction | null {
1043
return this._actions.get(id) || null;
1044
}
1045
1046
public trigger(source: string | null | undefined, handlerId: string, payload: any): void {
1047
payload = payload || {};
1048
1049
try {
1050
this._beginUpdate();
1051
1052
switch (handlerId) {
1053
case editorCommon.Handler.CompositionStart:
1054
this._startComposition();
1055
return;
1056
case editorCommon.Handler.CompositionEnd:
1057
this._endComposition(source);
1058
return;
1059
case editorCommon.Handler.Type: {
1060
const args = <Partial<editorCommon.TypePayload>>payload;
1061
this._type(source, args.text || '');
1062
return;
1063
}
1064
case editorCommon.Handler.ReplacePreviousChar: {
1065
const args = <Partial<editorCommon.ReplacePreviousCharPayload>>payload;
1066
this._compositionType(source, args.text || '', args.replaceCharCnt || 0, 0, 0);
1067
return;
1068
}
1069
case editorCommon.Handler.CompositionType: {
1070
const args = <Partial<editorCommon.CompositionTypePayload>>payload;
1071
this._compositionType(source, args.text || '', args.replacePrevCharCnt || 0, args.replaceNextCharCnt || 0, args.positionDelta || 0);
1072
return;
1073
}
1074
case editorCommon.Handler.Paste: {
1075
const args = <Partial<editorBrowser.PastePayload>>payload;
1076
this._paste(source, args.text || '', args.pasteOnNewLine || false, args.multicursorText || null, args.mode || null, args.clipboardEvent);
1077
return;
1078
}
1079
case editorCommon.Handler.Cut:
1080
this._cut(source);
1081
return;
1082
}
1083
1084
const action = this.getAction(handlerId);
1085
if (action) {
1086
Promise.resolve(action.run(payload)).then(undefined, onUnexpectedError);
1087
return;
1088
}
1089
1090
if (!this._modelData) {
1091
return;
1092
}
1093
1094
if (this._triggerEditorCommand(source, handlerId, payload)) {
1095
return;
1096
}
1097
1098
this._triggerCommand(handlerId, payload);
1099
} finally {
1100
this._endUpdate();
1101
}
1102
}
1103
1104
protected _triggerCommand(handlerId: string, payload: any): void {
1105
this._commandService.executeCommand(handlerId, payload);
1106
}
1107
1108
private _startComposition(): void {
1109
if (!this._modelData) {
1110
return;
1111
}
1112
this._modelData.viewModel.startComposition();
1113
this._onDidCompositionStart.fire();
1114
}
1115
1116
private _endComposition(source: string | null | undefined): void {
1117
if (!this._modelData) {
1118
return;
1119
}
1120
this._modelData.viewModel.endComposition(source);
1121
this._onDidCompositionEnd.fire();
1122
}
1123
1124
private _type(source: string | null | undefined, text: string): void {
1125
if (!this._modelData || text.length === 0) {
1126
return;
1127
}
1128
if (source === 'keyboard') {
1129
this._onWillType.fire(text);
1130
}
1131
this._modelData.viewModel.type(text, source);
1132
if (source === 'keyboard') {
1133
this._onDidType.fire(text);
1134
}
1135
}
1136
1137
private _compositionType(source: string | null | undefined, text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void {
1138
if (!this._modelData) {
1139
return;
1140
}
1141
this._modelData.viewModel.compositionType(text, replacePrevCharCnt, replaceNextCharCnt, positionDelta, source);
1142
}
1143
1144
private _paste(source: string | null | undefined, text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null, clipboardEvent?: ClipboardEvent): void {
1145
if (!this._modelData) {
1146
return;
1147
}
1148
const viewModel = this._modelData.viewModel;
1149
const startPosition = viewModel.getSelection().getStartPosition();
1150
viewModel.paste(text, pasteOnNewLine, multicursorText, source);
1151
const endPosition = viewModel.getSelection().getStartPosition();
1152
if (source === 'keyboard') {
1153
this._onDidPaste.fire({
1154
clipboardEvent,
1155
range: new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column),
1156
languageId: mode
1157
});
1158
}
1159
}
1160
1161
private _cut(source: string | null | undefined): void {
1162
if (!this._modelData) {
1163
return;
1164
}
1165
this._modelData.viewModel.cut(source);
1166
}
1167
1168
private _triggerEditorCommand(source: string | null | undefined, handlerId: string, payload: any): boolean {
1169
const command = EditorExtensionsRegistry.getEditorCommand(handlerId);
1170
if (command) {
1171
payload = payload || {};
1172
payload.source = source;
1173
this._instantiationService.invokeFunction((accessor) => {
1174
Promise.resolve(command.runEditorCommand(accessor, this, payload)).then(undefined, onUnexpectedError);
1175
});
1176
return true;
1177
}
1178
1179
return false;
1180
}
1181
1182
public _getViewModel(): IViewModel | null {
1183
if (!this._modelData) {
1184
return null;
1185
}
1186
return this._modelData.viewModel;
1187
}
1188
1189
public pushUndoStop(): boolean {
1190
if (!this._modelData) {
1191
return false;
1192
}
1193
if (this._configuration.options.get(EditorOption.readOnly)) {
1194
// read only editor => sorry!
1195
return false;
1196
}
1197
this._modelData.model.pushStackElement();
1198
return true;
1199
}
1200
1201
public popUndoStop(): boolean {
1202
if (!this._modelData) {
1203
return false;
1204
}
1205
if (this._configuration.options.get(EditorOption.readOnly)) {
1206
// read only editor => sorry!
1207
return false;
1208
}
1209
this._modelData.model.popStackElement();
1210
return true;
1211
}
1212
1213
public executeEdits(source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], endCursorState?: ICursorStateComputer | Selection[]): boolean {
1214
if (!this._modelData) {
1215
return false;
1216
}
1217
if (this._configuration.options.get(EditorOption.readOnly)) {
1218
// read only editor => sorry!
1219
return false;
1220
}
1221
1222
let cursorStateComputer: ICursorStateComputer;
1223
if (!endCursorState) {
1224
cursorStateComputer = () => null;
1225
} else if (Array.isArray(endCursorState)) {
1226
cursorStateComputer = () => endCursorState;
1227
} else {
1228
cursorStateComputer = endCursorState;
1229
}
1230
1231
this._modelData.viewModel.executeEdits(source, edits, cursorStateComputer);
1232
return true;
1233
}
1234
1235
public executeCommand(source: string | null | undefined, command: editorCommon.ICommand): void {
1236
if (!this._modelData) {
1237
return;
1238
}
1239
this._modelData.viewModel.executeCommand(command, source);
1240
}
1241
1242
public executeCommands(source: string | null | undefined, commands: editorCommon.ICommand[]): void {
1243
if (!this._modelData) {
1244
return;
1245
}
1246
this._modelData.viewModel.executeCommands(commands, source);
1247
}
1248
1249
public createDecorationsCollection(decorations?: IModelDeltaDecoration[]): EditorDecorationsCollection {
1250
return new EditorDecorationsCollection(this, decorations);
1251
}
1252
1253
public changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
1254
if (!this._modelData) {
1255
// callback will not be called
1256
return null;
1257
}
1258
return this._modelData.model.changeDecorations(callback, this._id);
1259
}
1260
1261
public getLineDecorations(lineNumber: number): IModelDecoration[] | null {
1262
if (!this._modelData) {
1263
return null;
1264
}
1265
return this._modelData.model.getLineDecorations(lineNumber, this._id, filterValidationDecorations(this._configuration.options));
1266
}
1267
1268
public getDecorationsInRange(range: Range): IModelDecoration[] | null {
1269
if (!this._modelData) {
1270
return null;
1271
}
1272
return this._modelData.model.getDecorationsInRange(range, this._id, filterValidationDecorations(this._configuration.options));
1273
}
1274
1275
/**
1276
* @deprecated
1277
*/
1278
public deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[] {
1279
if (!this._modelData) {
1280
return [];
1281
}
1282
1283
if (oldDecorations.length === 0 && newDecorations.length === 0) {
1284
return oldDecorations;
1285
}
1286
1287
return this._modelData.model.deltaDecorations(oldDecorations, newDecorations, this._id);
1288
}
1289
1290
public removeDecorations(decorationIds: string[]): void {
1291
if (!this._modelData || decorationIds.length === 0) {
1292
return;
1293
}
1294
1295
this._modelData.model.changeDecorations((changeAccessor) => {
1296
changeAccessor.deltaDecorations(decorationIds, []);
1297
});
1298
}
1299
1300
public setDecorationsByType(description: string, decorationTypeKey: string, decorationOptions: editorCommon.IDecorationOptions[]): void {
1301
1302
const newDecorationsSubTypes: { [key: string]: boolean } = {};
1303
const oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {};
1304
this._decorationTypeSubtypes[decorationTypeKey] = newDecorationsSubTypes;
1305
1306
const newModelDecorations: IModelDeltaDecoration[] = [];
1307
1308
for (const decorationOption of decorationOptions) {
1309
let typeKey = decorationTypeKey;
1310
if (decorationOption.renderOptions) {
1311
// identify custom render options by a hash code over all keys and values
1312
// For custom render options register a decoration type if necessary
1313
const subType = hash(decorationOption.renderOptions).toString(16);
1314
// The fact that `decorationTypeKey` appears in the typeKey has no influence
1315
// it is just a mechanism to get predictable and unique keys (repeatable for the same options and unique across clients)
1316
typeKey = decorationTypeKey + '-' + subType;
1317
if (!oldDecorationsSubTypes[subType] && !newDecorationsSubTypes[subType]) {
1318
// decoration type did not exist before, register new one
1319
this._registerDecorationType(description, typeKey, decorationOption.renderOptions, decorationTypeKey);
1320
}
1321
newDecorationsSubTypes[subType] = true;
1322
}
1323
const opts = this._resolveDecorationOptions(typeKey, !!decorationOption.hoverMessage);
1324
if (decorationOption.hoverMessage) {
1325
opts.hoverMessage = decorationOption.hoverMessage;
1326
}
1327
newModelDecorations.push({ range: decorationOption.range, options: opts });
1328
}
1329
1330
// remove decoration sub types that are no longer used, deregister decoration type if necessary
1331
for (const subType in oldDecorationsSubTypes) {
1332
if (!newDecorationsSubTypes[subType]) {
1333
this._removeDecorationType(decorationTypeKey + '-' + subType);
1334
}
1335
}
1336
1337
// update all decorations
1338
const oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey] || [];
1339
this.changeDecorations(accessor => this._decorationTypeKeysToIds[decorationTypeKey] = accessor.deltaDecorations(oldDecorationsIds, newModelDecorations));
1340
}
1341
1342
public setDecorationsByTypeFast(decorationTypeKey: string, ranges: IRange[]): void {
1343
1344
// remove decoration sub types that are no longer used, deregister decoration type if necessary
1345
const oldDecorationsSubTypes = this._decorationTypeSubtypes[decorationTypeKey] || {};
1346
for (const subType in oldDecorationsSubTypes) {
1347
this._removeDecorationType(decorationTypeKey + '-' + subType);
1348
}
1349
this._decorationTypeSubtypes[decorationTypeKey] = {};
1350
1351
const opts = ModelDecorationOptions.createDynamic(this._resolveDecorationOptions(decorationTypeKey, false));
1352
const newModelDecorations: IModelDeltaDecoration[] = new Array<IModelDeltaDecoration>(ranges.length);
1353
for (let i = 0, len = ranges.length; i < len; i++) {
1354
newModelDecorations[i] = { range: ranges[i], options: opts };
1355
}
1356
1357
// update all decorations
1358
const oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey] || [];
1359
this.changeDecorations(accessor => this._decorationTypeKeysToIds[decorationTypeKey] = accessor.deltaDecorations(oldDecorationsIds, newModelDecorations));
1360
}
1361
1362
public removeDecorationsByType(decorationTypeKey: string): void {
1363
// remove decorations for type and sub type
1364
const oldDecorationsIds = this._decorationTypeKeysToIds[decorationTypeKey];
1365
if (oldDecorationsIds) {
1366
this.changeDecorations(accessor => accessor.deltaDecorations(oldDecorationsIds, []));
1367
}
1368
if (this._decorationTypeKeysToIds.hasOwnProperty(decorationTypeKey)) {
1369
delete this._decorationTypeKeysToIds[decorationTypeKey];
1370
}
1371
if (this._decorationTypeSubtypes.hasOwnProperty(decorationTypeKey)) {
1372
delete this._decorationTypeSubtypes[decorationTypeKey];
1373
}
1374
}
1375
1376
public getLayoutInfo(): EditorLayoutInfo {
1377
const options = this._configuration.options;
1378
const layoutInfo = options.get(EditorOption.layoutInfo);
1379
return layoutInfo;
1380
}
1381
1382
public createOverviewRuler(cssClassName: string): editorBrowser.IOverviewRuler | null {
1383
if (!this._modelData || !this._modelData.hasRealView) {
1384
return null;
1385
}
1386
return this._modelData.view.createOverviewRuler(cssClassName);
1387
}
1388
1389
public getContainerDomNode(): HTMLElement {
1390
return this._domElement;
1391
}
1392
1393
public getDomNode(): HTMLElement | null {
1394
if (!this._modelData || !this._modelData.hasRealView) {
1395
return null;
1396
}
1397
return this._modelData.view.domNode.domNode;
1398
}
1399
1400
public delegateVerticalScrollbarPointerDown(browserEvent: PointerEvent): void {
1401
if (!this._modelData || !this._modelData.hasRealView) {
1402
return;
1403
}
1404
this._modelData.view.delegateVerticalScrollbarPointerDown(browserEvent);
1405
}
1406
1407
public delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {
1408
if (!this._modelData || !this._modelData.hasRealView) {
1409
return;
1410
}
1411
this._modelData.view.delegateScrollFromMouseWheelEvent(browserEvent);
1412
}
1413
1414
public layout(dimension?: IDimension, postponeRendering: boolean = false): void {
1415
this._configuration.observeContainer(dimension);
1416
if (!postponeRendering) {
1417
this.render();
1418
}
1419
}
1420
1421
public focus(): void {
1422
if (!this._modelData || !this._modelData.hasRealView) {
1423
return;
1424
}
1425
this._modelData.view.focus();
1426
}
1427
1428
public hasTextFocus(): boolean {
1429
if (!this._modelData || !this._modelData.hasRealView) {
1430
return false;
1431
}
1432
return this._modelData.view.isFocused();
1433
}
1434
1435
public hasWidgetFocus(): boolean {
1436
return this._focusTracker && this._focusTracker.hasFocus();
1437
}
1438
1439
public addContentWidget(widget: editorBrowser.IContentWidget): void {
1440
const widgetData: IContentWidgetData = {
1441
widget: widget,
1442
position: widget.getPosition()
1443
};
1444
1445
if (this._contentWidgets.hasOwnProperty(widget.getId())) {
1446
console.warn('Overwriting a content widget with the same id:' + widget.getId());
1447
}
1448
1449
this._contentWidgets[widget.getId()] = widgetData;
1450
1451
if (this._modelData && this._modelData.hasRealView) {
1452
this._modelData.view.addContentWidget(widgetData);
1453
}
1454
}
1455
1456
public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
1457
const widgetId = widget.getId();
1458
if (this._contentWidgets.hasOwnProperty(widgetId)) {
1459
const widgetData = this._contentWidgets[widgetId];
1460
widgetData.position = widget.getPosition();
1461
if (this._modelData && this._modelData.hasRealView) {
1462
this._modelData.view.layoutContentWidget(widgetData);
1463
}
1464
}
1465
}
1466
1467
public removeContentWidget(widget: editorBrowser.IContentWidget): void {
1468
const widgetId = widget.getId();
1469
if (this._contentWidgets.hasOwnProperty(widgetId)) {
1470
const widgetData = this._contentWidgets[widgetId];
1471
delete this._contentWidgets[widgetId];
1472
if (this._modelData && this._modelData.hasRealView) {
1473
this._modelData.view.removeContentWidget(widgetData);
1474
}
1475
}
1476
}
1477
1478
public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
1479
const widgetData: IOverlayWidgetData = {
1480
widget: widget,
1481
position: widget.getPosition()
1482
};
1483
1484
if (this._overlayWidgets.hasOwnProperty(widget.getId())) {
1485
console.warn('Overwriting an overlay widget with the same id.');
1486
}
1487
1488
this._overlayWidgets[widget.getId()] = widgetData;
1489
if (this._modelData && this._modelData.hasRealView) {
1490
this._modelData.view.addOverlayWidget(widgetData);
1491
}
1492
}
1493
1494
public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
1495
const widgetId = widget.getId();
1496
if (this._overlayWidgets.hasOwnProperty(widgetId)) {
1497
const widgetData = this._overlayWidgets[widgetId];
1498
widgetData.position = widget.getPosition();
1499
if (this._modelData && this._modelData.hasRealView) {
1500
this._modelData.view.layoutOverlayWidget(widgetData);
1501
}
1502
}
1503
}
1504
1505
public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
1506
const widgetId = widget.getId();
1507
if (this._overlayWidgets.hasOwnProperty(widgetId)) {
1508
const widgetData = this._overlayWidgets[widgetId];
1509
delete this._overlayWidgets[widgetId];
1510
if (this._modelData && this._modelData.hasRealView) {
1511
this._modelData.view.removeOverlayWidget(widgetData);
1512
}
1513
}
1514
}
1515
1516
public addGlyphMarginWidget(widget: editorBrowser.IGlyphMarginWidget): void {
1517
const widgetData: IGlyphMarginWidgetData = {
1518
widget: widget,
1519
position: widget.getPosition()
1520
};
1521
1522
if (this._glyphMarginWidgets.hasOwnProperty(widget.getId())) {
1523
console.warn('Overwriting a glyph margin widget with the same id.');
1524
}
1525
1526
this._glyphMarginWidgets[widget.getId()] = widgetData;
1527
1528
if (this._modelData && this._modelData.hasRealView) {
1529
this._modelData.view.addGlyphMarginWidget(widgetData);
1530
}
1531
}
1532
1533
public layoutGlyphMarginWidget(widget: editorBrowser.IGlyphMarginWidget): void {
1534
const widgetId = widget.getId();
1535
if (this._glyphMarginWidgets.hasOwnProperty(widgetId)) {
1536
const widgetData = this._glyphMarginWidgets[widgetId];
1537
widgetData.position = widget.getPosition();
1538
if (this._modelData && this._modelData.hasRealView) {
1539
this._modelData.view.layoutGlyphMarginWidget(widgetData);
1540
}
1541
}
1542
}
1543
1544
public removeGlyphMarginWidget(widget: editorBrowser.IGlyphMarginWidget): void {
1545
const widgetId = widget.getId();
1546
if (this._glyphMarginWidgets.hasOwnProperty(widgetId)) {
1547
const widgetData = this._glyphMarginWidgets[widgetId];
1548
delete this._glyphMarginWidgets[widgetId];
1549
if (this._modelData && this._modelData.hasRealView) {
1550
this._modelData.view.removeGlyphMarginWidget(widgetData);
1551
}
1552
}
1553
}
1554
1555
public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
1556
if (!this._modelData || !this._modelData.hasRealView) {
1557
return;
1558
}
1559
this._modelData.view.change(callback);
1560
}
1561
1562
public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget | null {
1563
if (!this._modelData || !this._modelData.hasRealView) {
1564
return null;
1565
}
1566
return this._modelData.view.getTargetAtClientPoint(clientX, clientY);
1567
}
1568
1569
public getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number } | null {
1570
if (!this._modelData || !this._modelData.hasRealView) {
1571
return null;
1572
}
1573
1574
const position = this._modelData.model.validatePosition(rawPosition);
1575
const options = this._configuration.options;
1576
const layoutInfo = options.get(EditorOption.layoutInfo);
1577
1578
const top = CodeEditorWidget._getVerticalOffsetForPosition(this._modelData, position.lineNumber, position.column) - this.getScrollTop();
1579
const left = this._modelData.view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this.getScrollLeft();
1580
1581
return {
1582
top: top,
1583
left: left,
1584
height: options.get(EditorOption.lineHeight)
1585
};
1586
}
1587
1588
public getOffsetForColumn(lineNumber: number, column: number): number {
1589
if (!this._modelData || !this._modelData.hasRealView) {
1590
return -1;
1591
}
1592
return this._modelData.view.getOffsetForColumn(lineNumber, column);
1593
}
1594
1595
public render(forceRedraw: boolean = false): void {
1596
if (!this._modelData || !this._modelData.hasRealView) {
1597
return;
1598
}
1599
this._modelData.viewModel.batchEvents(() => {
1600
this._modelData!.view.render(true, forceRedraw);
1601
});
1602
}
1603
1604
public setAriaOptions(options: editorBrowser.IEditorAriaOptions): void {
1605
if (!this._modelData || !this._modelData.hasRealView) {
1606
return;
1607
}
1608
this._modelData.view.setAriaOptions(options);
1609
}
1610
1611
public applyFontInfo(target: HTMLElement): void {
1612
applyFontInfo(target, this._configuration.options.get(EditorOption.fontInfo));
1613
}
1614
1615
public setBanner(domNode: HTMLElement | null, domNodeHeight: number): void {
1616
if (this._bannerDomNode && this._domElement.contains(this._bannerDomNode)) {
1617
this._bannerDomNode.remove();
1618
}
1619
1620
this._bannerDomNode = domNode;
1621
this._configuration.setReservedHeight(domNode ? domNodeHeight : 0);
1622
1623
if (this._bannerDomNode) {
1624
this._domElement.prepend(this._bannerDomNode);
1625
}
1626
}
1627
1628
protected _attachModel(model: ITextModel | null): void {
1629
if (!model) {
1630
this._modelData = null;
1631
return;
1632
}
1633
1634
const listenersToRemove: IDisposable[] = [];
1635
1636
this._domElement.setAttribute('data-mode-id', model.getLanguageId());
1637
this._configuration.setIsDominatedByLongLines(model.isDominatedByLongLines());
1638
this._configuration.setModelLineCount(model.getLineCount());
1639
1640
const attachedView = model.onBeforeAttached();
1641
1642
const viewModel = new ViewModel(
1643
this._id,
1644
this._configuration,
1645
model,
1646
DOMLineBreaksComputerFactory.create(dom.getWindow(this._domElement)),
1647
MonospaceLineBreaksComputerFactory.create(this._configuration.options),
1648
(callback) => dom.scheduleAtNextAnimationFrame(dom.getWindow(this._domElement), callback),
1649
this.languageConfigurationService,
1650
this._themeService,
1651
attachedView,
1652
{
1653
batchChanges: (cb) => {
1654
try {
1655
this._beginUpdate();
1656
return cb();
1657
} finally {
1658
this._endUpdate();
1659
}
1660
},
1661
}
1662
);
1663
1664
// Someone might destroy the model from under the editor, so prevent any exceptions by setting a null model
1665
listenersToRemove.push(model.onWillDispose(() => this.setModel(null)));
1666
1667
listenersToRemove.push(viewModel.onEvent((e) => {
1668
switch (e.kind) {
1669
case OutgoingViewModelEventKind.ContentSizeChanged:
1670
this._onDidContentSizeChange.fire(e);
1671
break;
1672
case OutgoingViewModelEventKind.FocusChanged:
1673
this._editorTextFocus.setValue(e.hasFocus);
1674
break;
1675
case OutgoingViewModelEventKind.ScrollChanged:
1676
this._onDidScrollChange.fire(e);
1677
break;
1678
case OutgoingViewModelEventKind.ViewZonesChanged:
1679
this._onDidChangeViewZones.fire();
1680
break;
1681
case OutgoingViewModelEventKind.HiddenAreasChanged:
1682
this._onDidChangeHiddenAreas.fire();
1683
break;
1684
case OutgoingViewModelEventKind.ReadOnlyEditAttempt:
1685
this._onDidAttemptReadOnlyEdit.fire();
1686
break;
1687
case OutgoingViewModelEventKind.CursorStateChanged: {
1688
if (e.reachedMaxCursorCount) {
1689
1690
const multiCursorLimit = this.getOption(EditorOption.multiCursorLimit);
1691
const message = nls.localize('cursors.maximum', "The number of cursors has been limited to {0}. Consider using [find and replace](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) for larger changes or increase the editor multi cursor limit setting.", multiCursorLimit);
1692
this._notificationService.prompt(Severity.Warning, message, [
1693
{
1694
label: 'Find and Replace',
1695
run: () => {
1696
this._commandService.executeCommand('editor.action.startFindReplaceAction');
1697
}
1698
},
1699
{
1700
label: nls.localize('goToSetting', 'Increase Multi Cursor Limit'),
1701
run: () => {
1702
this._commandService.executeCommand('workbench.action.openSettings2', {
1703
query: 'editor.multiCursorLimit'
1704
});
1705
}
1706
}
1707
]);
1708
}
1709
1710
const positions: Position[] = [];
1711
for (let i = 0, len = e.selections.length; i < len; i++) {
1712
positions[i] = e.selections[i].getPosition();
1713
}
1714
1715
const e1: ICursorPositionChangedEvent = {
1716
position: positions[0],
1717
secondaryPositions: positions.slice(1),
1718
reason: e.reason,
1719
source: e.source
1720
};
1721
this._onDidChangeCursorPosition.fire(e1);
1722
1723
const e2: ICursorSelectionChangedEvent = {
1724
selection: e.selections[0],
1725
secondarySelections: e.selections.slice(1),
1726
modelVersionId: e.modelVersionId,
1727
oldSelections: e.oldSelections,
1728
oldModelVersionId: e.oldModelVersionId,
1729
source: e.source,
1730
reason: e.reason
1731
};
1732
this._onDidChangeCursorSelection.fire(e2);
1733
1734
break;
1735
}
1736
case OutgoingViewModelEventKind.ModelDecorationsChanged:
1737
this._onDidChangeModelDecorations.fire(e.event);
1738
break;
1739
case OutgoingViewModelEventKind.ModelLanguageChanged:
1740
this._domElement.setAttribute('data-mode-id', model.getLanguageId());
1741
this._onDidChangeModelLanguage.fire(e.event);
1742
break;
1743
case OutgoingViewModelEventKind.ModelLanguageConfigurationChanged:
1744
this._onDidChangeModelLanguageConfiguration.fire(e.event);
1745
break;
1746
case OutgoingViewModelEventKind.ModelContentChanged:
1747
this._onDidChangeModelContent.fire(e.event);
1748
break;
1749
case OutgoingViewModelEventKind.ModelOptionsChanged:
1750
this._onDidChangeModelOptions.fire(e.event);
1751
break;
1752
case OutgoingViewModelEventKind.ModelTokensChanged:
1753
this._onDidChangeModelTokens.fire(e.event);
1754
break;
1755
1756
}
1757
}));
1758
1759
const [view, hasRealView] = this._createView(viewModel);
1760
if (hasRealView) {
1761
this._domElement.appendChild(view.domNode.domNode);
1762
1763
let keys = Object.keys(this._contentWidgets);
1764
for (let i = 0, len = keys.length; i < len; i++) {
1765
const widgetId = keys[i];
1766
view.addContentWidget(this._contentWidgets[widgetId]);
1767
}
1768
1769
keys = Object.keys(this._overlayWidgets);
1770
for (let i = 0, len = keys.length; i < len; i++) {
1771
const widgetId = keys[i];
1772
view.addOverlayWidget(this._overlayWidgets[widgetId]);
1773
}
1774
1775
keys = Object.keys(this._glyphMarginWidgets);
1776
for (let i = 0, len = keys.length; i < len; i++) {
1777
const widgetId = keys[i];
1778
view.addGlyphMarginWidget(this._glyphMarginWidgets[widgetId]);
1779
}
1780
1781
view.render(false, true);
1782
view.domNode.domNode.setAttribute('data-uri', model.uri.toString());
1783
}
1784
1785
this._modelData = new ModelData(model, viewModel, view, hasRealView, listenersToRemove, attachedView);
1786
}
1787
1788
protected _createView(viewModel: ViewModel): [View, boolean] {
1789
let commandDelegate: ICommandDelegate;
1790
if (this.isSimpleWidget) {
1791
commandDelegate = {
1792
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
1793
this._paste('keyboard', text, pasteOnNewLine, multicursorText, mode);
1794
},
1795
type: (text: string) => {
1796
this._type('keyboard', text);
1797
},
1798
compositionType: (text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number) => {
1799
this._compositionType('keyboard', text, replacePrevCharCnt, replaceNextCharCnt, positionDelta);
1800
},
1801
startComposition: () => {
1802
this._startComposition();
1803
},
1804
endComposition: () => {
1805
this._endComposition('keyboard');
1806
},
1807
cut: () => {
1808
this._cut('keyboard');
1809
}
1810
};
1811
} else {
1812
commandDelegate = {
1813
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
1814
const payload: editorBrowser.PastePayload = { text, pasteOnNewLine, multicursorText, mode };
1815
this._commandService.executeCommand(editorCommon.Handler.Paste, payload);
1816
},
1817
type: (text: string) => {
1818
const payload: editorCommon.TypePayload = { text };
1819
this._commandService.executeCommand(editorCommon.Handler.Type, payload);
1820
},
1821
compositionType: (text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number) => {
1822
// Try if possible to go through the existing `replacePreviousChar` command
1823
if (replaceNextCharCnt || positionDelta) {
1824
// must be handled through the new command
1825
const payload: editorCommon.CompositionTypePayload = { text, replacePrevCharCnt, replaceNextCharCnt, positionDelta };
1826
this._commandService.executeCommand(editorCommon.Handler.CompositionType, payload);
1827
} else {
1828
const payload: editorCommon.ReplacePreviousCharPayload = { text, replaceCharCnt: replacePrevCharCnt };
1829
this._commandService.executeCommand(editorCommon.Handler.ReplacePreviousChar, payload);
1830
}
1831
},
1832
startComposition: () => {
1833
this._commandService.executeCommand(editorCommon.Handler.CompositionStart, {});
1834
},
1835
endComposition: () => {
1836
this._commandService.executeCommand(editorCommon.Handler.CompositionEnd, {});
1837
},
1838
cut: () => {
1839
this._commandService.executeCommand(editorCommon.Handler.Cut, {});
1840
}
1841
};
1842
}
1843
1844
const viewUserInputEvents = new ViewUserInputEvents(viewModel.coordinatesConverter);
1845
viewUserInputEvents.onKeyDown = (e) => this._onKeyDown.fire(e);
1846
viewUserInputEvents.onKeyUp = (e) => this._onKeyUp.fire(e);
1847
viewUserInputEvents.onContextMenu = (e) => this._onContextMenu.fire(e);
1848
viewUserInputEvents.onMouseMove = (e) => this._onMouseMove.fire(e);
1849
viewUserInputEvents.onMouseLeave = (e) => this._onMouseLeave.fire(e);
1850
viewUserInputEvents.onMouseDown = (e) => this._onMouseDown.fire(e);
1851
viewUserInputEvents.onMouseUp = (e) => this._onMouseUp.fire(e);
1852
viewUserInputEvents.onMouseDrag = (e) => this._onMouseDrag.fire(e);
1853
viewUserInputEvents.onMouseDrop = (e) => this._onMouseDrop.fire(e);
1854
viewUserInputEvents.onMouseDropCanceled = (e) => this._onMouseDropCanceled.fire(e);
1855
viewUserInputEvents.onMouseWheel = (e) => this._onMouseWheel.fire(e);
1856
1857
const view = new View(
1858
commandDelegate,
1859
this._configuration,
1860
this._themeService.getColorTheme(),
1861
viewModel,
1862
viewUserInputEvents,
1863
this._overflowWidgetsDomNode,
1864
this._instantiationService
1865
);
1866
1867
return [view, true];
1868
}
1869
1870
protected _postDetachModelCleanup(detachedModel: ITextModel | null): void {
1871
detachedModel?.removeAllDecorationsWithOwnerId(this._id);
1872
}
1873
1874
private _detachModel(): ITextModel | null {
1875
this._contributionsDisposable?.dispose();
1876
this._contributionsDisposable = undefined;
1877
if (!this._modelData) {
1878
return null;
1879
}
1880
const model = this._modelData.model;
1881
const removeDomNode = this._modelData.hasRealView ? this._modelData.view.domNode.domNode : null;
1882
1883
this._modelData.dispose();
1884
this._modelData = null;
1885
1886
this._domElement.removeAttribute('data-mode-id');
1887
if (removeDomNode && this._domElement.contains(removeDomNode)) {
1888
removeDomNode.remove();
1889
}
1890
if (this._bannerDomNode && this._domElement.contains(this._bannerDomNode)) {
1891
this._bannerDomNode.remove();
1892
}
1893
return model;
1894
}
1895
1896
private _registerDecorationType(description: string, key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
1897
this._codeEditorService.registerDecorationType(description, key, options, parentTypeKey, this);
1898
}
1899
1900
private _removeDecorationType(key: string): void {
1901
this._codeEditorService.removeDecorationType(key);
1902
}
1903
1904
private _resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions {
1905
return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
1906
}
1907
1908
public getTelemetryData(): { [key: string]: any } | undefined {
1909
return this._telemetryData;
1910
}
1911
1912
public hasModel(): this is editorBrowser.IActiveCodeEditor {
1913
return (this._modelData !== null);
1914
}
1915
1916
private showDropIndicatorAt(position: Position): void {
1917
const newDecorations: IModelDeltaDecoration[] = [{
1918
range: new Range(position.lineNumber, position.column, position.lineNumber, position.column),
1919
options: CodeEditorWidget.dropIntoEditorDecorationOptions
1920
}];
1921
1922
this._dropIntoEditorDecorations.set(newDecorations);
1923
this.revealPosition(position, editorCommon.ScrollType.Immediate);
1924
}
1925
1926
private removeDropIndicator(): void {
1927
this._dropIntoEditorDecorations.clear();
1928
}
1929
1930
public setContextValue(key: string, value: ContextKeyValue): void {
1931
this._contextKeyService.createKey(key, value);
1932
}
1933
1934
private _beginUpdate(): void {
1935
this._updateCounter++;
1936
if (this._updateCounter === 1) {
1937
this._onBeginUpdate.fire();
1938
}
1939
}
1940
1941
private _endUpdate(): void {
1942
this._updateCounter--;
1943
if (this._updateCounter === 0) {
1944
this._onEndUpdate.fire();
1945
}
1946
}
1947
}
1948
1949
let EDITOR_ID = 0;
1950
1951
export interface ICodeEditorWidgetOptions {
1952
/**
1953
* Is this a simple widget (not a real code editor)?
1954
* Defaults to false.
1955
*/
1956
isSimpleWidget?: boolean;
1957
1958
/**
1959
* Contributions to instantiate.
1960
* When provided, only the contributions included will be instantiated.
1961
* To include the defaults, those must be provided as well via [...EditorExtensionsRegistry.getEditorContributions()]
1962
* Defaults to EditorExtensionsRegistry.getEditorContributions().
1963
*/
1964
contributions?: IEditorContributionDescription[];
1965
1966
/**
1967
* Telemetry data associated with this CodeEditorWidget.
1968
* Defaults to null.
1969
*/
1970
telemetryData?: object;
1971
1972
/**
1973
* The ID of the context menu.
1974
* Defaults to MenuId.SimpleEditorContext or MenuId.EditorContext depending on whether the widget is simple.
1975
*/
1976
contextMenuId?: MenuId;
1977
}
1978
1979
class ModelData {
1980
constructor(
1981
public readonly model: ITextModel,
1982
public readonly viewModel: ViewModel,
1983
public readonly view: View,
1984
public readonly hasRealView: boolean,
1985
public readonly listenersToRemove: IDisposable[],
1986
public readonly attachedView: IAttachedView,
1987
) {
1988
}
1989
1990
public dispose(): void {
1991
dispose(this.listenersToRemove);
1992
this.model.onBeforeDetached(this.attachedView);
1993
if (this.hasRealView) {
1994
this.view.dispose();
1995
}
1996
this.viewModel.dispose();
1997
}
1998
}
1999
2000
const enum BooleanEventValue {
2001
NotSet,
2002
False,
2003
True
2004
}
2005
2006
export class BooleanEventEmitter extends Disposable {
2007
private readonly _onDidChangeToTrue: Emitter<void> = this._register(new Emitter<void>(this._emitterOptions));
2008
public readonly onDidChangeToTrue: Event<void> = this._onDidChangeToTrue.event;
2009
2010
private readonly _onDidChangeToFalse: Emitter<void> = this._register(new Emitter<void>(this._emitterOptions));
2011
public readonly onDidChangeToFalse: Event<void> = this._onDidChangeToFalse.event;
2012
2013
private _value: BooleanEventValue;
2014
2015
constructor(
2016
private readonly _emitterOptions: EmitterOptions
2017
) {
2018
super();
2019
this._value = BooleanEventValue.NotSet;
2020
}
2021
2022
public setValue(_value: boolean) {
2023
const value = (_value ? BooleanEventValue.True : BooleanEventValue.False);
2024
if (this._value === value) {
2025
return;
2026
}
2027
this._value = value;
2028
if (this._value === BooleanEventValue.True) {
2029
this._onDidChangeToTrue.fire();
2030
} else if (this._value === BooleanEventValue.False) {
2031
this._onDidChangeToFalse.fire();
2032
}
2033
}
2034
}
2035
2036
/**
2037
* A regular event emitter that also makes sure contributions are instantiated if necessary
2038
*/
2039
class InteractionEmitter<T> extends Emitter<T> {
2040
2041
constructor(
2042
private readonly _contributions: CodeEditorContributions,
2043
deliveryQueue: EventDeliveryQueue
2044
) {
2045
super({ deliveryQueue });
2046
}
2047
2048
override fire(event: T): void {
2049
this._contributions.onBeforeInteractionEvent();
2050
super.fire(event);
2051
}
2052
}
2053
2054
class EditorContextKeysManager extends Disposable {
2055
2056
private readonly _editor: CodeEditorWidget;
2057
private readonly _editorSimpleInput: IContextKey<boolean>;
2058
private readonly _editorFocus: IContextKey<boolean>;
2059
private readonly _textInputFocus: IContextKey<boolean>;
2060
private readonly _editorTextFocus: IContextKey<boolean>;
2061
private readonly _tabMovesFocus: IContextKey<boolean>;
2062
private readonly _editorReadonly: IContextKey<boolean>;
2063
private readonly _inDiffEditor: IContextKey<boolean>;
2064
private readonly _editorColumnSelection: IContextKey<boolean>;
2065
private readonly _hasMultipleSelections: IContextKey<boolean>;
2066
private readonly _hasNonEmptySelection: IContextKey<boolean>;
2067
private readonly _canUndo: IContextKey<boolean>;
2068
private readonly _canRedo: IContextKey<boolean>;
2069
2070
constructor(
2071
editor: CodeEditorWidget,
2072
contextKeyService: IContextKeyService
2073
) {
2074
super();
2075
2076
this._editor = editor;
2077
2078
contextKeyService.createKey('editorId', editor.getId());
2079
2080
this._editorSimpleInput = EditorContextKeys.editorSimpleInput.bindTo(contextKeyService);
2081
this._editorFocus = EditorContextKeys.focus.bindTo(contextKeyService);
2082
this._textInputFocus = EditorContextKeys.textInputFocus.bindTo(contextKeyService);
2083
this._editorTextFocus = EditorContextKeys.editorTextFocus.bindTo(contextKeyService);
2084
this._tabMovesFocus = EditorContextKeys.tabMovesFocus.bindTo(contextKeyService);
2085
this._editorReadonly = EditorContextKeys.readOnly.bindTo(contextKeyService);
2086
this._inDiffEditor = EditorContextKeys.inDiffEditor.bindTo(contextKeyService);
2087
this._editorColumnSelection = EditorContextKeys.columnSelection.bindTo(contextKeyService);
2088
this._hasMultipleSelections = EditorContextKeys.hasMultipleSelections.bindTo(contextKeyService);
2089
this._hasNonEmptySelection = EditorContextKeys.hasNonEmptySelection.bindTo(contextKeyService);
2090
this._canUndo = EditorContextKeys.canUndo.bindTo(contextKeyService);
2091
this._canRedo = EditorContextKeys.canRedo.bindTo(contextKeyService);
2092
2093
this._register(this._editor.onDidChangeConfiguration(() => this._updateFromConfig()));
2094
this._register(this._editor.onDidChangeCursorSelection(() => this._updateFromSelection()));
2095
this._register(this._editor.onDidFocusEditorWidget(() => this._updateFromFocus()));
2096
this._register(this._editor.onDidBlurEditorWidget(() => this._updateFromFocus()));
2097
this._register(this._editor.onDidFocusEditorText(() => this._updateFromFocus()));
2098
this._register(this._editor.onDidBlurEditorText(() => this._updateFromFocus()));
2099
this._register(this._editor.onDidChangeModel(() => this._updateFromModel()));
2100
this._register(this._editor.onDidChangeConfiguration(() => this._updateFromModel()));
2101
this._register(TabFocus.onDidChangeTabFocus((tabFocusMode: boolean) => this._tabMovesFocus.set(tabFocusMode)));
2102
2103
this._updateFromConfig();
2104
this._updateFromSelection();
2105
this._updateFromFocus();
2106
this._updateFromModel();
2107
2108
this._editorSimpleInput.set(this._editor.isSimpleWidget);
2109
}
2110
2111
private _updateFromConfig(): void {
2112
const options = this._editor.getOptions();
2113
2114
this._tabMovesFocus.set(TabFocus.getTabFocusMode());
2115
this._editorReadonly.set(options.get(EditorOption.readOnly));
2116
this._inDiffEditor.set(options.get(EditorOption.inDiffEditor));
2117
this._editorColumnSelection.set(options.get(EditorOption.columnSelection));
2118
}
2119
2120
private _updateFromSelection(): void {
2121
const selections = this._editor.getSelections();
2122
if (!selections) {
2123
this._hasMultipleSelections.reset();
2124
this._hasNonEmptySelection.reset();
2125
} else {
2126
this._hasMultipleSelections.set(selections.length > 1);
2127
this._hasNonEmptySelection.set(selections.some(s => !s.isEmpty()));
2128
}
2129
}
2130
2131
private _updateFromFocus(): void {
2132
this._editorFocus.set(this._editor.hasWidgetFocus() && !this._editor.isSimpleWidget);
2133
this._editorTextFocus.set(this._editor.hasTextFocus() && !this._editor.isSimpleWidget);
2134
this._textInputFocus.set(this._editor.hasTextFocus());
2135
}
2136
2137
private _updateFromModel(): void {
2138
const model = this._editor.getModel();
2139
this._canUndo.set(Boolean(model && model.canUndo()));
2140
this._canRedo.set(Boolean(model && model.canRedo()));
2141
}
2142
}
2143
2144
export class EditorModeContext extends Disposable {
2145
2146
private readonly _langId: IContextKey<string>;
2147
private readonly _hasCompletionItemProvider: IContextKey<boolean>;
2148
private readonly _hasCodeActionsProvider: IContextKey<boolean>;
2149
private readonly _hasCodeLensProvider: IContextKey<boolean>;
2150
private readonly _hasDefinitionProvider: IContextKey<boolean>;
2151
private readonly _hasDeclarationProvider: IContextKey<boolean>;
2152
private readonly _hasImplementationProvider: IContextKey<boolean>;
2153
private readonly _hasTypeDefinitionProvider: IContextKey<boolean>;
2154
private readonly _hasHoverProvider: IContextKey<boolean>;
2155
private readonly _hasDocumentHighlightProvider: IContextKey<boolean>;
2156
private readonly _hasDocumentSymbolProvider: IContextKey<boolean>;
2157
private readonly _hasReferenceProvider: IContextKey<boolean>;
2158
private readonly _hasRenameProvider: IContextKey<boolean>;
2159
private readonly _hasDocumentFormattingProvider: IContextKey<boolean>;
2160
private readonly _hasDocumentSelectionFormattingProvider: IContextKey<boolean>;
2161
private readonly _hasMultipleDocumentFormattingProvider: IContextKey<boolean>;
2162
private readonly _hasMultipleDocumentSelectionFormattingProvider: IContextKey<boolean>;
2163
private readonly _hasSignatureHelpProvider: IContextKey<boolean>;
2164
private readonly _hasInlayHintsProvider: IContextKey<boolean>;
2165
private readonly _isInEmbeddedEditor: IContextKey<boolean>;
2166
2167
constructor(
2168
private readonly _editor: CodeEditorWidget,
2169
private readonly _contextKeyService: IContextKeyService,
2170
private readonly _languageFeaturesService: ILanguageFeaturesService,
2171
) {
2172
super();
2173
2174
this._langId = EditorContextKeys.languageId.bindTo(_contextKeyService);
2175
this._hasCompletionItemProvider = EditorContextKeys.hasCompletionItemProvider.bindTo(_contextKeyService);
2176
this._hasCodeActionsProvider = EditorContextKeys.hasCodeActionsProvider.bindTo(_contextKeyService);
2177
this._hasCodeLensProvider = EditorContextKeys.hasCodeLensProvider.bindTo(_contextKeyService);
2178
this._hasDefinitionProvider = EditorContextKeys.hasDefinitionProvider.bindTo(_contextKeyService);
2179
this._hasDeclarationProvider = EditorContextKeys.hasDeclarationProvider.bindTo(_contextKeyService);
2180
this._hasImplementationProvider = EditorContextKeys.hasImplementationProvider.bindTo(_contextKeyService);
2181
this._hasTypeDefinitionProvider = EditorContextKeys.hasTypeDefinitionProvider.bindTo(_contextKeyService);
2182
this._hasHoverProvider = EditorContextKeys.hasHoverProvider.bindTo(_contextKeyService);
2183
this._hasDocumentHighlightProvider = EditorContextKeys.hasDocumentHighlightProvider.bindTo(_contextKeyService);
2184
this._hasDocumentSymbolProvider = EditorContextKeys.hasDocumentSymbolProvider.bindTo(_contextKeyService);
2185
this._hasReferenceProvider = EditorContextKeys.hasReferenceProvider.bindTo(_contextKeyService);
2186
this._hasRenameProvider = EditorContextKeys.hasRenameProvider.bindTo(_contextKeyService);
2187
this._hasSignatureHelpProvider = EditorContextKeys.hasSignatureHelpProvider.bindTo(_contextKeyService);
2188
this._hasInlayHintsProvider = EditorContextKeys.hasInlayHintsProvider.bindTo(_contextKeyService);
2189
this._hasDocumentFormattingProvider = EditorContextKeys.hasDocumentFormattingProvider.bindTo(_contextKeyService);
2190
this._hasDocumentSelectionFormattingProvider = EditorContextKeys.hasDocumentSelectionFormattingProvider.bindTo(_contextKeyService);
2191
this._hasMultipleDocumentFormattingProvider = EditorContextKeys.hasMultipleDocumentFormattingProvider.bindTo(_contextKeyService);
2192
this._hasMultipleDocumentSelectionFormattingProvider = EditorContextKeys.hasMultipleDocumentSelectionFormattingProvider.bindTo(_contextKeyService);
2193
this._isInEmbeddedEditor = EditorContextKeys.isInEmbeddedEditor.bindTo(_contextKeyService);
2194
2195
const update = () => this._update();
2196
2197
// update when model/mode changes
2198
this._register(_editor.onDidChangeModel(update));
2199
this._register(_editor.onDidChangeModelLanguage(update));
2200
2201
// update when registries change
2202
this._register(_languageFeaturesService.completionProvider.onDidChange(update));
2203
this._register(_languageFeaturesService.codeActionProvider.onDidChange(update));
2204
this._register(_languageFeaturesService.codeLensProvider.onDidChange(update));
2205
this._register(_languageFeaturesService.definitionProvider.onDidChange(update));
2206
this._register(_languageFeaturesService.declarationProvider.onDidChange(update));
2207
this._register(_languageFeaturesService.implementationProvider.onDidChange(update));
2208
this._register(_languageFeaturesService.typeDefinitionProvider.onDidChange(update));
2209
this._register(_languageFeaturesService.hoverProvider.onDidChange(update));
2210
this._register(_languageFeaturesService.documentHighlightProvider.onDidChange(update));
2211
this._register(_languageFeaturesService.documentSymbolProvider.onDidChange(update));
2212
this._register(_languageFeaturesService.referenceProvider.onDidChange(update));
2213
this._register(_languageFeaturesService.renameProvider.onDidChange(update));
2214
this._register(_languageFeaturesService.documentFormattingEditProvider.onDidChange(update));
2215
this._register(_languageFeaturesService.documentRangeFormattingEditProvider.onDidChange(update));
2216
this._register(_languageFeaturesService.signatureHelpProvider.onDidChange(update));
2217
this._register(_languageFeaturesService.inlayHintsProvider.onDidChange(update));
2218
2219
update();
2220
}
2221
2222
override dispose() {
2223
super.dispose();
2224
}
2225
2226
reset() {
2227
this._contextKeyService.bufferChangeEvents(() => {
2228
this._langId.reset();
2229
this._hasCompletionItemProvider.reset();
2230
this._hasCodeActionsProvider.reset();
2231
this._hasCodeLensProvider.reset();
2232
this._hasDefinitionProvider.reset();
2233
this._hasDeclarationProvider.reset();
2234
this._hasImplementationProvider.reset();
2235
this._hasTypeDefinitionProvider.reset();
2236
this._hasHoverProvider.reset();
2237
this._hasDocumentHighlightProvider.reset();
2238
this._hasDocumentSymbolProvider.reset();
2239
this._hasReferenceProvider.reset();
2240
this._hasRenameProvider.reset();
2241
this._hasDocumentFormattingProvider.reset();
2242
this._hasDocumentSelectionFormattingProvider.reset();
2243
this._hasSignatureHelpProvider.reset();
2244
this._isInEmbeddedEditor.reset();
2245
});
2246
}
2247
2248
private _update() {
2249
const model = this._editor.getModel();
2250
if (!model) {
2251
this.reset();
2252
return;
2253
}
2254
this._contextKeyService.bufferChangeEvents(() => {
2255
this._langId.set(model.getLanguageId());
2256
this._hasCompletionItemProvider.set(this._languageFeaturesService.completionProvider.has(model));
2257
this._hasCodeActionsProvider.set(this._languageFeaturesService.codeActionProvider.has(model));
2258
this._hasCodeLensProvider.set(this._languageFeaturesService.codeLensProvider.has(model));
2259
this._hasDefinitionProvider.set(this._languageFeaturesService.definitionProvider.has(model));
2260
this._hasDeclarationProvider.set(this._languageFeaturesService.declarationProvider.has(model));
2261
this._hasImplementationProvider.set(this._languageFeaturesService.implementationProvider.has(model));
2262
this._hasTypeDefinitionProvider.set(this._languageFeaturesService.typeDefinitionProvider.has(model));
2263
this._hasHoverProvider.set(this._languageFeaturesService.hoverProvider.has(model));
2264
this._hasDocumentHighlightProvider.set(this._languageFeaturesService.documentHighlightProvider.has(model));
2265
this._hasDocumentSymbolProvider.set(this._languageFeaturesService.documentSymbolProvider.has(model));
2266
this._hasReferenceProvider.set(this._languageFeaturesService.referenceProvider.has(model));
2267
this._hasRenameProvider.set(this._languageFeaturesService.renameProvider.has(model));
2268
this._hasSignatureHelpProvider.set(this._languageFeaturesService.signatureHelpProvider.has(model));
2269
this._hasInlayHintsProvider.set(this._languageFeaturesService.inlayHintsProvider.has(model));
2270
this._hasDocumentFormattingProvider.set(this._languageFeaturesService.documentFormattingEditProvider.has(model) || this._languageFeaturesService.documentRangeFormattingEditProvider.has(model));
2271
this._hasDocumentSelectionFormattingProvider.set(this._languageFeaturesService.documentRangeFormattingEditProvider.has(model));
2272
this._hasMultipleDocumentFormattingProvider.set(this._languageFeaturesService.documentFormattingEditProvider.all(model).length + this._languageFeaturesService.documentRangeFormattingEditProvider.all(model).length > 1);
2273
this._hasMultipleDocumentSelectionFormattingProvider.set(this._languageFeaturesService.documentRangeFormattingEditProvider.all(model).length > 1);
2274
this._isInEmbeddedEditor.set(model.uri.scheme === Schemas.walkThroughSnippet || model.uri.scheme === Schemas.vscodeChatCodeBlock);
2275
});
2276
}
2277
}
2278
2279
class CodeEditorWidgetFocusTracker extends Disposable {
2280
2281
private _hasDomElementFocus: boolean;
2282
private readonly _domFocusTracker: dom.IFocusTracker;
2283
private readonly _overflowWidgetsDomNode: dom.IFocusTracker | undefined;
2284
2285
private readonly _onChange: Emitter<void> = this._register(new Emitter<void>());
2286
public readonly onChange: Event<void> = this._onChange.event;
2287
2288
private _overflowWidgetsDomNodeHasFocus: boolean;
2289
2290
private _hadFocus: boolean | undefined = undefined;
2291
2292
constructor(domElement: HTMLElement, overflowWidgetsDomNode: HTMLElement | undefined) {
2293
super();
2294
2295
this._hasDomElementFocus = false;
2296
this._domFocusTracker = this._register(dom.trackFocus(domElement));
2297
2298
this._overflowWidgetsDomNodeHasFocus = false;
2299
2300
this._register(this._domFocusTracker.onDidFocus(() => {
2301
this._hasDomElementFocus = true;
2302
this._update();
2303
}));
2304
this._register(this._domFocusTracker.onDidBlur(() => {
2305
this._hasDomElementFocus = false;
2306
this._update();
2307
}));
2308
2309
if (overflowWidgetsDomNode) {
2310
this._overflowWidgetsDomNode = this._register(dom.trackFocus(overflowWidgetsDomNode));
2311
this._register(this._overflowWidgetsDomNode.onDidFocus(() => {
2312
this._overflowWidgetsDomNodeHasFocus = true;
2313
this._update();
2314
}));
2315
this._register(this._overflowWidgetsDomNode.onDidBlur(() => {
2316
this._overflowWidgetsDomNodeHasFocus = false;
2317
this._update();
2318
}));
2319
}
2320
}
2321
2322
private _update() {
2323
const focused = this._hasDomElementFocus || this._overflowWidgetsDomNodeHasFocus;
2324
if (this._hadFocus !== focused) {
2325
this._hadFocus = focused;
2326
this._onChange.fire(undefined);
2327
}
2328
}
2329
2330
public hasFocus(): boolean {
2331
return this._hadFocus ?? false;
2332
}
2333
2334
public refreshState(): void {
2335
this._domFocusTracker.refreshState();
2336
this._overflowWidgetsDomNode?.refreshState?.();
2337
}
2338
}
2339
2340
class EditorDecorationsCollection implements editorCommon.IEditorDecorationsCollection {
2341
2342
private _decorationIds: string[] = [];
2343
private _isChangingDecorations: boolean = false;
2344
2345
public get length(): number {
2346
return this._decorationIds.length;
2347
}
2348
2349
constructor(
2350
private readonly _editor: editorBrowser.ICodeEditor,
2351
decorations: IModelDeltaDecoration[] | undefined
2352
) {
2353
if (Array.isArray(decorations) && decorations.length > 0) {
2354
this.set(decorations);
2355
}
2356
}
2357
2358
public onDidChange(listener: (e: IModelDecorationsChangedEvent) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable {
2359
return this._editor.onDidChangeModelDecorations((e) => {
2360
if (this._isChangingDecorations) {
2361
return;
2362
}
2363
listener.call(thisArgs, e);
2364
}, disposables);
2365
}
2366
2367
public getRange(index: number): Range | null {
2368
if (!this._editor.hasModel()) {
2369
return null;
2370
}
2371
if (index >= this._decorationIds.length) {
2372
return null;
2373
}
2374
return this._editor.getModel().getDecorationRange(this._decorationIds[index]);
2375
}
2376
2377
public getRanges(): Range[] {
2378
if (!this._editor.hasModel()) {
2379
return [];
2380
}
2381
const model = this._editor.getModel();
2382
const result: Range[] = [];
2383
for (const decorationId of this._decorationIds) {
2384
const range = model.getDecorationRange(decorationId);
2385
if (range) {
2386
result.push(range);
2387
}
2388
}
2389
return result;
2390
}
2391
2392
public has(decoration: IModelDecoration): boolean {
2393
return this._decorationIds.includes(decoration.id);
2394
}
2395
2396
public clear(): void {
2397
if (this._decorationIds.length === 0) {
2398
// nothing to do
2399
return;
2400
}
2401
this.set([]);
2402
}
2403
2404
public set(newDecorations: readonly IModelDeltaDecoration[]): string[] {
2405
try {
2406
this._isChangingDecorations = true;
2407
this._editor.changeDecorations((accessor) => {
2408
this._decorationIds = accessor.deltaDecorations(this._decorationIds, newDecorations);
2409
});
2410
} finally {
2411
this._isChangingDecorations = false;
2412
}
2413
return this._decorationIds;
2414
}
2415
2416
public append(newDecorations: readonly IModelDeltaDecoration[]): string[] {
2417
let newDecorationIds: string[] = [];
2418
try {
2419
this._isChangingDecorations = true;
2420
this._editor.changeDecorations((accessor) => {
2421
newDecorationIds = accessor.deltaDecorations([], newDecorations);
2422
this._decorationIds = this._decorationIds.concat(newDecorationIds);
2423
});
2424
} finally {
2425
this._isChangingDecorations = false;
2426
}
2427
return newDecorationIds;
2428
}
2429
}
2430
2431
const squigglyStart = encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 3' enable-background='new 0 0 6 3' height='3' width='6'><g fill='`);
2432
const squigglyEnd = encodeURIComponent(`'><polygon points='5.5,0 2.5,3 1.1,3 4.1,0'/><polygon points='4,0 6,2 6,0.6 5.4,0'/><polygon points='0,2 1,3 2.4,3 0,0.6'/></g></svg>`);
2433
2434
function getSquigglySVGData(color: Color) {
2435
return squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;
2436
}
2437
2438
const dotdotdotStart = encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" height="3" width="12"><g fill="`);
2439
const dotdotdotEnd = encodeURIComponent(`"><circle cx="1" cy="1" r="1"/><circle cx="5" cy="1" r="1"/><circle cx="9" cy="1" r="1"/></g></svg>`);
2440
2441
function getDotDotDotSVGData(color: Color) {
2442
return dotdotdotStart + encodeURIComponent(color.toString()) + dotdotdotEnd;
2443
}
2444
2445
registerThemingParticipant((theme, collector) => {
2446
const errorForeground = theme.getColor(editorErrorForeground);
2447
if (errorForeground) {
2448
collector.addRule(`.monaco-editor .${ClassName.EditorErrorDecoration} { background: url("data:image/svg+xml,${getSquigglySVGData(errorForeground)}") repeat-x bottom left; }`);
2449
}
2450
const warningForeground = theme.getColor(editorWarningForeground);
2451
if (warningForeground) {
2452
collector.addRule(`.monaco-editor .${ClassName.EditorWarningDecoration} { background: url("data:image/svg+xml,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`);
2453
}
2454
const infoForeground = theme.getColor(editorInfoForeground);
2455
if (infoForeground) {
2456
collector.addRule(`.monaco-editor .${ClassName.EditorInfoDecoration} { background: url("data:image/svg+xml,${getSquigglySVGData(infoForeground)}") repeat-x bottom left; }`);
2457
}
2458
const hintForeground = theme.getColor(editorHintForeground);
2459
if (hintForeground) {
2460
collector.addRule(`.monaco-editor .${ClassName.EditorHintDecoration} { background: url("data:image/svg+xml,${getDotDotDotSVGData(hintForeground)}") no-repeat bottom left; }`);
2461
}
2462
const unnecessaryForeground = theme.getColor(editorUnnecessaryCodeOpacity);
2463
if (unnecessaryForeground) {
2464
collector.addRule(`.monaco-editor.showUnused .${ClassName.EditorUnnecessaryInlineDecoration} { opacity: ${unnecessaryForeground.rgba.a}; }`);
2465
}
2466
});
2467
2468