codeEditorWidget.ts 18.2 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import 'vs/css!./media/editor';
import 'vs/css!./media/tokens';
J
Johannes Rieken 已提交
9
import { onUnexpectedError } from 'vs/base/common/errors';
10
import { TPromise } from 'vs/base/common/winjs.base';
A
Alex Dima 已提交
11
import * as dom from 'vs/base/browser/dom';
J
Johannes Rieken 已提交
12 13 14 15 16
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { CommonCodeEditor } from 'vs/editor/common/commonCodeEditor';
import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig';
A
Alex Dima 已提交
17
import * as editorCommon from 'vs/editor/common/editorCommon';
18
import { EditorAction, EditorExtensionsRegistry, IEditorContributionCtor } from 'vs/editor/browser/editorExtensions';
19
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
J
Johannes Rieken 已提交
20
import { Configuration } from 'vs/editor/browser/config/configuration';
A
Alex Dima 已提交
21
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
A
Alex Dima 已提交
22
import { View, IOverlayWidgetData, IContentWidgetData } from 'vs/editor/browser/view/viewImpl';
23
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
24
import Event, { Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
25 26
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
27 28
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IPosition } from 'vs/editor/common/core/position';
29
import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands';
30
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
31
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoBorder, editorInfoForeground } from 'vs/editor/common/view/editorColorRegistry';
32
import { Color } from 'vs/base/common/color';
B
Benjamin Pasero 已提交
33
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
34
import { ClassName } from 'vs/editor/common/model/intervalTree';
A
Alex Dima 已提交
35
import { ITextModel, IModelDecorationOptions } from 'vs/editor/common/model';
E
Erich Gamma 已提交
36

37
export abstract class CodeEditorWidget extends CommonCodeEditor implements editorBrowser.ICodeEditor {
E
Erich Gamma 已提交
38

A
Alex Dima 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
	private readonly _onMouseUp: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseUp: Event<editorBrowser.IEditorMouseEvent> = this._onMouseUp.event;

	private readonly _onMouseDown: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseDown: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDown.event;

	private readonly _onMouseDrag: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseDrag: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDrag.event;

	private readonly _onMouseDrop: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseDrop: Event<editorBrowser.IEditorMouseEvent> = this._onMouseDrop.event;

	private readonly _onContextMenu: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onContextMenu: Event<editorBrowser.IEditorMouseEvent> = this._onContextMenu.event;

	private readonly _onMouseMove: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseMove: Event<editorBrowser.IEditorMouseEvent> = this._onMouseMove.event;

	private readonly _onMouseLeave: Emitter<editorBrowser.IEditorMouseEvent> = this._register(new Emitter<editorBrowser.IEditorMouseEvent>());
	public readonly onMouseLeave: Event<editorBrowser.IEditorMouseEvent> = this._onMouseLeave.event;

	private readonly _onKeyUp: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
	public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;

	private readonly _onKeyDown: Emitter<IKeyboardEvent> = this._register(new Emitter<IKeyboardEvent>());
	public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;

	private readonly _onDidScrollChange: Emitter<editorCommon.IScrollEvent> = this._register(new Emitter<editorCommon.IScrollEvent>());
	public readonly onDidScrollChange: Event<editorCommon.IScrollEvent> = this._onDidScrollChange.event;

	private readonly _onDidChangeViewZones: Emitter<void> = this._register(new Emitter<void>());
	public readonly onDidChangeViewZones: Event<void> = this._onDidChangeViewZones.event;
A
Alex Dima 已提交
71

72
	private _codeEditorService: ICodeEditorService;
73
	private _commandService: ICommandService;
74
	private _themeService: IThemeService;
75

J
Johannes Rieken 已提交
76
	protected domElement: HTMLElement;
77
	private _focusTracker: CodeEditorWidgetFocusTracker;
E
Erich Gamma 已提交
78

J
Johannes Rieken 已提交
79
	_configuration: Configuration;
80

A
Alex Dima 已提交
81 82
	private contentWidgets: { [key: string]: IContentWidgetData; };
	private overlayWidgets: { [key: string]: IOverlayWidgetData; };
E
Erich Gamma 已提交
83

A
Alex Dima 已提交
84
	_view: View;
E
Erich Gamma 已提交
85 86

