codeEditorWidget.ts 18.1 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';
E
Erich Gamma 已提交
35

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

A
Alex Dima 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	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 已提交
70

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

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

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

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

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

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

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

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

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

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

124
		this._getActions().forEach((action) => {
125 126 127 128 129 130 131 132 133 134 135 136
			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 已提交
137
			this._actions[internalAction.id] = internalAction;
138
		});
139 140

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Alex Dima 已提交
198
	public addContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
199
		let widgetData: IContentWidgetData = {
E
Erich Gamma 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
			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 已提交
215
	public layoutContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
216
		let widgetId = widget.getId();
E
Erich Gamma 已提交
217
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
218
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
219 220 221 222 223 224 225
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutContentWidget(widgetData);
			}
		}
	}

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

A
Alex Dima 已提交
237
	public addOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
238
		let widgetData: IOverlayWidgetData = {
E
Erich Gamma 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
			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 已提交
254
	public layoutOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
255
		let widgetId = widget.getId();
E
Erich Gamma 已提交
256
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
257
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
258 259 260 261 262 263 264
			widgetData.position = widget.getPosition();
			if (this.hasView) {
				this._view.layoutOverlayWidget(widgetData);
			}
		}
	}

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

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

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

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

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

301 302
		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 已提交
303 304 305 306 307 308 309 310

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

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

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

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

J
Johannes Rieken 已提交
329
	_attachModel(model: editorCommon.IModel): void {
E
Erich Gamma 已提交
330 331
		this._view = null;

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

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

A
Alex Dima 已提交
337 338 339 340 341
			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 已提交
342

A
Alex Dima 已提交
343 344 345 346 347
			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 已提交
348

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

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

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

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

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

A
Alex Dima 已提交
382 383 384 385 386 387 388 389 390 391 392
		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);
393
	}
E
Erich Gamma 已提交
394

395 396 397 398 399 400 401 402 403 404
	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 已提交
405
	protected _detachModel(): editorCommon.IModel {
A
Alex Dima 已提交
406
		let removeDomNode: HTMLElement = null;
E
Erich Gamma 已提交
407 408 409

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

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

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

		return result;
	}
422 423 424

	// BEGIN decorations

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

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

J
Johannes Rieken 已提交
433
	protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
434 435 436 437
		return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
	}

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

	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 已提交
450 451
}

452 453
class CodeEditorWidgetFocusTracker extends Disposable {

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

	private _onChange: Emitter<void> = this._register(new Emitter<void>());
A
Alex Dima 已提交
458
	public onChange: Event<void> = this._onChange.event;
459

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

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

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

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

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

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

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

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

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