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';
17
import { Range } from 'vs/editor/common/core/range';
A
Alex Dima 已提交
18
import * as editorCommon from 'vs/editor/common/editorCommon';
19
import { EditorAction, EditorExtensionsRegistry, IEditorContributionCtor } from 'vs/editor/browser/editorExtensions';
20
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
J
Johannes Rieken 已提交
21
import { Configuration } from 'vs/editor/browser/config/configuration';
A
Alex Dima 已提交
22
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
A
Alex Dima 已提交
23
import { View, IOverlayWidgetData, IContentWidgetData } from 'vs/editor/browser/view/viewImpl';
24
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
A
Alex Dima 已提交
25
import Event, { Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
26 27
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { InternalEditorAction } from 'vs/editor/common/editorAction';
28 29
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IPosition } from 'vs/editor/common/core/position';
30
import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands';
31
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
32
import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoBorder, editorInfoForeground } from 'vs/editor/common/view/editorColorRegistry';
33
import { Color } from 'vs/base/common/color';
B
Benjamin Pasero 已提交
34
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
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();
	}

A
Alex Dima 已提交
160 161
	public createOverviewRuler(cssClassName: string, minimumHeight: number, maximumHeight: number): editorBrowser.IOverviewRuler {
		return this._view.createOverviewRuler(cssClassName, minimumHeight, maximumHeight);
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
	}

A
Alex Dima 已提交
171
	public getCompletelyVisibleLinesRangeInViewport(): Range {
A
Alex Dima 已提交
172 173 174 175
		if (!this.hasView) {
			return null;
		}
		const viewRange = this.viewModel.getCompletelyVisibleViewRange();
A
Alex Dima 已提交
176
		return this.viewModel.coordinatesConverter.convertViewRangeToModelRange(viewRange);
177 178
	}

179
	public delegateVerticalScrollbarMouseDown(browserEvent: IMouseEvent): void {
E
Erich Gamma 已提交
180
		if (!this.hasView) {
181
			return;
E
Erich Gamma 已提交
182
		}
A
Alex Dima 已提交
183
		this._view.delegateVerticalScrollbarMouseDown(browserEvent);
E
Erich Gamma 已提交
184 185
	}

J
Johannes Rieken 已提交
186
	public layout(dimension?: editorCommon.IDimension): void {
E
Erich Gamma 已提交
187
		this._configuration.observeReferenceElement(dimension);
188
		this.render();
E
Erich Gamma 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201
	}

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

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

202
	public hasWidgetFocus(): boolean {
203
		return this._focusTracker && this._focusTracker.hasFocus();
204 205
	}

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

A
Alex Dima 已提交
234
	public removeContentWidget(widget: editorBrowser.IContentWidget): void {
A
Alex Dima 已提交
235
		let widgetId = widget.getId();
E
Erich Gamma 已提交
236
		if (this.contentWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
237
			let widgetData = this.contentWidgets[widgetId];
E
Erich Gamma 已提交
238 239 240 241 242 243 244
			delete this.contentWidgets[widgetId];
			if (this.hasView) {
				this._view.removeContentWidget(widgetData);
			}
		}
	}

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

A
Alex Dima 已提交
273
	public removeOverlayWidget(widget: editorBrowser.IOverlayWidget): void {
A
Alex Dima 已提交
274
		let widgetId = widget.getId();
E
Erich Gamma 已提交
275
		if (this.overlayWidgets.hasOwnProperty(widgetId)) {
A
Alex Dima 已提交
276
			let widgetData = this.overlayWidgets[widgetId];
E
Erich Gamma 已提交
277 278 279 280 281 282 283
			delete this.overlayWidgets[widgetId];
			if (this.hasView) {
				this._view.removeOverlayWidget(widgetData);
			}
		}
	}