	constructor(
J
Johannes Rieken 已提交
87
		domElement: HTMLElement,
88
		options: IEditorOptions,
E
Erich Gamma 已提交
89 90
		@IInstantiationService instantiationService: IInstantiationService,
		@ICodeEditorService codeEditorService: ICodeEditorService,
91
		@ICommandService commandService: ICommandService,
92 93
		@IContextKeyService contextKeyService: IContextKeyService,
		@IThemeService themeService: IThemeService
E
Erich Gamma 已提交
94
	) {
95
		super(domElement, options, instantiationService, contextKeyService);
96
		this._codeEditorService = codeEditorService;
97
		this._commandService = commandService;
98
		this._themeService = themeService;
E
Erich Gamma 已提交
99

100
		this._focusTracker = new CodeEditorWidgetFocusTracker(domElement);
A
Alex Dima 已提交
101
		this._focusTracker.onChange(() => {
102
			let hasFocus = this._focusTracker.hasFocus();
103

104
			if (hasFocus) {
A
Alex Dima 已提交
105
				this._onDidFocusEditor.fire();
106
			} else {
A
Alex Dima 已提交
107
				this._onDidBlurEditor.fire();
E
Erich Gamma 已提交
108 109 110 111 112 113
			}
		});

		this.contentWidgets = {};
		this.overlayWidgets = {};

114 115 116
		let contributions = this._getContributions();
		for (let i = 0, len = contributions.length; i < len; i++) {
			let ctor = contributions[i];
E
Erich Gamma 已提交
117
			try {
118
				let contribution = this._instantiationService.createInstance(ctor, this);
A
Alex Dima 已提交
119
				this._contributions[contribution.getId()] = contribution;
E
Erich Gamma 已提交
120
			} catch (err) {
121
				onUnexpectedError(err);
E
Erich Gamma 已提交
122 123
			}
		}
124

125
		this._getActions().forEach((action) => {
126 127 128 129 130 131 132 133 134 135 136 137
			const internalAction = new InternalEditorAction(
				action.id,
				action.label,
				action.alias,
				action.precondition,
				(): void | TPromise<void> => {
					return this._instantiationService.invokeFunction((accessor) => {
						return action.runEditorCommand(accessor, this, null);
					});
				},
				this._contextKeyService
			);
A
Alex Dima 已提交
138
			this._actions[internalAction.id] = internalAction;
139
		});
140 141

		this._codeEditorService.addCodeEditor(this);
E
Erich Gamma 已提交
142 143
	}

144
	protected abstract _getContributions(): IEditorContributionCtor[];
145 146
	protected abstract _getActions(): EditorAction[];

A
Alex Dima 已提交
147
	protected _createConfiguration(options: IEditorOptions): CommonEditorConfiguration {
148
		return new Configuration(options, this.domElement);
E
Erich Gamma 已提交
149 150 151
	}

	public dispose(): void {
152 153
		this._codeEditorService.removeCodeEditor(this);

E
Erich Gamma 已提交
154 155 156
		this.contentWidgets = {};
		this.overlayWidgets = {};

157
		this._focusTracker.dispose();
E
Erich Gamma 已提交
158 159 160
		super.dispose();
	}

161 162
	public createOverviewRuler(cssClassName: string): editorBrowser.IOverviewRuler {
		return this._view.createOverviewRuler(cssClassName);
E
Erich Gamma 已提交
163 164 165 166 167 168
	}

	public getDomNode(): HTMLElement {
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
169
		return this._view.domNode.domNode;
E
Erich Gamma 已提交
170 171
	}

172
	public delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {
E
Erich Gamma 已提交
173
		if (!this.hasView) {
174
			return;
E
Erich Gamma 已提交
175
		}
A
Alex Dima 已提交
176
		this._view.delegateVerticalScrollbarMouseDown(browserEvent);
E
Erich Gamma 已提交
177 178
	}

J
Johannes Rieken 已提交
179
	public layout(dimension?: editorCommon.IDimension): void {
E
Erich Gamma 已提交
180
		this._configuration.observeReferenceElement(dimension);
181
		this.render();
E
Erich Gamma 已提交
182 183 184 185 186 187 188 189 190 191 192 193 194
	}

	public focus(): void {
		if (!this.hasView) {
			return;
		}
		this._view.focus();
	}