J
Johannes Rieken 已提交
284
	public changeViewZones(callback: (accessor: editorBrowser.IViewZoneChangeAccessor) => void): void {
E
Erich Gamma 已提交
285 286 287
		if (!this.hasView) {
			return;
		}
A
Alex Dima 已提交
288
		let hasChanges = this._view.change(callback);
E
Erich Gamma 已提交
289
		if (hasChanges) {
A
Alex Dima 已提交
290
			this._onDidChangeViewZones.fire();
E
Erich Gamma 已提交
291 292 293
		}
	}

294 295 296 297
	public getTargetAtClientPoint(clientX: number, clientY: number): editorBrowser.IMouseTarget {
		if (!this.hasView) {
			return null;
		}
A
Alex Dima 已提交
298
		return this._view.getTargetAtClientPoint(clientX, clientY);
299 300
	}

A
Alex Dima 已提交
301
	public getScrolledVisiblePosition(rawPosition: IPosition): { top: number; left: number; height: number; } {
E
Erich Gamma 已提交
302 303 304 305
		if (!this.hasView) {
			return null;
		}

A
Alex Dima 已提交
306 307
		let position = this.model.validatePosition(rawPosition);
		let layoutInfo = this._configuration.editor.layoutInfo;
E
Erich Gamma 已提交
308

309 310
		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 已提交
311 312 313 314 315 316 317 318

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

J
Johannes Rieken 已提交
319
	public getOffsetForColumn(lineNumber: number, column: number): number {
E
Erich Gamma 已提交
320 321 322
		if (!this.hasView) {
			return -1;
		}
A
Alex Dima 已提交
323
		return this._view.getOffsetForColumn(lineNumber, column);
E
Erich Gamma 已提交
324 325
	}

326 327 328 329
	public render(): void {
		if (!this.hasView) {
			return;
		}
330
		this._view.render(true, false);
331 332
	}

J
Johannes Rieken 已提交
333
	public setAriaActiveDescendant(id: string): void {
A
Alex Dima 已提交
334 335 336 337 338 339
		if (!this.hasView) {
			return;
		}
		this._view.setAriaActiveDescendant(id);
	}

J
Johannes Rieken 已提交
340
	public applyFontInfo(target: HTMLElement): void {
341 342 343
		Configuration.applyFontInfoSlow(target, this._configuration.editor.fontInfo);
	}

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

347
		super._attachModel(model);
E
Erich Gamma 已提交
348

349
		if (this._view) {
A
Alex Dima 已提交
350
			this.domElement.appendChild(this._view.domNode.domNode);
E
Erich Gamma 已提交
351

A
Alex Dima 已提交
352 353 354 355 356
			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 已提交
357

A
Alex Dima 已提交
358 359 360 361 362
			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 已提交
363

A
Alex Dima 已提交
364 365
			this._view.render(false, true);
			this.hasView = true;
S
smoke:  
Sandeep Somavarapu 已提交
366
			this._view.domNode.domNode.setAttribute('data-uri', model.uri.toString());
E
Erich Gamma 已提交
367 368 369
		}
	}

370 371 372 373
	protected _scheduleAtNextAnimationFrame(callback: () => void): IDisposable {
		return dom.scheduleAtNextAnimationFrame(callback);
	}

374 375
	protected _createView(): void {
		this._view = new View(
376
			this._commandService,
377
			this._configuration,
378
			this._themeService,
379
			this.viewModel,
380
			this.cursor,
381
			(editorCommand: CoreEditorCommand, args: any) => {
A
Alex Dima 已提交
382 383 384
				if (!this.cursor) {
					return;
				}
385
				editorCommand.runCoreEditorCommand(this.cursor, args);
A
Alex Dima 已提交
386
			}
387
		);
E
Erich Gamma 已提交
388

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

A
Alex Dima 已提交
391
		viewEventBus.onDidGainFocus = () => {
A
Alex Dima 已提交
392 393 394
			this._onDidFocusEditorText.fire();
			// In IE, the focus is not synchronous, so we give it a little help
			this._onDidFocusEditor.fire();
A
Alex Dima 已提交
395
		};
A
Alex Dima 已提交
396

A
Alex Dima 已提交
397 398 399 400 401 402 403 404 405 406 407
		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);