	public isFocused(): boolean {
		return this.hasView && this._view.isFocused();
	}

195
	public hasWidgetFocus(): boolean {
196
		return this._focusTracker && this._focusTracker.hasFocus();
197 198
	}

A
Alex Dima 已提交
199
	public addContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
200
		let widgetData: IContentWidgetData = {
E
Erich Gamma 已提交
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
			widget: widget,
			position: widget.getPosition()
		};

		if (this.contentWidgets.hasOwnProperty(widget.getId())) {
			console.warn('Overwriting a content widget with the same id.');
		}

		this.contentWidgets[widget.getId()] = widgetData;

		if (this.hasView) {
			this._view.addContentWidget(widgetData);
		}
	}

A
Alex Dima 已提交
216
	public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
217
		let widgetId = widget.getId();
E
Erich Gamma 已提交
218
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
219
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
220 221 222 223 224 225 226
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
227
	public removeContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
228
		let widgetId = widget.getId();
E
Erich Gamma 已提交
229
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
230
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
231 232 233 234 235 236 237
			delete this.contentWidgets[widgetId];
			if (this.hasView) {
				this._view.removeContentWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
238
	public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
239
		let widgetData: IOverlayWidgetData = {
E
Erich Gamma 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
			widget: widget,
			position: widget.getPosition()
		};

		if (this.overlayWidgets.hasOwnProperty(widget.getId())) {
			console.warn('Overwriting an overlay widget with the same id.');
		}

		this.overlayWidgets[widget.getId()] = widgetData;

		if (this.hasView) {
			this._view.addOverlayWidget(widgetData);
		}
	}

A
Alex Dima 已提交
255
	public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
256
		let widgetId = widget.getId();
E
Erich Gamma 已提交
257
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
258
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
259 260 261 262 263 264 265
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutOverlayWidget(widgetData);
			}
		}
	}

A
Alex Dima 已提交
266
	public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
267
		let widgetId = widget.getId();
E
Erich Gamma 已提交
268
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
269
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
270 271 272 273 274 275 276
			delete this.overlayWidgets[widgetId];
			if (this.hasView) {
				this._view.removeOverlayWidget(widgetData);
			}
		}
	}

J
Johannes Rieken 已提交
277
	public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
E
Erich Gamma 已提交
278 279 280
		if (!this.hasView) {
			return;
		}
A
Alex Dima 已提交
281
		let hasChanges = this._view.change(callback);
E
Erich Gamma 已提交
282
		if (hasChanges) {
A
Alex Dima 已提交
283
			this._onDidChangeViewZones.fire();
E
Erich Gamma 已提交
284 285 286
		}
	}

287 288 289 290
	public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
291
		return this._view.getTargetAtClientPoint(clientX, clientY);
292 293
	}

A
Alex Dima 已提交
294
	public getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number; } {
E
Erich Gamma 已提交
295 296 297 298
		if (!this.hasView) {
			return null;
		}

A
Alex Dima 已提交
299 300
		let position = this.model.validatePosition(rawPosition);
		let layoutInfo = this._configuration.editor.layoutInfo;
E
Erich Gamma 已提交
301

302 303
		let top = this._getVerticalOffsetForPosition(position.lineNumber, position.column) - this.getScrollTop();
		let left = this._view.getOffsetForColumn(position.lineNumber, position.column) + layoutInfo.glyphMarginWidth + layoutInfo.lineNumbersWidth + layoutInfo.decorationsWidth - this.getScrollLeft();
E
Erich Gamma 已提交
304 305 306 307 308 309 310 311

		return {
			top: top,
			left: left,
			height: this._configuration.editor.lineHeight
		};
	}

J
Johannes Rieken 已提交
312
	public getOffsetForColumn(lineNumber: number, column: number): number {
E
Erich Gamma 已提交
313 314 315
		if (!this.hasView) {
			return -1;
		}
A
Alex Dima 已提交
316
		return this._view.getOffsetForColumn(lineNumber, column);
E
Erich Gamma 已提交
317 318
	}

319 320 321 322
	public render(): void {
		if (!this.hasView) {
			return;
		}
323
		this._view.render(true, false);
324 325
	}

J
Johannes Rieken 已提交
326
	public applyFontInfo(target: HTMLElement): void {
327 328 329
		Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
	}

A
Alex Dima 已提交
330
	_attachModel(model: ITextModel): void {
E
Erich Gamma 已提交
331 332
		this._view = null;

333
		super._attachModel(model);
E
Erich Gamma 已提交
334

335
		if (this._view) {
A
Alex Dima 已提交
336
			this.domElement.appendChild(this._view.domNode.domNode);
E
Erich Gamma 已提交
337

A
Alex Dima 已提交
338 339 340 341 342
			let keys = Object.keys(this.contentWidgets);
			for (let i = 0, len = keys.length; i < len; i++) {
				let widgetId = keys[i];
				this._view.addContentWidget(this.contentWidgets[widgetId]);
			}
E
Erich Gamma 已提交
343

A
Alex Dima 已提交
344 345 346 347 348
			keys = Object.keys(this.overlayWidgets);
			for (let i = 0, len = keys.length; i < len; i++) {
				let widgetId = keys[i];
				this._view.addOverlayWidget(this.overlayWidgets[widgetId]);
			}
E
Erich Gamma 已提交
349

A
Alex Dima 已提交
350 351
			this._view.render(false, true);
			this.hasView = true;
S
smoke:  
Sandeep Somavarapu 已提交
352
			this._view.domNode.domNode.setAttribute('data-uri', model.uri.toString());
E
Erich Gamma 已提交
353 354 355
		}
	}

356 357 358 359
	protected _scheduleAtNextAnimationFrame(callback: () => void): IDisposable {
		return dom.scheduleAtNextAnimationFrame(callback);
	}

360 361
	protected _createView(): void {
		this._view = new View(
362
			this._commandService,
363
			this._configuration,
364
			this._themeService,
365
			this.viewModel,
366
			this.cursor,
367
			(editorCommand: CoreEditorCommand, args: any) => {
A
Alex Dima 已提交
368 369 370
				if (!this.cursor) {
					return;
				}
371
				editorCommand.runCoreEditorCommand(this.cursor, args);
A
Alex Dima 已提交
372
			}
373
		);
E
Erich Gamma 已提交
374

A
Alex Dima 已提交
375
		const viewEventBus = this._view.getInternalEventBus();
A
Alex Dima 已提交
376

A
Alex Dima 已提交
377
		viewEventBus.onDidGainFocus = () => {
A
Alex Dima 已提交
378 379 380
			this._onDidFocusEditorText.fire();
			// In IE, the focus is not synchronous, so we give it a little help
			this._onDidFocusEditor.fire();
A
Alex Dima 已提交
381
		};
A
Alex Dima 已提交
382

A
Alex Dima 已提交
383 384 385 386 387 388 389 390 391 392 393
		viewEventBus.onDidScroll = (e) => this._onDidScrollChange.fire(e);
		viewEventBus.onDidLoseFocus = () => this._onDidBlurEditorText.fire();
		viewEventBus.onContextMenu = (e) => this._onContextMenu.fire(e);
		viewEventBus.onMouseDown = (e) => this._onMouseDown.fire(e);
		viewEventBus.onMouseUp = (e) => this._onMouseUp.fire(e);
		viewEventBus.onMouseDrag = (e) => this._onMouseDrag.fire(e);
		viewEventBus.onMouseDrop = (e) => this._onMouseDrop.fire(e);
		viewEventBus.onKeyUp = (e) => this._onKeyUp.fire(e);
		viewEventBus.onMouseMove = (e) => this._onMouseMove.fire(e);
		viewEventBus.onMouseLeave = (e) => this._onMouseLeave.fire(e);
		viewEventBus.onKeyDown = (e) => this._onKeyDown.fire(e);
394
	}
E
Erich Gamma 已提交
395

396 397 398 399 400 401 402 403 404 405
	public restoreViewState(s: editorCommon.ICodeEditorViewState): void {
		super.restoreViewState(s);
		if (!this.cursor || !this.hasView) {
			return;
		}
		if (s && s.cursorState && s.viewState) {
			this._view.restoreState(this.viewModel.viewLayout.reduceRestoreState(s.viewState));
		}
	}