408
	}
E
Erich Gamma 已提交
409

A
Alex Dima 已提交
410
	protected _detachModel(): editorCommon.IModel {
A
Alex Dima 已提交
411
		let removeDomNode: HTMLElement = null;
E
Erich Gamma 已提交
412 413 414

		if (this._view) {
			this._view.dispose();
A
Alex Dima 已提交
415
			removeDomNode = this._view.domNode.domNode;
E
Erich Gamma 已提交
416 417 418
			this._view = null;
		}

419
		let result = super._detachModel();
E
Erich Gamma 已提交
420 421 422 423 424 425 426

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

		return result;
	}
427 428 429

	// BEGIN decorations

J
Johannes Rieken 已提交
430
	protected _registerDecorationType(key: string, options: editorCommon.IDecorationRenderOptions, parentTypeKey?: string): void {
431 432 433
		this._codeEditorService.registerDecorationType(key, options, parentTypeKey);
	}

J
Johannes Rieken 已提交
434
	protected _removeDecorationType(key: string): void {
435 436 437
		this._codeEditorService.removeDecorationType(key);
	}

J
Johannes Rieken 已提交
438
	protected _resolveDecorationOptions(typeKey: string, writable: boolean): editorCommon.IModelDecorationOptions {
439 440 441 442
		return this._codeEditorService.resolveDecorationOptions(typeKey, writable);
	}

	// END decorations
443 444 445 446 447 448 449 450 451 452 453 454

	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 已提交
455 456
}

457 458
class CodeEditorWidgetFocusTracker extends Disposable {

459 460
	private _hasFocus: boolean;
	private _domFocusTracker: dom.IFocusTracker;
461 462

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

J
Johannes Rieken 已提交
465
	constructor(domElement: HTMLElement) {
466 467
		super();

468 469
		this._hasFocus = false;
		this._domFocusTracker = this._register(dom.trackFocus(domElement));
470

471 472 473
		this._domFocusTracker.addFocusListener(() => {
			this._hasFocus = true;
			this._onChange.fire(void 0);
474
		});
475 476 477
		this._domFocusTracker.addBlurListener(() => {
			this._hasFocus = false;
			this._onChange.fire(void 0);
478 479 480 481
		});
	}

	public hasFocus(): boolean {
482
		return this._hasFocus;
483 484
	}
}
485

486 487
const squigglyStart = encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' height='3' width='6'><g fill='`);
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>`);
488

489 490 491
function getSquigglySVGData(color: Color) {
	return squigglyStart + encodeURIComponent(color.toString()) + squigglyEnd;
}
492

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

503 504
	let warningBorderColor = theme.getColor(editorWarningBorder);
	if (warningBorderColor) {
505
		collector.addRule(`.monaco-editor .warningsquiggly { border-bottom: 4px double ${warningBorderColor}; }`);
506 507 508
	}
	let warningForeground = theme.getColor(editorWarningForeground);
	if (warningForeground) {
509 510 511 512 513 514 515 516 517 518
		collector.addRule(`.monaco-editor .warningsquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(warningForeground)}") repeat-x bottom left; }`);
	}

	let infoBorderColor = theme.getColor(editorInfoBorder);
	if (warningBorderColor) {
		collector.addRule(`.monaco-editor .infosquiggly { border-bottom: 4px double ${infoBorderColor}; }`);
	}
	let infoForeground = theme.getColor(editorInfoForeground);
	if (warningForeground) {
		collector.addRule(`.monaco-editor .infosquiggly { background: url("data:image/svg+xml;utf8,${getSquigglySVGData(infoForeground)}") repeat-x bottom left; }`);
519
	}
520
});