A
Alex Dima 已提交
406
	protected _detachModel(): ITextModel {
A
Alex Dima 已提交
407
		let removeDomNode: HTMLElement = null;
E
Erich Gamma 已提交
408 409 410

		if (this._view) {
			this._view.dispose();
A
Alex Dima 已提交
411
			removeDomNode = this._view.domNode.domNode;
E
Erich Gamma 已提交
412 413 414
			this._view = null;
		}

415
		let result = super._detachModel();
E
Erich Gamma 已提交
416 417 418 419 420 421 422

		if (removeDomNode) {
			this.domElement.removeChild(removeDomNode);
		}

		return result;
	}
423 424 425

	// BEGIN decorations

J
Johannes Rieken 已提交
426
	protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
427 428 429
		this._codeEditorService.registerDecorationType(key, options, parentTypeKey);
	}

J
Johannes Rieken 已提交
430
	protected _removeDecorationType(key: string): void {
431 432 433
		this._codeEditorService.removeDecorationType(key);
	}

434
	protected _resolveDecorationOptions(typeKey: string, writable: boolean): IModelDecorationOptions {
435 436 437 438
		return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
	}

	// END decorations
439 440 441 442 443 444 445 446 447 448 449 450

	protected _triggerEditorCommand(source: string, handlerId: string, payload: any): boolean {
		const command = EditorExtensionsRegistry.getEditorCommand(handlerId);
		if (command) {
			payload = payload || {};
			payload.source = source;
			TPromise.as(command.runEditorCommand(null, this, payload)).done(null, onUnexpectedError);
			return true;
		}

		return false;
	}
E
Erich Gamma 已提交
451 452
}

453 454
class CodeEditorWidgetFocusTracker extends Disposable {

455 456
	private _hasFocus: boolean;
	private _domFocusTracker: dom.IFocusTracker;
457 458

	private _onChange: Emitter<void> = this._register(new Emitter<void>());
459
	public readonly onChange: Event<void> = this._onChange.event;
460

J
Johannes Rieken 已提交
461
	constructor(domElement: HTMLElement) {
462 463
		super();

464 465
		this._hasFocus = false;
		this._domFocusTracker = this._register(dom.trackFocus(domElement));
466

467
		this._register(this._domFocusTracker.onDidFocus(() => {
468 469
			this._hasFocus = true;
			this._onChange.fire(void 0);
470 471
		}));
		this._register(this._domFocusTracker.onDidBlur(() => {
472 473
			this._hasFocus = false;
			this._onChange.fire(void 0);
474
		}));
475 476 477
	}

	public hasFocus(): boolean {
478
		return this._hasFocus;
479 480
	}
}
481

482
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='`);
483
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>`);
484

485 486 487
function getSquigglySVGData(color: Color) {
	return squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;
}
488

489 490 491
registerThemingParticipant((theme, collector) => {
	let errorBorderColor = theme.getColor(editorErrorBorder);
	if (errorBorderColor) {
492
		collector.addRule(`.monaco-editor .${ClassName.EditorErrorDecoration} { border-bottom: 4px double ${errorBorderColor}; }`);
493 494 495
	}
	let errorForeground = theme.getColor(editorErrorForeground);
	if (errorForeground) {
496
		collector.addRule(`.monaco-editor .${ClassName.EditorErrorDecoration} { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(errorForeground)}") repeat-x bottom left; }`);
497 498
	}

499 500
	let warningBorderColor = theme.getColor(editorWarningBorder);
	if (warningBorderColor) {
501
		collector.addRule(`.monaco-editor .${ClassName.EditorWarningDecoration} { border-bottom: 4px double ${warningBorderColor}; }`);
502 503 504
	}
	let warningForeground = theme.getColor(editorWarningForeground);
	if (warningForeground) {
505
		collector.addRule(`.monaco-editor .${ClassName.EditorWarningDecoration} { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`);
506 507 508
	}

	let infoBorderColor = theme.getColor(editorInfoBorder);
509 510
	if (infoBorderColor) {
		collector.addRule(`.monaco-editor .${ClassName.EditorInfoDecoration} { border-bottom: 4px double ${infoBorderColor}; }`);
511 512
	}
	let infoForeground = theme.getColor(editorInfoForeground);
513 514
	if (infoForeground) {
		collector.addRule(`.monaco-editor .${ClassName.EditorInfoDecoration} { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(infoForeground)}") repeat-x bottom left; }`);
515
	}
516
});