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

import 'vs/css!./media/diffEditor';
7
import * as nls from 'vs/nls';
A
Alex Dima 已提交
8
import * as dom from 'vs/base/browser/dom';
A
Alex Dima 已提交
9
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
J
Joao Moreno 已提交
10
import { ISashEvent, IVerticalSashLayoutProvider, Sash, SashState } from 'vs/base/browser/ui/sash/sash';
A
Alex Dima 已提交
11
import { RunOnceScheduler, IntervalTimer } from 'vs/base/common/async';
A
Alex Dima 已提交
12 13 14 15 16 17 18
import { Color } from 'vs/base/common/color';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import * as objects from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import { Configuration } from 'vs/editor/browser/config/configuration';
import { StableEditorScrollState } from 'vs/editor/browser/core/editorState';
A
Alex Dima 已提交
19
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
A
Alex Dima 已提交
20
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
A
Alex Dima 已提交
21
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
A
Alex Dima 已提交
22
import { DiffReview } from 'vs/editor/browser/widget/diffReview';
23
import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';
A
Alex Dima 已提交
24 25 26 27 28 29 30 31
import { IPosition, Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
import { IStringBuilder, createStringBuilder } from 'vs/editor/common/core/stringBuilder';
import * as editorCommon from 'vs/editor/common/editorCommon';
import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
32
import { OverviewRulerZone } from 'vs/editor/common/view/overviewZoneManager';
A
Alex Dima 已提交
33 34
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';
35
import { IEditorWhitespace } from 'vs/editor/common/viewLayout/linesLayout';
A
Alex Dima 已提交
36 37 38 39
import { InlineDecoration, InlineDecorationType, ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
40
import { INotificationService } from 'vs/platform/notification/common/notification';
41
import { defaultInsertColor, defaultRemoveColor, diffBorder, diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, scrollbarShadow, scrollbarSliderBackground, scrollbarSliderHoverBackground, scrollbarSliderActiveBackground } from 'vs/platform/theme/common/colorRegistry';
A
Alex Dima 已提交
42
import { ITheme, IThemeService, getThemeTypeSelector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
43 44 45
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
46
import { Constants } from 'vs/base/common/uint';
47
import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
A
Alex Dima 已提交
48
import { onUnexpectedError } from 'vs/base/common/errors';
49
import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
E
Erich Gamma 已提交
50 51

interface IEditorDiffDecorations {
52
	decorations: IModelDeltaDecoration[];
A
Alex Dima 已提交
53
	overviewZones: OverviewRulerZone[];
E
Erich Gamma 已提交
54 55 56
}

interface IEditorDiffDecorationsWithZones extends IEditorDiffDecorations {
57
	zones: IMyViewZone[];
E
Erich Gamma 已提交
58 59 60
}

interface IEditorsDiffDecorationsWithZones {
J
Johannes Rieken 已提交
61 62
	original: IEditorDiffDecorationsWithZones;
	modified: IEditorDiffDecorationsWithZones;
E
Erich Gamma 已提交
63 64 65
}

interface IEditorsZones {
66 67
	original: IMyViewZone[];
	modified: IMyViewZone[];
E
Erich Gamma 已提交
68 69 70
}

interface IDiffEditorWidgetStyle {
A
Alex Dima 已提交
71
	getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones;
J
Johannes Rieken 已提交
72
	setEnableSplitViewResizing(enableSplitViewResizing: boolean): void;
73
	applyColors(theme: ITheme): boolean;
E
Erich Gamma 已提交
74 75 76 77 78
	layout(): number;
	dispose(): void;
}

class VisualEditorState {
A
Alex Dima 已提交
79
	private _zones: string[];
80
	private inlineDiffMargins: InlineDiffMargin[];
J
Johannes Rieken 已提交
81 82
	private _zonesMap: { [zoneId: string]: boolean; };
	private _decorations: string[];
E
Erich Gamma 已提交
83

84 85
	constructor(
		private _contextMenuService: IContextMenuService,
86
		private _clipboardService: IClipboardService | null
87
	) {
E
Erich Gamma 已提交
88
		this._zones = [];
89
		this.inlineDiffMargins = [];
E
Erich Gamma 已提交
90 91 92 93
		this._zonesMap = {};
		this._decorations = [];
	}

A
Alex Dima 已提交
94
	public getForeignViewZones(allViewZones: IEditorWhitespace[]): IEditorWhitespace[] {
E
Erich Gamma 已提交
95 96 97
		return allViewZones.filter((z) => !this._zonesMap[String(z.id)]);
	}

A
Alex Dima 已提交
98
	public clean(editor: CodeEditorWidget): void {
E
Erich Gamma 已提交
99 100
		// (1) View zones
		if (this._zones.length > 0) {
J
Johannes Rieken 已提交
101
			editor.changeViewZones((viewChangeAccessor: editorBrowser.IViewZoneChangeAccessor) => {
A
Alex Dima 已提交
102
				for (let i = 0, length = this._zones.length; i < length; i++) {
E
Erich Gamma 已提交
103 104 105 106 107 108 109 110
					viewChangeAccessor.removeZone(this._zones[i]);
				}
			});
		}
		this._zones = [];
		this._zonesMap = {};

		// (2) Model decorations
A
Alex Dima 已提交
111
		this._decorations = editor.deltaDecorations(this._decorations, []);
E
Erich Gamma 已提交
112 113
	}

A
Alex Dima 已提交
114
	public apply(editor: CodeEditorWidget, overviewRuler: editorBrowser.IOverviewRuler, newDecorations: IEditorDiffDecorationsWithZones, restoreScrollState: boolean): void {
A
Alex Dima 已提交
115 116 117

		const scrollState = restoreScrollState ? StableEditorScrollState.capture(editor) : null;

E
Erich Gamma 已提交
118
		// view zones
J
Johannes Rieken 已提交
119
		editor.changeViewZones((viewChangeAccessor: editorBrowser.IViewZoneChangeAccessor) => {
A
Alex Dima 已提交
120
			for (let i = 0, length = this._zones.length; i < length; i++) {
E
Erich Gamma 已提交
121 122
				viewChangeAccessor.removeZone(this._zones[i]);
			}
123 124 125
			for (let i = 0, length = this.inlineDiffMargins.length; i < length; i++) {
				this.inlineDiffMargins[i].dispose();
			}
E
Erich Gamma 已提交
126 127
			this._zones = [];
			this._zonesMap = {};
128
			this.inlineDiffMargins = [];
A
Alex Dima 已提交
129
			for (let i = 0, length = newDecorations.zones.length; i < length; i++) {
130
				const viewZone = <editorBrowser.IViewZone>newDecorations.zones[i];
131
				viewZone.suppressMouseDown = true;
132
				let zoneId = viewChangeAccessor.addZone(viewZone);
E
Erich Gamma 已提交
133 134
				this._zones.push(zoneId);
				this._zonesMap[String(zoneId)] = true;
135

136
				if (newDecorations.zones[i].diff && viewZone.marginDomNode && this._clipboardService) {
137
					viewZone.suppressMouseDown = false;
P
Peng Lyu 已提交
138
					this.inlineDiffMargins.push(new InlineDiffMargin(zoneId, viewZone.marginDomNode, editor, newDecorations.zones[i].diff!, this._contextMenuService, this._clipboardService));
139
				}
E
Erich Gamma 已提交
140 141 142
			}
		});

A
Alex Dima 已提交
143 144 145 146
		if (scrollState) {
			scrollState.restore(editor);
		}

E
Erich Gamma 已提交
147 148 149 150
		// decorations
		this._decorations = editor.deltaDecorations(this._decorations, newDecorations.decorations);

		// overview ruler
151 152 153
		if (overviewRuler) {
			overviewRuler.setZones(newDecorations.overviewZones);
		}
E
Erich Gamma 已提交
154 155 156
	}
}

A
Alex Dima 已提交
157
let DIFF_EDITOR_ID = 0;
E
Erich Gamma 已提交
158

A
Alex Dima 已提交
159
export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffEditor {
A
Alex Dima 已提交
160

161
	private static readonly ONE_OVERVIEW_WIDTH = 15;
M
Matt Bierner 已提交
162
	public static readonly ENTIRE_DIFF_OVERVIEW_WIDTH = 30;
163
	private static readonly UPDATE_DIFF_DECORATIONS_DELAY = 200; // ms
E
Erich Gamma 已提交
164

A
Alex Dima 已提交
165 166
	private readonly _onDidDispose: Emitter<void> = this._register(new Emitter<void>());
	public readonly onDidDispose: Event<void> = this._onDidDispose.event;
E
Erich Gamma 已提交
167

A
Alex Dima 已提交
168 169 170 171
	private readonly _onDidUpdateDiff: Emitter<void> = this._register(new Emitter<void>());
	public readonly onDidUpdateDiff: Event<void> = this._onDidUpdateDiff.event;

	private readonly id: number;
172
	private _state: editorBrowser.DiffEditorState;
173
	private _updatingDiffProgress: IProgressRunner | null;
E
Erich Gamma 已提交
174

175
	private readonly _domElement: HTMLElement;
A
Alex Dima 已提交
176 177 178
	protected readonly _containerDomElement: HTMLElement;
	private readonly _overviewDomElement: HTMLElement;
	private readonly _overviewViewportDomElement: FastDomNode<HTMLElement>;
E
Erich Gamma 已提交
179

J
Johannes Rieken 已提交
180 181
	private _width: number;
	private _height: number;
A
Alex Dima 已提交
182
	private _reviewHeight: number;
A
Alex Dima 已提交
183
	private readonly _measureDomElementToken: IntervalTimer | null;
E
Erich Gamma 已提交
184

A
Alex Dima 已提交
185
	private readonly originalEditor: CodeEditorWidget;
A
Alex Dima 已提交
186
	private readonly _originalDomNode: HTMLElement;
187
	private readonly _originalEditorState: VisualEditorState;
A
Alex Dima 已提交
188
	private _originalOverviewRuler: editorBrowser.IOverviewRuler | null;
E
Erich Gamma 已提交
189

A
Alex Dima 已提交
190
	private readonly modifiedEditor: CodeEditorWidget;
A
Alex Dima 已提交
191
	private readonly _modifiedDomNode: HTMLElement;
192
	private readonly _modifiedEditorState: VisualEditorState;
A
Alex Dima 已提交
193
	private _modifiedOverviewRuler: editorBrowser.IOverviewRuler | null;
E
Erich Gamma 已提交
194

J
Johannes Rieken 已提交
195 196 197
	private _currentlyChangingViewZones: boolean;
	private _beginUpdateDecorationsTimeout: number;
	private _diffComputationToken: number;
A
Alex Dima 已提交
198
	private _diffComputationResult: IDiffComputationResult | null;
E
Erich Gamma 已提交
199

J
Johannes Rieken 已提交
200 201
	private _isVisible: boolean;
	private _isHandlingScrollEvent: boolean;
E
Erich Gamma 已提交
202 203

	private _ignoreTrimWhitespace: boolean;
204
	private _originalIsEditable: boolean;
E
Erich Gamma 已提交
205

J
Johannes Rieken 已提交
206
	private _renderSideBySide: boolean;
207
	private _maxComputationTime: number;
208
	private _renderIndicators: boolean;
J
Johannes Rieken 已提交
209
	private _enableSplitViewResizing: boolean;
A
Alex Dima 已提交
210
	private _strategy!: IDiffEditorWidgetStyle;
E
Erich Gamma 已提交
211

212
	private readonly _updateDecorationsRunner: RunOnceScheduler;
E
Erich Gamma 已提交
213

214
	private readonly _editorWorkerService: IEditorWorkerService;
215
	protected _contextKeyService: IContextKeyService;
216 217 218
	private readonly _codeEditorService: ICodeEditorService;
	private readonly _themeService: IThemeService;
	private readonly _notificationService: INotificationService;
219

220
	private readonly _reviewPane: DiffReview;
A
Alex Dima 已提交
221

222
	constructor(
J
Johannes Rieken 已提交
223
		domElement: HTMLElement,
224
		options: IDiffEditorOptions,
225
		clipboardService: IClipboardService | null,
226
		@IEditorWorkerService editorWorkerService: IEditorWorkerService,
227
		@IContextKeyService contextKeyService: IContextKeyService,
228
		@IInstantiationService instantiationService: IInstantiationService,
229
		@ICodeEditorService codeEditorService: ICodeEditorService,
230
		@IThemeService themeService: IThemeService,
231 232
		@INotificationService notificationService: INotificationService,
		@IContextMenuService contextMenuService: IContextMenuService,
233
		@IEditorProgressService private readonly _editorProgressService: IEditorProgressService
234
	) {
E
Erich Gamma 已提交
235
		super();
A
Alex Dima 已提交
236

237
		this._editorWorkerService = editorWorkerService;
238
		this._codeEditorService = codeEditorService;
239
		this._contextKeyService = this._register(contextKeyService.createScoped(domElement));
J
Joao Moreno 已提交
240
		this._contextKeyService.createKey('isInDiffEditor', true);
241
		this._themeService = themeService;
242
		this._notificationService = notificationService;
E
Erich Gamma 已提交
243 244

		this.id = (++DIFF_EDITOR_ID);
245
		this._state = editorBrowser.DiffEditorState.Idle;
246
		this._updatingDiffProgress = null;
E
Erich Gamma 已提交
247 248 249 250 251 252 253 254 255 256

		this._domElement = domElement;
		options = options || {};

		// renderSideBySide
		this._renderSideBySide = true;
		if (typeof options.renderSideBySide !== 'undefined') {
			this._renderSideBySide = options.renderSideBySide;
		}

257 258 259 260
		// maxComputationTime
		this._maxComputationTime = 5000;
		if (typeof options.maxComputationTime !== 'undefined') {
			this._maxComputationTime = options.maxComputationTime;
261 262
		}

E
Erich Gamma 已提交
263 264 265 266 267 268
		// ignoreTrimWhitespace
		this._ignoreTrimWhitespace = true;
		if (typeof options.ignoreTrimWhitespace !== 'undefined') {
			this._ignoreTrimWhitespace = options.ignoreTrimWhitespace;
		}

269 270 271 272 273 274
		// renderIndicators
		this._renderIndicators = true;
		if (typeof options.renderIndicators !== 'undefined') {
			this._renderIndicators = options.renderIndicators;
		}

275 276 277 278 279
		this._originalIsEditable = false;
		if (typeof options.originalEditable !== 'undefined') {
			this._originalIsEditable = Boolean(options.originalEditable);
		}

A
Alex Dima 已提交
280
		this._updateDecorationsRunner = this._register(new RunOnceScheduler(() => this._updateDecorations(), 0));
E
Erich Gamma 已提交
281 282

		this._containerDomElement = document.createElement('div');
283
		this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getTheme(), this._renderSideBySide);
E
Erich Gamma 已提交
284 285 286 287
		this._containerDomElement.style.position = 'relative';
		this._containerDomElement.style.height = '100%';
		this._domElement.appendChild(this._containerDomElement);

A
Alex Dima 已提交
288 289 290
		this._overviewViewportDomElement = createFastDomNode(document.createElement('div'));
		this._overviewViewportDomElement.setClassName('diffViewport');
		this._overviewViewportDomElement.setPosition('absolute');
E
Erich Gamma 已提交
291 292 293 294 295

		this._overviewDomElement = document.createElement('div');
		this._overviewDomElement.className = 'diffOverview';
		this._overviewDomElement.style.position = 'absolute';

A
Alex Dima 已提交
296
		this._overviewDomElement.appendChild(this._overviewViewportDomElement.domNode);
E
Erich Gamma 已提交
297

298
		this._register(dom.addStandardDisposableListener(this._overviewDomElement, 'mousedown', (e) => {
E
Erich Gamma 已提交
299 300 301 302
			this.modifiedEditor.delegateVerticalScrollbarMouseDown(e);
		}));
		this._containerDomElement.appendChild(this._overviewDomElement);

A
Alex Dima 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315
		// Create left side
		this._originalDomNode = document.createElement('div');
		this._originalDomNode.className = 'editor original';
		this._originalDomNode.style.position = 'absolute';
		this._originalDomNode.style.height = '100%';
		this._containerDomElement.appendChild(this._originalDomNode);

		// Create right side
		this._modifiedDomNode = document.createElement('div');
		this._modifiedDomNode.className = 'editor modified';
		this._modifiedDomNode.style.position = 'absolute';
		this._modifiedDomNode.style.height = '100%';
		this._containerDomElement.appendChild(this._modifiedDomNode);
E
Erich Gamma 已提交
316 317 318 319 320

		this._beginUpdateDecorationsTimeout = -1;
		this._currentlyChangingViewZones = false;
		this._diffComputationToken = 0;

321 322
		this._originalEditorState = new VisualEditorState(contextMenuService, clipboardService);
		this._modifiedEditorState = new VisualEditorState(contextMenuService, clipboardService);
E
Erich Gamma 已提交
323 324 325 326 327 328

		this._isVisible = true;
		this._isHandlingScrollEvent = false;

		this._width = 0;
		this._height = 0;
A
Alex Dima 已提交
329
		this._reviewHeight = 0;
E
Erich Gamma 已提交
330

A
Alex Dima 已提交
331
		this._diffComputationResult = null;
E
Erich Gamma 已提交
332

333 334
		const leftContextKeyService = this._contextKeyService.createScoped();
		leftContextKeyService.createKey('isInDiffLeftEditor', true);
J
Joao Moreno 已提交
335

336 337 338
		const leftServices = new ServiceCollection();
		leftServices.set(IContextKeyService, leftContextKeyService);
		const leftScopedInstantiationService = instantiationService.createChild(leftServices);
J
Joao Moreno 已提交
339

340 341 342 343 344 345 346
		const rightContextKeyService = this._contextKeyService.createScoped();
		rightContextKeyService.createKey('isInDiffRightEditor', true);

		const rightServices = new ServiceCollection();
		rightServices.set(IContextKeyService, rightContextKeyService);
		const rightScopedInstantiationService = instantiationService.createChild(rightServices);

A
Alex Dima 已提交
347 348 349 350 351
		this.originalEditor = this._createLeftHandSideEditor(options, leftScopedInstantiationService);
		this.modifiedEditor = this._createRightHandSideEditor(options, rightScopedInstantiationService);

		this._originalOverviewRuler = null;
		this._modifiedOverviewRuler = null;
E
Erich Gamma 已提交
352

353 354 355
		this._reviewPane = new DiffReview(this);
		this._containerDomElement.appendChild(this._reviewPane.domNode.domNode);
		this._containerDomElement.appendChild(this._reviewPane.shadow.domNode);
356
		this._containerDomElement.appendChild(this._reviewPane.actionBarContainer.domNode);
357

E
Erich Gamma 已提交
358
		if (options.automaticLayout) {
A
Alex Dima 已提交
359 360 361 362
			this._measureDomElementToken = new IntervalTimer();
			this._measureDomElementToken.cancelAndSet(() => this._measureDomElement(false), 100);
		} else {
			this._measureDomElementToken = null;
E
Erich Gamma 已提交
363 364 365 366 367 368 369 370 371
		}

		// enableSplitViewResizing
		this._enableSplitViewResizing = true;
		if (typeof options.enableSplitViewResizing !== 'undefined') {
			this._enableSplitViewResizing = options.enableSplitViewResizing;
		}

		if (this._renderSideBySide) {
H
Howard Hung 已提交
372
			this._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));
E
Erich Gamma 已提交
373
		} else {
H
Howard Hung 已提交
374
			this._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
E
Erich Gamma 已提交
375
		}
376

377
		this._register(themeService.onThemeChange(t => {
378 379 380
			if (this._strategy && this._strategy.applyColors(t)) {
				this._updateDecorationsRunner.schedule();
			}
381 382
			this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getTheme(), this._renderSideBySide);
		}));
383

384 385
		const contributions: IDiffEditorContributionDescription[] = EditorExtensionsRegistry.getDiffEditorContributions();
		for (const desc of contributions) {
A
Alex Dima 已提交
386
			try {
387
				this._register(instantiationService.createInstance(desc.ctor, this));
A
Alex Dima 已提交
388 389 390 391 392
			} catch (err) {
				onUnexpectedError(err);
			}
		}

393
		this._codeEditorService.addDiffEditor(this);
E
Erich Gamma 已提交
394 395
	}

396 397 398 399 400 401 402 403
	public get ignoreTrimWhitespace(): boolean {
		return this._ignoreTrimWhitespace;
	}

	public get renderSideBySide(): boolean {
		return this._renderSideBySide;
	}

404 405 406 407
	public get maxComputationTime(): number {
		return this._maxComputationTime;
	}

408 409 410 411
	public get renderIndicators(): boolean {
		return this._renderIndicators;
	}

412
	private _setState(newState: editorBrowser.DiffEditorState): void {
413
		if (this._state === newState) {
414 415 416
			return;
		}
		this._state = newState;
417 418 419 420 421 422 423 424 425

		if (this._updatingDiffProgress) {
			this._updatingDiffProgress.done();
			this._updatingDiffProgress = null;
		}

		if (this._state === editorBrowser.DiffEditorState.ComputingDiff) {
			this._updatingDiffProgress = this._editorProgressService.show(true, 1000);
		}
426 427
	}

A
Alex Dima 已提交
428 429 430 431 432 433 434 435 436 437 438 439
	public hasWidgetFocus(): boolean {
		return dom.isAncestor(document.activeElement, this._domElement);
	}

	public diffReviewNext(): void {
		this._reviewPane.next();
	}

	public diffReviewPrev(): void {
		this._reviewPane.prev();
	}

440
	private static _getClassName(theme: ITheme, renderSideBySide: boolean): string {
A
Alex Dima 已提交
441
		let result = 'monaco-diff-editor monaco-editor-background ';
E
Erich Gamma 已提交
442 443 444
		if (renderSideBySide) {
			result += 'side-by-side ';
		}
445
		result += getThemeTypeSelector(theme.type);
E
Erich Gamma 已提交
446 447 448 449 450 451 452 453
		return result;
	}

	private _recreateOverviewRulers(): void {
		if (this._originalOverviewRuler) {
			this._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());
			this._originalOverviewRuler.dispose();
		}
A
Alex Dima 已提交
454 455 456 457
		if (this.originalEditor.hasModel()) {
			this._originalOverviewRuler = this.originalEditor.createOverviewRuler('original diffOverviewRuler')!;
			this._overviewDomElement.appendChild(this._originalOverviewRuler.getDomNode());
		}
E
Erich Gamma 已提交
458 459 460 461 462

		if (this._modifiedOverviewRuler) {
			this._overviewDomElement.removeChild(this._modifiedOverviewRuler.getDomNode());
			this._modifiedOverviewRuler.dispose();
		}
A
Alex Dima 已提交
463 464 465 466
		if (this.modifiedEditor.hasModel()) {
			this._modifiedOverviewRuler = this.modifiedEditor.createOverviewRuler('modified diffOverviewRuler')!;
			this._overviewDomElement.appendChild(this._modifiedOverviewRuler.getDomNode());
		}
E
Erich Gamma 已提交
467 468 469 470

		this._layoutOverviewRulers();
	}

471
	private _createLeftHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget {
A
Alex Dima 已提交
472
		const editor = this._createInnerEditor(instantiationService, this._originalDomNode, this._adjustOptionsForLeftHandSide(options, this._originalIsEditable));
A
Alex Dima 已提交
473

A
Alex Dima 已提交
474
		this._register(editor.onDidScrollChange((e) => {
A
Alex Dima 已提交
475 476 477
			if (this._isHandlingScrollEvent) {
				return;
			}
478
			if (!e.scrollTopChanged && !e.scrollLeftChanged && !e.scrollHeightChanged) {
A
Alex Dima 已提交
479 480 481 482 483 484 485 486
				return;
			}
			this._isHandlingScrollEvent = true;
			this.modifiedEditor.setScrollPosition({
				scrollLeft: e.scrollLeft,
				scrollTop: e.scrollTop
			});
			this._isHandlingScrollEvent = false;
487 488

			this._layoutOverviewViewport();
A
Alex Dima 已提交
489 490
		}));

A
Alex Dima 已提交
491
		this._register(editor.onDidChangeViewZones(() => {
A
Alex Dima 已提交
492 493 494
			this._onViewZonesChanged();
		}));

A
Alex Dima 已提交
495
		this._register(editor.onDidChangeModelContent(() => {
A
Alex Dima 已提交
496 497 498 499
			if (this._isVisible) {
				this._beginUpdateDecorationsSoon();
			}
		}));
A
Alex Dima 已提交
500 501

		return editor;
E
Erich Gamma 已提交
502 503
	}

504
	private _createRightHandSideEditor(options: IDiffEditorOptions, instantiationService: IInstantiationService): CodeEditorWidget {
A
Alex Dima 已提交
505
		const editor = this._createInnerEditor(instantiationService, this._modifiedDomNode, this._adjustOptionsForRightHandSide(options));
A
Alex Dima 已提交
506

A
Alex Dima 已提交
507
		this._register(editor.onDidScrollChange((e) => {
A
Alex Dima 已提交
508 509 510
			if (this._isHandlingScrollEvent) {
				return;
			}
511
			if (!e.scrollTopChanged && !e.scrollLeftChanged && !e.scrollHeightChanged) {
A
Alex Dima 已提交
512 513 514 515 516 517 518 519 520 521 522 523
				return;
			}
			this._isHandlingScrollEvent = true;
			this.originalEditor.setScrollPosition({
				scrollLeft: e.scrollLeft,
				scrollTop: e.scrollTop
			});
			this._isHandlingScrollEvent = false;

			this._layoutOverviewViewport();
		}));

A
Alex Dima 已提交
524
		this._register(editor.onDidChangeViewZones(() => {
A
Alex Dima 已提交
525 526 527
			this._onViewZonesChanged();
		}));

A
Alex Dima 已提交
528
		this._register(editor.onDidChangeConfiguration((e) => {
529
			if (e.hasChanged(EditorOption.fontInfo) && editor.getModel()) {
A
Alex Dima 已提交
530 531 532 533
				this._onViewZonesChanged();
			}
		}));

A
Alex Dima 已提交
534
		this._register(editor.onDidChangeModelContent(() => {
A
Alex Dima 已提交
535 536 537 538
			if (this._isVisible) {
				this._beginUpdateDecorationsSoon();
			}
		}));
A
Alex Dima 已提交
539

540 541 542 543 544 545
		this._register(editor.onDidChangeModelOptions((e) => {
			if (e.tabSize) {
				this._updateDecorationsRunner.schedule();
			}
		}));

A
Alex Dima 已提交
546
		return editor;
E
Erich Gamma 已提交
547 548
	}

549
	protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: IEditorOptions): CodeEditorWidget {
550
		return instantiationService.createInstance(CodeEditorWidget, container, options, {});
A
Alex Dima 已提交
551 552
	}

E
Erich Gamma 已提交
553
	public dispose(): void {
554 555
		this._codeEditorService.removeDiffEditor(this);

556 557 558 559 560
		if (this._beginUpdateDecorationsTimeout !== -1) {
			window.clearTimeout(this._beginUpdateDecorationsTimeout);
			this._beginUpdateDecorationsTimeout = -1;
		}

A
Alex Dima 已提交
561 562 563
		if (this._measureDomElementToken) {
			this._measureDomElementToken.dispose();
		}
E
Erich Gamma 已提交
564 565 566

		this._cleanViewZonesAndDecorations();

567 568 569 570 571 572 573 574
		if (this._originalOverviewRuler) {
			this._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());
			this._originalOverviewRuler.dispose();
		}
		if (this._modifiedOverviewRuler) {
			this._overviewDomElement.removeChild(this._modifiedOverviewRuler.getDomNode());
			this._modifiedOverviewRuler.dispose();
		}
575 576
		this._overviewDomElement.removeChild(this._overviewViewportDomElement.domNode);
		this._containerDomElement.removeChild(this._overviewDomElement);
E
Erich Gamma 已提交
577

578
		this._containerDomElement.removeChild(this._originalDomNode);
A
Alex Dima 已提交
579
		this.originalEditor.dispose();
580 581

		this._containerDomElement.removeChild(this._modifiedDomNode);
A
Alex Dima 已提交
582
		this.modifiedEditor.dispose();
E
Erich Gamma 已提交
583 584 585

		this._strategy.dispose();

586 587 588
		this._containerDomElement.removeChild(this._reviewPane.domNode.domNode);
		this._containerDomElement.removeChild(this._reviewPane.shadow.domNode);
		this._containerDomElement.removeChild(this._reviewPane.actionBarContainer.domNode);
589 590
		this._reviewPane.dispose();

591 592
		this._domElement.removeChild(this._containerDomElement);

A
Alex Dima 已提交
593
		this._onDidDispose.fire();
A
Alex Dima 已提交
594

E
Erich Gamma 已提交
595 596 597 598 599 600 601 602 603 604
		super.dispose();
	}

	//------------ begin IDiffEditor methods

	public getId(): string {
		return this.getEditorType() + ':' + this.id;
	}

	public getEditorType(): string {
A
Alex Dima 已提交
605
		return editorCommon.EditorType.IDiffEditor;
E
Erich Gamma 已提交
606 607
	}

A
Alex Dima 已提交
608
	public getLineChanges(): editorCommon.ILineChange[] | null {
A
Alex Dima 已提交
609 610 611 612
		if (!this._diffComputationResult) {
			return null;
		}
		return this._diffComputationResult.changes;
E
Erich Gamma 已提交
613 614
	}

615 616 617 618
	public getDiffComputationResult(): IDiffComputationResult | null {
		return this._diffComputationResult;
	}

A
Alex Dima 已提交
619
	public getOriginalEditor(): editorBrowser.ICodeEditor {
E
Erich Gamma 已提交
620 621 622
		return this.originalEditor;
	}

A
Alex Dima 已提交
623
	public getModifiedEditor(): editorBrowser.ICodeEditor {
E
Erich Gamma 已提交
624 625 626
		return this.modifiedEditor;
	}

627
	public updateOptions(newOptions: IDiffEditorOptions): void {
E
Erich Gamma 已提交
628 629

		// Handle side by side
A
Alex Dima 已提交
630
		let renderSideBySideChanged = false;
E
Erich Gamma 已提交
631 632 633 634 635 636 637
		if (typeof newOptions.renderSideBySide !== 'undefined') {
			if (this._renderSideBySide !== newOptions.renderSideBySide) {
				this._renderSideBySide = newOptions.renderSideBySide;
				renderSideBySideChanged = true;
			}
		}

638 639
		if (typeof newOptions.maxComputationTime !== 'undefined') {
			this._maxComputationTime = newOptions.maxComputationTime;
640 641 642
			if (this._isVisible) {
				this._beginUpdateDecorationsSoon();
			}
643 644
		}

645 646
		let beginUpdateDecorations = false;

E
Erich Gamma 已提交
647 648 649 650
		if (typeof newOptions.ignoreTrimWhitespace !== 'undefined') {
			if (this._ignoreTrimWhitespace !== newOptions.ignoreTrimWhitespace) {
				this._ignoreTrimWhitespace = newOptions.ignoreTrimWhitespace;
				// Begin comparing
651 652 653 654 655 656 657 658
				beginUpdateDecorations = true;
			}
		}

		if (typeof newOptions.renderIndicators !== 'undefined') {
			if (this._renderIndicators !== newOptions.renderIndicators) {
				this._renderIndicators = newOptions.renderIndicators;
				beginUpdateDecorations = true;
E
Erich Gamma 已提交
659 660 661
			}
		}

662 663 664 665
		if (beginUpdateDecorations) {
			this._beginUpdateDecorations();
		}

666 667 668 669
		if (typeof newOptions.originalEditable !== 'undefined') {
			this._originalIsEditable = Boolean(newOptions.originalEditable);
		}

E
Erich Gamma 已提交
670
		this.modifiedEditor.updateOptions(this._adjustOptionsForRightHandSide(newOptions));
671
		this.originalEditor.updateOptions(this._adjustOptionsForLeftHandSide(newOptions, this._originalIsEditable));
E
Erich Gamma 已提交
672 673 674 675 676 677 678 679 680 681

		// enableSplitViewResizing
		if (typeof newOptions.enableSplitViewResizing !== 'undefined') {
			this._enableSplitViewResizing = newOptions.enableSplitViewResizing;
		}
		this._strategy.setEnableSplitViewResizing(this._enableSplitViewResizing);

		// renderSideBySide
		if (renderSideBySideChanged) {
			if (this._renderSideBySide) {
H
Howard Hung 已提交
682
				this._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));
E
Erich Gamma 已提交
683
			} else {
H
Howard Hung 已提交
684
				this._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
E
Erich Gamma 已提交
685
			}
686 687
			// Update class name
			this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getTheme(), this._renderSideBySide);
E
Erich Gamma 已提交
688 689 690
		}
	}

A
Alex Dima 已提交
691
	public getModel(): editorCommon.IDiffEditorModel {
E
Erich Gamma 已提交
692
		return {
A
Alex Dima 已提交
693 694
			original: this.originalEditor.getModel()!,
			modified: this.modifiedEditor.getModel()!
E
Erich Gamma 已提交
695 696 697
		};
	}

J
Johannes Rieken 已提交
698
	public setModel(model: editorCommon.IDiffEditorModel): void {
E
Erich Gamma 已提交
699 700 701 702 703 704 705 706 707 708 709 710 711
		// Guard us against partial null model
		if (model && (!model.original || !model.modified)) {
			throw new Error(!model.original ? 'DiffEditorWidget.setModel: Original model is null' : 'DiffEditorWidget.setModel: Modified model is null');
		}

		// Remove all view zones & decorations
		this._cleanViewZonesAndDecorations();

		// Update code editor models
		this.originalEditor.setModel(model ? model.original : null);
		this.modifiedEditor.setModel(model ? model.modified : null);
		this._updateDecorationsRunner.cancel();

712 713
		// this.originalEditor.onDidChangeModelOptions

E
Erich Gamma 已提交
714 715 716 717 718 719
		if (model) {
			this.originalEditor.setScrollTop(0);
			this.modifiedEditor.setScrollTop(0);
		}

		// Disable any diff computations that will come in
A
Alex Dima 已提交
720
		this._diffComputationResult = null;
E
Erich Gamma 已提交
721
		this._diffComputationToken++;
722
		this._setState(editorBrowser.DiffEditorState.Idle);
E
Erich Gamma 已提交
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737

		if (model) {
			this._recreateOverviewRulers();

			// Begin comparing
			this._beginUpdateDecorations();
		}

		this._layoutOverviewViewport();
	}

	public getDomNode(): HTMLElement {
		return this._domElement;
	}

A
Alex Dima 已提交
738
	public getVisibleColumnFromPosition(position: IPosition): number {
E
Erich Gamma 已提交
739 740 741
		return this.modifiedEditor.getVisibleColumnFromPosition(position);
	}

742 743 744 745
	public getStatusbarColumn(position: IPosition): number {
		return this.modifiedEditor.getStatusbarColumn(position);
	}

A
Alex Dima 已提交
746
	public getPosition(): Position | null {
E
Erich Gamma 已提交
747 748 749
		return this.modifiedEditor.getPosition();
	}

750 751
	public setPosition(position: IPosition): void {
		this.modifiedEditor.setPosition(position);
E
Erich Gamma 已提交
752 753
	}

754 755
	public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLine(lineNumber, scrollType);
E
Erich Gamma 已提交
756 757
	}

758 759
	public revealLineInCenter(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLineInCenter(lineNumber, scrollType);
E
Erich Gamma 已提交
760 761
	}

762 763
	public revealLineInCenterIfOutsideViewport(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLineInCenterIfOutsideViewport(lineNumber, scrollType);
E
Erich Gamma 已提交
764 765
	}

766 767
	public revealLineNearTop(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLineNearTop(lineNumber, scrollType);
768 769
	}

770 771
	public revealPosition(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealPosition(position, scrollType);
E
Erich Gamma 已提交
772 773
	}

774 775
	public revealPositionInCenter(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealPositionInCenter(position, scrollType);
E
Erich Gamma 已提交
776 777
	}

778 779
	public revealPositionInCenterIfOutsideViewport(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealPositionInCenterIfOutsideViewport(position, scrollType);
E
Erich Gamma 已提交
780 781
	}

782 783
	public revealPositionNearTop(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealPositionNearTop(position, scrollType);
784 785
	}

A
Alex Dima 已提交
786
	public getSelection(): Selection | null {
E
Erich Gamma 已提交
787 788 789
		return this.modifiedEditor.getSelection();
	}

A
Alex Dima 已提交
790
	public getSelections(): Selection[] | null {
E
Erich Gamma 已提交
791 792 793
		return this.modifiedEditor.getSelections();
	}

794 795 796 797 798 799
	public setSelection(range: IRange): void;
	public setSelection(editorRange: Range): void;
	public setSelection(selection: ISelection): void;
	public setSelection(editorSelection: Selection): void;
	public setSelection(something: any): void {
		this.modifiedEditor.setSelection(something);
E
Erich Gamma 已提交
800 801
	}

802
	public setSelections(ranges: readonly ISelection[]): void {
E
Erich Gamma 已提交
803 804 805
		this.modifiedEditor.setSelections(ranges);
	}

806 807
	public revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLines(startLineNumber, endLineNumber, scrollType);
E
Erich Gamma 已提交
808 809
	}

810 811
	public revealLinesInCenter(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLinesInCenter(startLineNumber, endLineNumber, scrollType);
E
Erich Gamma 已提交
812 813
	}

814 815
	public revealLinesInCenterIfOutsideViewport(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLinesInCenterIfOutsideViewport(startLineNumber, endLineNumber, scrollType);
E
Erich Gamma 已提交
816 817
	}

818 819
	public revealLinesNearTop(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLinesNearTop(startLineNumber, endLineNumber, scrollType);
820 821
	}

822 823
	public revealRange(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void {
		this.modifiedEditor.revealRange(range, scrollType, revealVerticalInCenter, revealHorizontal);
E
Erich Gamma 已提交
824 825
	}

826 827
	public revealRangeInCenter(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealRangeInCenter(range, scrollType);
E
Erich Gamma 已提交
828 829
	}

830 831
	public revealRangeInCenterIfOutsideViewport(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealRangeInCenterIfOutsideViewport(range, scrollType);
E
Erich Gamma 已提交
832 833
	}

834 835
	public revealRangeNearTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealRangeNearTop(range, scrollType);
836 837
	}

838 839
	public revealRangeAtTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealRangeAtTop(range, scrollType);
840 841
	}

A
Alex Dima 已提交
842
	public getSupportedActions(): editorCommon.IEditorAction[] {
843 844 845
		return this.modifiedEditor.getSupportedActions();
	}

A
Alex Dima 已提交
846
	public saveViewState(): editorCommon.IDiffEditorViewState {
A
Alex Dima 已提交
847 848
		let originalViewState = this.originalEditor.saveViewState();
		let modifiedViewState = this.modifiedEditor.saveViewState();
E
Erich Gamma 已提交
849 850 851 852 853 854
		return {
			original: originalViewState,
			modified: modifiedViewState
		};
	}

A
Alex Dima 已提交
855
	public restoreViewState(s: editorCommon.IDiffEditorViewState): void {
A
Alex Dima 已提交
856
		if (s.original && s.modified) {
A
Alex Dima 已提交
857
			let diffEditorState = <editorCommon.IDiffEditorViewState>s;
E
Erich Gamma 已提交
858 859 860 861 862
			this.originalEditor.restoreViewState(diffEditorState.original);
			this.modifiedEditor.restoreViewState(diffEditorState.modified);
		}
	}

J
Johannes Rieken 已提交
863
	public layout(dimension?: editorCommon.IDimension): void {
E
Erich Gamma 已提交
864 865 866 867 868 869 870
		this._measureDomElement(false, dimension);
	}

	public focus(): void {
		this.modifiedEditor.focus();
	}

A
Alex Dima 已提交
871 872
	public hasTextFocus(): boolean {
		return this.originalEditor.hasTextFocus() || this.modifiedEditor.hasTextFocus();
E
Erich Gamma 已提交
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
	}

	public onVisible(): void {
		this._isVisible = true;
		this.originalEditor.onVisible();
		this.modifiedEditor.onVisible();
		// Begin comparing
		this._beginUpdateDecorations();
	}

	public onHide(): void {
		this._isVisible = false;
		this.originalEditor.onHide();
		this.modifiedEditor.onHide();
		// Remove all view zones & decorations
		this._cleanViewZonesAndDecorations();
	}

J
Johannes Rieken 已提交
891
	public trigger(source: string, handlerId: string, payload: any): void {
E
Erich Gamma 已提交
892 893 894
		this.modifiedEditor.trigger(source, handlerId, payload);
	}

895
	public changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {
E
Erich Gamma 已提交
896 897 898 899 900 901 902 903 904
		return this.modifiedEditor.changeDecorations(callback);
	}

	//------------ end IDiffEditor methods



	//------------ begin layouting methods

J
Johannes Rieken 已提交
905
	private _measureDomElement(forceDoLayoutCall: boolean, dimensions?: editorCommon.IDimension): void {
906 907 908 909
		dimensions = dimensions || {
			width: this._containerDomElement.clientWidth,
			height: this._containerDomElement.clientHeight
		};
E
Erich Gamma 已提交
910 911

		if (dimensions.width <= 0) {
912 913
			this._width = 0;
			this._height = 0;
A
Alex Dima 已提交
914
			this._reviewHeight = 0;
E
Erich Gamma 已提交
915 916 917 918 919 920 921 922 923 924
			return;
		}

		if (!forceDoLayoutCall && dimensions.width === this._width && dimensions.height === this._height) {
			// Nothing has changed
			return;
		}

		this._width = dimensions.width;
		this._height = dimensions.height;
925
		this._reviewHeight = this._reviewPane.isVisible() ? this._height : 0;
E
Erich Gamma 已提交
926 927 928 929 930

		this._doLayout();
	}

	private _layoutOverviewRulers(): void {
A
Alex Dima 已提交
931 932 933
		if (!this._originalOverviewRuler || !this._modifiedOverviewRuler) {
			return;
		}
A
Alex Dima 已提交
934 935
		let freeSpace = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH - 2 * DiffEditorWidget.ONE_OVERVIEW_WIDTH;
		let layoutInfo = this.modifiedEditor.getLayoutInfo();
E
Erich Gamma 已提交
936
		if (layoutInfo) {
A
Alex Dima 已提交
937
			this._originalOverviewRuler.setLayout({
E
Erich Gamma 已提交
938 939 940
				top: 0,
				width: DiffEditorWidget.ONE_OVERVIEW_WIDTH,
				right: freeSpace + DiffEditorWidget.ONE_OVERVIEW_WIDTH,
A
Alex Dima 已提交
941
				height: (this._height - this._reviewHeight)
A
Alex Dima 已提交
942 943
			});
			this._modifiedOverviewRuler.setLayout({
E
Erich Gamma 已提交
944 945 946
				top: 0,
				right: 0,
				width: DiffEditorWidget.ONE_OVERVIEW_WIDTH,
A
Alex Dima 已提交
947
				height: (this._height - this._reviewHeight)
A
Alex Dima 已提交
948
			});
E
Erich Gamma 已提交
949 950 951 952 953 954 955 956 957 958 959 960
		}
	}

	//------------ end layouting methods

	private _onViewZonesChanged(): void {
		if (this._currentlyChangingViewZones) {
			return;
		}
		this._updateDecorationsRunner.schedule();
	}

A
Alex Dima 已提交
961 962 963 964 965 966 967 968 969
	private _beginUpdateDecorationsSoon(): void {
		// Clear previous timeout if necessary
		if (this._beginUpdateDecorationsTimeout !== -1) {
			window.clearTimeout(this._beginUpdateDecorationsTimeout);
			this._beginUpdateDecorationsTimeout = -1;
		}
		this._beginUpdateDecorationsTimeout = window.setTimeout(() => this._beginUpdateDecorations(), DiffEditorWidget.UPDATE_DIFF_DECORATIONS_DELAY);
	}

970 971
	private _lastOriginalWarning: URI | null = null;
	private _lastModifiedWarning: URI | null = null;
972

A
Alex Dima 已提交
973
	private static _equals(a: URI | null, b: URI | null): boolean {
974 975 976 977 978 979 980 981 982
		if (!a && !b) {
			return true;
		}
		if (!a || !b) {
			return false;
		}
		return (a.toString() === b.toString());
	}

E
Erich Gamma 已提交
983 984
	private _beginUpdateDecorations(): void {
		this._beginUpdateDecorationsTimeout = -1;
985 986 987
		const currentOriginalModel = this.originalEditor.getModel();
		const currentModifiedModel = this.modifiedEditor.getModel();
		if (!currentOriginalModel || !currentModifiedModel) {
E
Erich Gamma 已提交
988 989 990 991 992 993 994
			return;
		}

		// Prevent old diff requests to come if a new request has been initiated
		// The best method would be to call cancel on the Promise, but this is not
		// yet supported, so using tokens for now.
		this._diffComputationToken++;
A
Alex Dima 已提交
995
		let currentToken = this._diffComputationToken;
996
		this._setState(editorBrowser.DiffEditorState.ComputingDiff);
E
Erich Gamma 已提交
997

998 999 1000 1001 1002 1003 1004
		if (!this._editorWorkerService.canComputeDiff(currentOriginalModel.uri, currentModifiedModel.uri)) {
			if (
				!DiffEditorWidget._equals(currentOriginalModel.uri, this._lastOriginalWarning)
				|| !DiffEditorWidget._equals(currentModifiedModel.uri, this._lastModifiedWarning)
			) {
				this._lastOriginalWarning = currentOriginalModel.uri;
				this._lastModifiedWarning = currentModifiedModel.uri;
1005
				this._notificationService.warn(nls.localize("diff.tooLarge", "Cannot compare files because one file is too large."));
1006 1007 1008 1009
			}
			return;
		}

1010
		this._editorWorkerService.computeDiff(currentOriginalModel.uri, currentModifiedModel.uri, this._ignoreTrimWhitespace, this._maxComputationTime).then((result) => {
1011 1012 1013
			if (currentToken === this._diffComputationToken
				&& currentOriginalModel === this.originalEditor.getModel()
				&& currentModifiedModel === this.modifiedEditor.getModel()
J
Johannes Rieken 已提交
1014
			) {
1015
				this._setState(editorBrowser.DiffEditorState.DiffComputed);
A
Alex Dima 已提交
1016
				this._diffComputationResult = result;
1017
				this._updateDecorationsRunner.schedule();
A
Alex Dima 已提交
1018
				this._onDidUpdateDiff.fire();
1019 1020 1021 1022 1023
			}
		}, (error) => {
			if (currentToken === this._diffComputationToken
				&& currentOriginalModel === this.originalEditor.getModel()
				&& currentModifiedModel === this.modifiedEditor.getModel()
J
Johannes Rieken 已提交
1024
			) {
1025
				this._setState(editorBrowser.DiffEditorState.DiffComputed);
A
Alex Dima 已提交
1026
				this._diffComputationResult = null;
E
Erich Gamma 已提交
1027 1028
				this._updateDecorationsRunner.schedule();
			}
1029
		});
E
Erich Gamma 已提交
1030 1031 1032 1033 1034 1035 1036 1037
	}

	private _cleanViewZonesAndDecorations(): void {
		this._originalEditorState.clean(this.originalEditor);
		this._modifiedEditorState.clean(this.modifiedEditor);
	}

	private _updateDecorations(): void {
A
Alex Dima 已提交
1038
		if (!this.originalEditor.getModel() || !this.modifiedEditor.getModel() || !this._originalOverviewRuler || !this._modifiedOverviewRuler) {
1039 1040
			return;
		}
A
Alex Dima 已提交
1041
		const lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);
E
Erich Gamma 已提交
1042

A
Alex Dima 已提交
1043 1044
		let foreignOriginal = this._originalEditorState.getForeignViewZones(this.originalEditor.getWhitespaces());
		let foreignModified = this._modifiedEditorState.getForeignViewZones(this.modifiedEditor.getWhitespaces());
E
Erich Gamma 已提交
1045

1046
		let diffDecorations = this._strategy.getEditorsDiffDecorations(lineChanges, this._ignoreTrimWhitespace, this._renderIndicators, foreignOriginal, foreignModified, this.originalEditor, this.modifiedEditor);
E
Erich Gamma 已提交
1047 1048 1049

		try {
			this._currentlyChangingViewZones = true;
A
Alex Dima 已提交
1050 1051
			this._originalEditorState.apply(this.originalEditor, this._originalOverviewRuler, diffDecorations.original, false);
			this._modifiedEditorState.apply(this.modifiedEditor, this._modifiedOverviewRuler, diffDecorations.modified, true);
E
Erich Gamma 已提交
1052 1053 1054 1055 1056
		} finally {
			this._currentlyChangingViewZones = false;
		}
	}

1057 1058
	private _adjustOptionsForSubEditor(options: IDiffEditorOptions): IDiffEditorOptions {
		let clonedOptions: IDiffEditorOptions = objects.deepClone(options || {});
A
Alex Dima 已提交
1059
		clonedOptions.inDiffEditor = true;
1060
		clonedOptions.wordWrap = 'off';
1061
		clonedOptions.wordWrapMinified = false;
E
Erich Gamma 已提交
1062 1063 1064
		clonedOptions.automaticLayout = false;
		clonedOptions.scrollbar = clonedOptions.scrollbar || {};
		clonedOptions.scrollbar.vertical = 'visible';
A
Alex Dima 已提交
1065
		clonedOptions.folding = false;
1066
		clonedOptions.codeLens = false;
J
Joao Moreno 已提交
1067
		clonedOptions.fixedOverflowWidgets = true;
1068
		// clonedOptions.lineDecorationsWidth = '2ch';
1069 1070 1071
		if (!clonedOptions.minimap) {
			clonedOptions.minimap = {};
		}
1072
		clonedOptions.minimap.enabled = false;
E
Erich Gamma 已提交
1073 1074 1075
		return clonedOptions;
	}

1076
	private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean): IEditorOptions {
1077 1078
		let result = this._adjustOptionsForSubEditor(options);
		result.readOnly = !isEditable;
1079
		result.extraEditorClassName = 'original-in-monaco-diff-editor';
1080 1081 1082
		return result;
	}

1083
	private _adjustOptionsForRightHandSide(options: IDiffEditorOptions): IEditorOptions {
1084
		let result = this._adjustOptionsForSubEditor(options);
A
Alex Dima 已提交
1085
		result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
A
Alex Dima 已提交
1086
		result.scrollbar!.verticalHasArrows = false;
1087
		result.extraEditorClassName = 'modified-in-monaco-diff-editor';
1088
		return result;
E
Erich Gamma 已提交
1089 1090
	}

1091 1092 1093 1094
	public doLayout(): void {
		this._measureDomElement(true);
	}

E
Erich Gamma 已提交
1095
	private _doLayout(): void {
A
Alex Dima 已提交
1096
		let splitPoint = this._strategy.layout();
E
Erich Gamma 已提交
1097 1098 1099 1100 1101 1102 1103 1104

		this._originalDomNode.style.width = splitPoint + 'px';
		this._originalDomNode.style.left = '0px';

		this._modifiedDomNode.style.width = (this._width - splitPoint) + 'px';
		this._modifiedDomNode.style.left = splitPoint + 'px';

		this._overviewDomElement.style.top = '0px';
A
Alex Dima 已提交
1105
		this._overviewDomElement.style.height = (this._height - this._reviewHeight) + 'px';
E
Erich Gamma 已提交
1106 1107
		this._overviewDomElement.style.width = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH + 'px';
		this._overviewDomElement.style.left = (this._width - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH) + 'px';
A
Alex Dima 已提交
1108 1109
		this._overviewViewportDomElement.setWidth(DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH);
		this._overviewViewportDomElement.setHeight(30);
E
Erich Gamma 已提交
1110

A
Alex Dima 已提交
1111 1112
		this.originalEditor.layout({ width: splitPoint, height: (this._height - this._reviewHeight) });
		this.modifiedEditor.layout({ width: this._width - splitPoint - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH, height: (this._height - this._reviewHeight) });
E
Erich Gamma 已提交
1113 1114 1115 1116 1117

		if (this._originalOverviewRuler || this._modifiedOverviewRuler) {
			this._layoutOverviewRulers();
		}

A
Alex Dima 已提交
1118 1119
		this._reviewPane.layout(this._height - this._reviewHeight, this._width, this._reviewHeight);

E
Erich Gamma 已提交
1120 1121 1122 1123
		this._layoutOverviewViewport();
	}

	private _layoutOverviewViewport(): void {
A
Alex Dima 已提交
1124
		let layout = this._computeOverviewViewport();
E
Erich Gamma 已提交
1125
		if (!layout) {
A
Alex Dima 已提交
1126 1127
			this._overviewViewportDomElement.setTop(0);
			this._overviewViewportDomElement.setHeight(0);
E
Erich Gamma 已提交
1128
		} else {
A
Alex Dima 已提交
1129 1130
			this._overviewViewportDomElement.setTop(layout.top);
			this._overviewViewportDomElement.setHeight(layout.height);
E
Erich Gamma 已提交
1131 1132 1133
		}
	}

A
Alex Dima 已提交
1134
	private _computeOverviewViewport(): { height: number; top: number; } | null {
A
Alex Dima 已提交
1135
		let layoutInfo = this.modifiedEditor.getLayoutInfo();
E
Erich Gamma 已提交
1136 1137 1138 1139
		if (!layoutInfo) {
			return null;
		}

A
Alex Dima 已提交
1140 1141
		let scrollTop = this.modifiedEditor.getScrollTop();
		let scrollHeight = this.modifiedEditor.getScrollHeight();
E
Erich Gamma 已提交
1142

1143
		let computedAvailableSize = Math.max(0, layoutInfo.height);
A
Alex Dima 已提交
1144 1145
		let computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * 0);
		let computedRatio = scrollHeight > 0 ? (computedRepresentableSize / scrollHeight) : 0;
E
Erich Gamma 已提交
1146

1147
		let computedSliderSize = Math.max(0, Math.floor(layoutInfo.height * computedRatio));
A
Alex Dima 已提交
1148
		let computedSliderPosition = Math.floor(scrollTop * computedRatio);
E
Erich Gamma 已提交
1149 1150 1151 1152 1153 1154 1155

		return {
			height: computedSliderSize,
			top: computedSliderPosition
		};
	}

J
Johannes Rieken 已提交
1156
	private _createDataSource(): IDataSource {
E
Erich Gamma 已提交
1157 1158 1159 1160 1161 1162
		return {
			getWidth: () => {
				return this._width;
			},

			getHeight: () => {
A
Alex Dima 已提交
1163
				return (this._height - this._reviewHeight);
E
Erich Gamma 已提交
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
			},

			getContainerDomNode: () => {
				return this._containerDomElement;
			},

			relayoutEditors: () => {
				this._doLayout();
			},

			getOriginalEditor: () => {
				return this.originalEditor;
			},

			getModifiedEditor: () => {
				return this.modifiedEditor;
			}
		};
	}

J
Johannes Rieken 已提交
1184
	private _setStrategy(newStrategy: IDiffEditorWidgetStyle): void {
E
Erich Gamma 已提交
1185 1186 1187 1188 1189
		if (this._strategy) {
			this._strategy.dispose();
		}

		this._strategy = newStrategy;
1190
		newStrategy.applyColors(this._themeService.getTheme());
E
Erich Gamma 已提交
1191

A
Alex Dima 已提交
1192
		if (this._diffComputationResult) {
E
Erich Gamma 已提交
1193 1194 1195 1196 1197 1198 1199
			this._updateDecorations();
		}

		// Just do a layout, the strategy might need it
		this._measureDomElement(true);
	}

A
Alex Dima 已提交
1200
	private _getLineChangeAtOrBeforeLineNumber(lineNumber: number, startLineNumberExtractor: (lineChange: editorCommon.ILineChange) => number): editorCommon.ILineChange | null {
A
Alex Dima 已提交
1201 1202
		const lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);
		if (lineChanges.length === 0 || lineNumber < startLineNumberExtractor(lineChanges[0])) {
E
Erich Gamma 已提交
1203 1204 1205 1206
			// There are no changes or `lineNumber` is before the first change
			return null;
		}

A
Alex Dima 已提交
1207
		let min = 0, max = lineChanges.length - 1;
E
Erich Gamma 已提交
1208
		while (min < max) {
A
Alex Dima 已提交
1209
			let mid = Math.floor((min + max) / 2);
A
Alex Dima 已提交
1210
			let midStart = startLineNumberExtractor(lineChanges[mid]);
1211
			let midEnd = (mid + 1 <= max ? startLineNumberExtractor(lineChanges[mid + 1]) : Constants.MAX_SAFE_SMALL_INTEGER);
E
Erich Gamma 已提交
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222

			if (lineNumber < midStart) {
				max = mid - 1;
			} else if (lineNumber >= midEnd) {
				min = mid + 1;
			} else {
				// HIT!
				min = mid;
				max = mid;
			}
		}
A
Alex Dima 已提交
1223
		return lineChanges[min];
E
Erich Gamma 已提交
1224 1225 1226
	}

	private _getEquivalentLineForOriginalLineNumber(lineNumber: number): number {
A
Alex Dima 已提交
1227
		let lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.originalStartLineNumber);
E
Erich Gamma 已提交
1228 1229 1230 1231 1232

		if (!lineChange) {
			return lineNumber;
		}

A
Alex Dima 已提交
1233 1234 1235 1236
		let originalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);
		let modifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);
		let lineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? (lineChange.originalEndLineNumber - lineChange.originalStartLineNumber + 1) : 0);
		let lineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? (lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1) : 0);
E
Erich Gamma 已提交
1237 1238


A
Alex Dima 已提交
1239
		let delta = lineNumber - originalEquivalentLineNumber;
E
Erich Gamma 已提交
1240 1241 1242 1243 1244

		if (delta <= lineChangeOriginalLength) {
			return modifiedEquivalentLineNumber + Math.min(delta, lineChangeModifiedLength);
		}

J
Johannes Rieken 已提交
1245
		return modifiedEquivalentLineNumber + lineChangeModifiedLength - lineChangeOriginalLength + delta;
E
Erich Gamma 已提交
1246 1247 1248
	}

	private _getEquivalentLineForModifiedLineNumber(lineNumber: number): number {
A
Alex Dima 已提交
1249
		let lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.modifiedStartLineNumber);
E
Erich Gamma 已提交
1250 1251 1252 1253 1254

		if (!lineChange) {
			return lineNumber;
		}

A
Alex Dima 已提交
1255 1256 1257 1258
		let originalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);
		let modifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);
		let lineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? (lineChange.originalEndLineNumber - lineChange.originalStartLineNumber + 1) : 0);
		let lineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? (lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1) : 0);
E
Erich Gamma 已提交
1259 1260


A
Alex Dima 已提交
1261
		let delta = lineNumber - modifiedEquivalentLineNumber;
E
Erich Gamma 已提交
1262 1263 1264 1265 1266

		if (delta <= lineChangeModifiedLength) {
			return originalEquivalentLineNumber + Math.min(delta, lineChangeOriginalLength);
		}

J
Johannes Rieken 已提交
1267
		return originalEquivalentLineNumber + lineChangeOriginalLength - lineChangeModifiedLength + delta;
E
Erich Gamma 已提交
1268 1269
	}

A
Alex Dima 已提交
1270
	public getDiffLineInformationForOriginal(lineNumber: number): editorBrowser.IDiffLineInformation | null {
A
Alex Dima 已提交
1271
		if (!this._diffComputationResult) {
E
Erich Gamma 已提交
1272 1273 1274 1275 1276 1277 1278 1279
			// Cannot answer that which I don't know
			return null;
		}
		return {
			equivalentLineNumber: this._getEquivalentLineForOriginalLineNumber(lineNumber)
		};
	}

A
Alex Dima 已提交
1280
	public getDiffLineInformationForModified(lineNumber: number): editorBrowser.IDiffLineInformation | null {
A
Alex Dima 已提交
1281
		if (!this._diffComputationResult) {
E
Erich Gamma 已提交
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
			// Cannot answer that which I don't know
			return null;
		}
		return {
			equivalentLineNumber: this._getEquivalentLineForModifiedLineNumber(lineNumber)
		};
	}
}

interface IDataSource {
	getWidth(): number;
	getHeight(): number;
	getContainerDomNode(): HTMLElement;
	relayoutEditors(): void;

A
Alex Dima 已提交
1297 1298
	getOriginalEditor(): editorBrowser.ICodeEditor;
	getModifiedEditor(): editorBrowser.ICodeEditor;
E
Erich Gamma 已提交
1299 1300
}

A
Alex Dima 已提交
1301
abstract class DiffEditorWidgetStyle extends Disposable implements IDiffEditorWidgetStyle {
E
Erich Gamma 已提交
1302

J
Johannes Rieken 已提交
1303
	_dataSource: IDataSource;
A
Alex Dima 已提交
1304 1305
	_insertColor: Color | null;
	_removeColor: Color | null;
E
Erich Gamma 已提交
1306

J
Johannes Rieken 已提交
1307
	constructor(dataSource: IDataSource) {
A
Alex Dima 已提交
1308
		super();
E
Erich Gamma 已提交
1309
		this._dataSource = dataSource;
A
Alex Dima 已提交
1310 1311
		this._insertColor = null;
		this._removeColor = null;
E
Erich Gamma 已提交
1312 1313
	}

1314 1315 1316 1317 1318 1319 1320 1321 1322
	public applyColors(theme: ITheme): boolean {
		let newInsertColor = (theme.getColor(diffInserted) || defaultInsertColor).transparent(2);
		let newRemoveColor = (theme.getColor(diffRemoved) || defaultRemoveColor).transparent(2);
		let hasChanges = !newInsertColor.equals(this._insertColor) || !newRemoveColor.equals(this._removeColor);
		this._insertColor = newInsertColor;
		this._removeColor = newRemoveColor;
		return hasChanges;
	}

A
Alex Dima 已提交
1323
	public getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones {
E
Erich Gamma 已提交
1324 1325 1326 1327 1328 1329 1330
		// Get view zones
		modifiedWhitespaces = modifiedWhitespaces.sort((a, b) => {
			return a.afterLineNumber - b.afterLineNumber;
		});
		originalWhitespaces = originalWhitespaces.sort((a, b) => {
			return a.afterLineNumber - b.afterLineNumber;
		});
1331
		let zones = this._getViewZones(lineChanges, originalWhitespaces, modifiedWhitespaces, originalEditor, modifiedEditor, renderIndicators);
E
Erich Gamma 已提交
1332 1333

		// Get decorations & overview ruler zones
1334 1335
		let originalDecorations = this._getOriginalEditorDecorations(lineChanges, ignoreTrimWhitespace, renderIndicators, originalEditor, modifiedEditor);
		let modifiedDecorations = this._getModifiedEditorDecorations(lineChanges, ignoreTrimWhitespace, renderIndicators, originalEditor, modifiedEditor);
E
Erich Gamma 已提交
1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350

		return {
			original: {
				decorations: originalDecorations.decorations,
				overviewZones: originalDecorations.overviewZones,
				zones: zones.original
			},
			modified: {
				decorations: modifiedDecorations.decorations,
				overviewZones: modifiedDecorations.overviewZones,
				zones: zones.modified
			}
		};
	}

1351 1352 1353
	protected abstract _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones;
	protected abstract _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations;
	protected abstract _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations;
A
Alex Dima 已提交
1354 1355 1356

	public abstract setEnableSplitViewResizing(enableSplitViewResizing: boolean): void;
	public abstract layout(): number;
E
Erich Gamma 已提交
1357 1358
}

A
Alex Dima 已提交
1359
interface IMyViewZone {
E
Erich Gamma 已提交
1360
	shouldNotShrink?: boolean;
A
Alex Dima 已提交
1361 1362 1363 1364 1365
	afterLineNumber: number;
	heightInLines: number;
	minWidthInPx?: number;
	domNode: HTMLElement | null;
	marginDomNode?: HTMLElement | null;
1366
	diff?: IDiffLinesChange;
E
Erich Gamma 已提交
1367 1368 1369 1370 1371
}

class ForeignViewZonesIterator {

	private _index: number;
1372
	private readonly _source: IEditorWhitespace[];
A
Alex Dima 已提交
1373
	public current: IEditorWhitespace | null;
E
Erich Gamma 已提交
1374

A
Alex Dima 已提交
1375
	constructor(source: IEditorWhitespace[]) {
E
Erich Gamma 已提交
1376 1377
		this._source = source;
		this._index = -1;
A
Alex Dima 已提交
1378
		this.current = null;
E
Erich Gamma 已提交
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
		this.advance();
	}

	public advance(): void {
		this._index++;
		if (this._index < this._source.length) {
			this.current = this._source[this._index];
		} else {
			this.current = null;
		}
	}
}

1392
abstract class ViewZonesComputer {
E
Erich Gamma 已提交
1393

1394 1395
	private readonly lineChanges: editorCommon.ILineChange[];
	private readonly originalForeignVZ: IEditorWhitespace[];
1396
	private readonly originalLineHeight: number;
1397
	private readonly modifiedForeignVZ: IEditorWhitespace[];
1398
	private readonly modifiedLineHeight: number;
E
Erich Gamma 已提交
1399

1400
	constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], originalLineHeight: number, modifiedForeignVZ: IEditorWhitespace[], modifiedLineHeight: number) {
E
Erich Gamma 已提交
1401 1402
		this.lineChanges = lineChanges;
		this.originalForeignVZ = originalForeignVZ;
1403
		this.originalLineHeight = originalLineHeight;
E
Erich Gamma 已提交
1404
		this.modifiedForeignVZ = modifiedForeignVZ;
1405
		this.modifiedLineHeight = modifiedLineHeight;
E
Erich Gamma 已提交
1406 1407 1408
	}

	public getViewZones(): IEditorsZones {
A
Alex Dima 已提交
1409
		let result: { original: IMyViewZone[]; modified: IMyViewZone[]; } = {
E
Erich Gamma 已提交
1410 1411 1412 1413
			original: [],
			modified: []
		};

A
Alex Dima 已提交
1414 1415 1416 1417 1418 1419 1420 1421
		let lineChangeModifiedLength: number = 0;
		let lineChangeOriginalLength: number = 0;
		let originalEquivalentLineNumber: number = 0;
		let modifiedEquivalentLineNumber: number = 0;
		let originalEndEquivalentLineNumber: number = 0;
		let modifiedEndEquivalentLineNumber: number = 0;

		let sortMyViewZones = (a: IMyViewZone, b: IMyViewZone) => {
E
Erich Gamma 已提交
1422 1423 1424
			return a.afterLineNumber - b.afterLineNumber;
		};

A
Alex Dima 已提交
1425
		let addAndCombineIfPossible = (destination: IMyViewZone[], item: IMyViewZone) => {
E
Erich Gamma 已提交
1426
			if (item.domNode === null && destination.length > 0) {
A
Alex Dima 已提交
1427
				let lastItem = destination[destination.length - 1];
E
Erich Gamma 已提交
1428 1429 1430 1431 1432 1433 1434 1435
				if (lastItem.afterLineNumber === item.afterLineNumber && lastItem.domNode === null) {
					lastItem.heightInLines += item.heightInLines;
					return;
				}
			}
			destination.push(item);
		};

A
Alex Dima 已提交
1436 1437
		let modifiedForeignVZ = new ForeignViewZonesIterator(this.modifiedForeignVZ);
		let originalForeignVZ = new ForeignViewZonesIterator(this.originalForeignVZ);
E
Erich Gamma 已提交
1438 1439

		// In order to include foreign view zones after the last line change, the for loop will iterate once more after the end of the `lineChanges` array
A
Alex Dima 已提交
1440 1441
		for (let i = 0, length = this.lineChanges.length; i <= length; i++) {
			let lineChange = (i < length ? this.lineChanges[i] : null);
E
Erich Gamma 已提交
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458

			if (lineChange !== null) {
				originalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);
				modifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);
				lineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? (lineChange.originalEndLineNumber - lineChange.originalStartLineNumber + 1) : 0);
				lineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? (lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1) : 0);
				originalEndEquivalentLineNumber = Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber);
				modifiedEndEquivalentLineNumber = Math.max(lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber);
			} else {
				// Increase to very large value to get the producing tests of foreign view zones running
				originalEquivalentLineNumber += 10000000 + lineChangeOriginalLength;
				modifiedEquivalentLineNumber += 10000000 + lineChangeModifiedLength;
				originalEndEquivalentLineNumber = originalEquivalentLineNumber;
				modifiedEndEquivalentLineNumber = modifiedEquivalentLineNumber;
			}

			// Each step produces view zones, and after producing them, we try to cancel them out, to avoid empty-empty view zone cases
A
Alex Dima 已提交
1459 1460
			let stepOriginal: IMyViewZone[] = [];
			let stepModified: IMyViewZone[] = [];
E
Erich Gamma 已提交
1461 1462 1463 1464 1465

			// ---------------------------- PRODUCE VIEW ZONES

			// [PRODUCE] View zone(s) in original-side due to foreign view zone(s) in modified-side
			while (modifiedForeignVZ.current && modifiedForeignVZ.current.afterLineNumber <= modifiedEndEquivalentLineNumber) {
A
Alex Dima 已提交
1466
				let viewZoneLineNumber: number;
E
Erich Gamma 已提交
1467 1468 1469 1470 1471
				if (modifiedForeignVZ.current.afterLineNumber <= modifiedEquivalentLineNumber) {
					viewZoneLineNumber = originalEquivalentLineNumber - modifiedEquivalentLineNumber + modifiedForeignVZ.current.afterLineNumber;
				} else {
					viewZoneLineNumber = originalEndEquivalentLineNumber;
				}
A
Alex Dima 已提交
1472

1473
				let marginDomNode: HTMLDivElement | null = null;
A
Alex Dima 已提交
1474 1475 1476 1477
				if (lineChange && lineChange.modifiedStartLineNumber <= modifiedForeignVZ.current.afterLineNumber && modifiedForeignVZ.current.afterLineNumber <= lineChange.modifiedEndLineNumber) {
					marginDomNode = this._createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion();
				}

E
Erich Gamma 已提交
1478 1479
				stepOriginal.push({
					afterLineNumber: viewZoneLineNumber,
1480
					heightInLines: modifiedForeignVZ.current.height / this.modifiedLineHeight,
A
Alex Dima 已提交
1481 1482
					domNode: null,
					marginDomNode: marginDomNode
E
Erich Gamma 已提交
1483 1484 1485 1486 1487 1488
				});
				modifiedForeignVZ.advance();
			}

			// [PRODUCE] View zone(s) in modified-side due to foreign view zone(s) in original-side
			while (originalForeignVZ.current && originalForeignVZ.current.afterLineNumber <= originalEndEquivalentLineNumber) {
A
Alex Dima 已提交
1489
				let viewZoneLineNumber: number;
E
Erich Gamma 已提交
1490 1491 1492 1493 1494 1495 1496
				if (originalForeignVZ.current.afterLineNumber <= originalEquivalentLineNumber) {
					viewZoneLineNumber = modifiedEquivalentLineNumber - originalEquivalentLineNumber + originalForeignVZ.current.afterLineNumber;
				} else {
					viewZoneLineNumber = modifiedEndEquivalentLineNumber;
				}
				stepModified.push({
					afterLineNumber: viewZoneLineNumber,
1497
					heightInLines: originalForeignVZ.current.height / this.originalLineHeight,
E
Erich Gamma 已提交
1498 1499 1500 1501 1502 1503
					domNode: null
				});
				originalForeignVZ.advance();
			}

			if (lineChange !== null && isChangeOrInsert(lineChange)) {
A
Alex Dima 已提交
1504
				let r = this._produceOriginalFromDiff(lineChange, lineChangeOriginalLength, lineChangeModifiedLength);
E
Erich Gamma 已提交
1505 1506 1507 1508 1509 1510
				if (r) {
					stepOriginal.push(r);
				}
			}

			if (lineChange !== null && isChangeOrDelete(lineChange)) {
A
Alex Dima 已提交
1511
				let r = this._produceModifiedFromDiff(lineChange, lineChangeOriginalLength, lineChangeModifiedLength);
E
Erich Gamma 已提交
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
				if (r) {
					stepModified.push(r);
				}
			}

			// ---------------------------- END PRODUCE VIEW ZONES


			// ---------------------------- EMIT MINIMAL VIEW ZONES

			// [CANCEL & EMIT] Try to cancel view zones out
A
Alex Dima 已提交
1523 1524
			let stepOriginalIndex = 0;
			let stepModifiedIndex = 0;
E
Erich Gamma 已提交
1525 1526 1527 1528 1529

			stepOriginal = stepOriginal.sort(sortMyViewZones);
			stepModified = stepModified.sort(sortMyViewZones);

			while (stepOriginalIndex < stepOriginal.length && stepModifiedIndex < stepModified.length) {
A
Alex Dima 已提交
1530 1531
				let original = stepOriginal[stepOriginalIndex];
				let modified = stepModified[stepModifiedIndex];
E
Erich Gamma 已提交
1532

A
Alex Dima 已提交
1533 1534
				let originalDelta = original.afterLineNumber - originalEquivalentLineNumber;
				let modifiedDelta = modified.afterLineNumber - modifiedEquivalentLineNumber;
E
Erich Gamma 已提交
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575

				if (originalDelta < modifiedDelta) {
					addAndCombineIfPossible(result.original, original);
					stepOriginalIndex++;
				} else if (modifiedDelta < originalDelta) {
					addAndCombineIfPossible(result.modified, modified);
					stepModifiedIndex++;
				} else if (original.shouldNotShrink) {
					addAndCombineIfPossible(result.original, original);
					stepOriginalIndex++;
				} else if (modified.shouldNotShrink) {
					addAndCombineIfPossible(result.modified, modified);
					stepModifiedIndex++;
				} else {
					if (original.heightInLines >= modified.heightInLines) {
						// modified view zone gets removed
						original.heightInLines -= modified.heightInLines;
						stepModifiedIndex++;
					} else {
						// original view zone gets removed
						modified.heightInLines -= original.heightInLines;
						stepOriginalIndex++;
					}
				}
			}

			// [EMIT] Remaining original view zones
			while (stepOriginalIndex < stepOriginal.length) {
				addAndCombineIfPossible(result.original, stepOriginal[stepOriginalIndex]);
				stepOriginalIndex++;
			}

			// [EMIT] Remaining modified view zones
			while (stepModifiedIndex < stepModified.length) {
				addAndCombineIfPossible(result.modified, stepModified[stepModifiedIndex]);
				stepModifiedIndex++;
			}

			// ---------------------------- END EMIT MINIMAL VIEW ZONES
		}

A
Alex Dima 已提交
1576 1577 1578 1579 1580 1581
		return {
			original: ViewZonesComputer._ensureDomNodes(result.original),
			modified: ViewZonesComputer._ensureDomNodes(result.modified),
		};
	}

1582
	private static _ensureDomNodes(zones: IMyViewZone[]): IMyViewZone[] {
A
Alex Dima 已提交
1583
		return zones.map((z) => {
E
Erich Gamma 已提交
1584 1585 1586
			if (!z.domNode) {
				z.domNode = createFakeLinesDiv();
			}
1587
			return z;
A
Alex Dima 已提交
1588
		});
E
Erich Gamma 已提交
1589 1590
	}

A
Alex Dima 已提交
1591
	protected abstract _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null;
A
Alex Dima 已提交
1592

A
Alex Dima 已提交
1593
	protected abstract _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null;
E
Erich Gamma 已提交
1594

A
Alex Dima 已提交
1595
	protected abstract _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null;
E
Erich Gamma 已提交
1596 1597
}

1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
function createDecoration(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, options: ModelDecorationOptions) {
	return {
		range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
		options: options
	};
}

const DECORATIONS = {

	charDelete: ModelDecorationOptions.register({
		className: 'char-delete'
	}),
	charDeleteWholeLine: ModelDecorationOptions.register({
		className: 'char-delete',
		isWholeLine: true
	}),

	charInsert: ModelDecorationOptions.register({
		className: 'char-insert'
	}),
	charInsertWholeLine: ModelDecorationOptions.register({
		className: 'char-insert',
		isWholeLine: true
	}),

	lineInsert: ModelDecorationOptions.register({
		className: 'line-insert',
		marginClassName: 'line-insert',
		isWholeLine: true
	}),
	lineInsertWithSign: ModelDecorationOptions.register({
		className: 'line-insert',
A
Alexandru Dima 已提交
1630
		linesDecorationsClassName: 'insert-sign codicon codicon-add',
1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641
		marginClassName: 'line-insert',
		isWholeLine: true
	}),

	lineDelete: ModelDecorationOptions.register({
		className: 'line-delete',
		marginClassName: 'line-delete',
		isWholeLine: true
	}),
	lineDeleteWithSign: ModelDecorationOptions.register({
		className: 'line-delete',
A
Alexandru Dima 已提交
1642
		linesDecorationsClassName: 'delete-sign codicon codicon-remove',
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
		marginClassName: 'line-delete',
		isWholeLine: true

	}),
	lineDeleteMargin: ModelDecorationOptions.register({
		marginClassName: 'line-delete',
	})

};

H
Howard Hung 已提交
1653
class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider {
E
Erich Gamma 已提交
1654

1655
	static readonly MINIMUM_EDITOR_WIDTH = 100;
E
Erich Gamma 已提交
1656 1657

	private _disableSash: boolean;
1658
	private readonly _sash: Sash;
A
Alex Dima 已提交
1659 1660
	private _sashRatio: number | null;
	private _sashPosition: number | null;
A
Alex Dima 已提交
1661
	private _startSashPosition: number | null;
E
Erich Gamma 已提交
1662

J
Johannes Rieken 已提交
1663
	constructor(dataSource: IDataSource, enableSplitViewResizing: boolean) {
E
Erich Gamma 已提交
1664 1665 1666 1667 1668
		super(dataSource);

		this._disableSash = (enableSplitViewResizing === false);
		this._sashRatio = null;
		this._sashPosition = null;
A
Alex Dima 已提交
1669
		this._startSashPosition = null;
A
Alex Dima 已提交
1670
		this._sash = this._register(new Sash(this._dataSource.getContainerDomNode(), this));
E
Erich Gamma 已提交
1671 1672

		if (this._disableSash) {
J
Joao Moreno 已提交
1673
			this._sash.state = SashState.Disabled;
E
Erich Gamma 已提交
1674 1675
		}

I
isidor 已提交
1676 1677 1678 1679
		this._sash.onDidStart(() => this.onSashDragStart());
		this._sash.onDidChange((e: ISashEvent) => this.onSashDrag(e));
		this._sash.onDidEnd(() => this.onSashDragEnd());
		this._sash.onDidReset(() => this.onSashReset());
E
Erich Gamma 已提交
1680 1681
	}

J
Johannes Rieken 已提交
1682
	public setEnableSplitViewResizing(enableSplitViewResizing: boolean): void {
A
Alex Dima 已提交
1683
		let newDisableSash = (enableSplitViewResizing === false);
E
Erich Gamma 已提交
1684 1685
		if (this._disableSash !== newDisableSash) {
			this._disableSash = newDisableSash;
J
Joao Moreno 已提交
1686
			this._sash.state = this._disableSash ? SashState.Disabled : SashState.Enabled;
E
Erich Gamma 已提交
1687 1688 1689
		}
	}

A
Alex Dima 已提交
1690
	public layout(sashRatio: number | null = this._sashRatio): number {
A
Alex Dima 已提交
1691 1692
		let w = this._dataSource.getWidth();
		let contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
E
Erich Gamma 已提交
1693

A
Alex Dima 已提交
1694 1695
		let sashPosition = Math.floor((sashRatio || 0.5) * contentWidth);
		let midPoint = Math.floor(0.5 * contentWidth);
E
Erich Gamma 已提交
1696

A
Alex Dima 已提交
1697
		sashPosition = this._disableSash ? midPoint : sashPosition || midPoint;
E
Erich Gamma 已提交
1698

H
Howard Hung 已提交
1699 1700 1701
		if (contentWidth > DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH * 2) {
			if (sashPosition < DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
				sashPosition = DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
E
Erich Gamma 已提交
1702 1703
			}

H
Howard Hung 已提交
1704 1705
			if (sashPosition > contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
				sashPosition = contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
E
Erich Gamma 已提交
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
			}
		} else {
			sashPosition = midPoint;
		}

		if (this._sashPosition !== sashPosition) {
			this._sashPosition = sashPosition;
			this._sash.layout();
		}

		return this._sashPosition;
	}

M
Maxime Quandalle 已提交
1719
	private onSashDragStart(): void {
A
Alex Dima 已提交
1720
		this._startSashPosition = this._sashPosition!;
E
Erich Gamma 已提交
1721 1722
	}

J
Johannes Rieken 已提交
1723
	private onSashDrag(e: ISashEvent): void {
A
Alex Dima 已提交
1724 1725
		let w = this._dataSource.getWidth();
		let contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
A
Alex Dima 已提交
1726
		let sashPosition = this.layout((this._startSashPosition! + (e.currentX - e.startX)) / contentWidth);
E
Erich Gamma 已提交
1727 1728 1729 1730 1731 1732

		this._sashRatio = sashPosition / contentWidth;

		this._dataSource.relayoutEditors();
	}

M
Maxime Quandalle 已提交
1733 1734 1735 1736 1737 1738 1739
	private onSashDragEnd(): void {
		this._sash.layout();
	}

	private onSashReset(): void {
		this._sashRatio = 0.5;
		this._dataSource.relayoutEditors();
E
Erich Gamma 已提交
1740 1741 1742
		this._sash.layout();
	}

A
Alex Dima 已提交
1743
	public getVerticalSashTop(sash: Sash): number {
E
Erich Gamma 已提交
1744 1745 1746
		return 0;
	}

A
Alex Dima 已提交
1747
	public getVerticalSashLeft(sash: Sash): number {
A
Alex Dima 已提交
1748
		return this._sashPosition!;
E
Erich Gamma 已提交
1749 1750
	}

A
Alex Dima 已提交
1751
	public getVerticalSashHeight(sash: Sash): number {
E
Erich Gamma 已提交
1752 1753 1754
		return this._dataSource.getHeight();
	}

1755
	protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones {
1756
		let c = new SideBySideViewZonesComputer(lineChanges, originalForeignVZ, originalEditor.getOption(EditorOption.lineHeight), modifiedForeignVZ, modifiedEditor.getOption(EditorOption.lineHeight));
E
Erich Gamma 已提交
1757 1758 1759
		return c.getViewZones();
	}

1760
	protected _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
A
Alex Dima 已提交
1761
		const overviewZoneColor = String(this._removeColor);
E
Erich Gamma 已提交
1762

A
Alex Dima 已提交
1763
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1764 1765
			decorations: [],
			overviewZones: []
P
Peng Lyu 已提交
1766
		};
A
Alex Dima 已提交
1767

A
Alex Dima 已提交
1768
		let originalModel = originalEditor.getModel()!;
A
Alex Dima 已提交
1769 1770 1771

		for (let i = 0, length = lineChanges.length; i < length; i++) {
			let lineChange = lineChanges[i];
E
Erich Gamma 已提交
1772 1773

			if (isChangeOrDelete(lineChange)) {
1774
				result.decorations.push({
1775
					range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1776
					options: (renderIndicators ? DECORATIONS.lineDeleteWithSign : DECORATIONS.lineDelete)
1777
				});
E
Erich Gamma 已提交
1778
				if (!isChangeOrInsert(lineChange) || !lineChange.charChanges) {
1779
					result.decorations.push(createDecoration(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charDeleteWholeLine));
E
Erich Gamma 已提交
1780 1781
				}

A
Alex Dima 已提交
1782
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1783 1784
					lineChange.originalStartLineNumber,
					lineChange.originalEndLineNumber,
A
Alex Dima 已提交
1785
					overviewZoneColor
A
Alex Dima 已提交
1786
				));
E
Erich Gamma 已提交
1787 1788

				if (lineChange.charChanges) {
A
Alex Dima 已提交
1789 1790
					for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
						let charChange = lineChange.charChanges[j];
E
Erich Gamma 已提交
1791 1792
						if (isChangeOrDelete(charChange)) {
							if (ignoreTrimWhitespace) {
A
Alex Dima 已提交
1793 1794 1795
								for (let lineNumber = charChange.originalStartLineNumber; lineNumber <= charChange.originalEndLineNumber; lineNumber++) {
									let startColumn: number;
									let endColumn: number;
E
Erich Gamma 已提交
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805
									if (lineNumber === charChange.originalStartLineNumber) {
										startColumn = charChange.originalStartColumn;
									} else {
										startColumn = originalModel.getLineFirstNonWhitespaceColumn(lineNumber);
									}
									if (lineNumber === charChange.originalEndLineNumber) {
										endColumn = charChange.originalEndColumn;
									} else {
										endColumn = originalModel.getLineLastNonWhitespaceColumn(lineNumber);
									}
1806
									result.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charDelete));
E
Erich Gamma 已提交
1807 1808
								}
							} else {
1809
								result.decorations.push(createDecoration(charChange.originalStartLineNumber, charChange.originalStartColumn, charChange.originalEndLineNumber, charChange.originalEndColumn, DECORATIONS.charDelete));
E
Erich Gamma 已提交
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819
							}
						}
					}
				}
			}
		}

		return result;
	}

1820
	protected _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
A
Alex Dima 已提交
1821
		const overviewZoneColor = String(this._insertColor);
E
Erich Gamma 已提交
1822

A
Alex Dima 已提交
1823
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1824 1825
			decorations: [],
			overviewZones: []
A
Alex Dima 已提交
1826 1827
		};

A
Alex Dima 已提交
1828
		let modifiedModel = modifiedEditor.getModel()!;
A
Alex Dima 已提交
1829 1830 1831

		for (let i = 0, length = lineChanges.length; i < length; i++) {
			let lineChange = lineChanges[i];
E
Erich Gamma 已提交
1832 1833 1834

			if (isChangeOrInsert(lineChange)) {

1835
				result.decorations.push({
1836
					range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1837
					options: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert)
1838
				});
E
Erich Gamma 已提交
1839
				if (!isChangeOrDelete(lineChange) || !lineChange.charChanges) {
1840
					result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charInsertWholeLine));
E
Erich Gamma 已提交
1841
				}
A
Alex Dima 已提交
1842
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1843 1844
					lineChange.modifiedStartLineNumber,
					lineChange.modifiedEndLineNumber,
A
Alex Dima 已提交
1845
					overviewZoneColor
A
Alex Dima 已提交
1846
				));
E
Erich Gamma 已提交
1847 1848

				if (lineChange.charChanges) {
A
Alex Dima 已提交
1849 1850
					for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
						let charChange = lineChange.charChanges[j];
E
Erich Gamma 已提交
1851 1852
						if (isChangeOrInsert(charChange)) {
							if (ignoreTrimWhitespace) {
A
Alex Dima 已提交
1853 1854 1855
								for (let lineNumber = charChange.modifiedStartLineNumber; lineNumber <= charChange.modifiedEndLineNumber; lineNumber++) {
									let startColumn: number;
									let endColumn: number;
E
Erich Gamma 已提交
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
									if (lineNumber === charChange.modifiedStartLineNumber) {
										startColumn = charChange.modifiedStartColumn;
									} else {
										startColumn = modifiedModel.getLineFirstNonWhitespaceColumn(lineNumber);
									}
									if (lineNumber === charChange.modifiedEndLineNumber) {
										endColumn = charChange.modifiedEndColumn;
									} else {
										endColumn = modifiedModel.getLineLastNonWhitespaceColumn(lineNumber);
									}
1866
									result.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charInsert));
E
Erich Gamma 已提交
1867 1868
								}
							} else {
1869
								result.decorations.push(createDecoration(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn, DECORATIONS.charInsert));
E
Erich Gamma 已提交
1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
							}
						}
					}
				}

			}
		}
		return result;
	}
}

class SideBySideViewZonesComputer extends ViewZonesComputer {

1883 1884
	constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], originalLineHeight: number, modifiedForeignVZ: IEditorWhitespace[], modifiedLineHeight: number) {
		super(lineChanges, originalForeignVZ, originalLineHeight, modifiedForeignVZ, modifiedLineHeight);
E
Erich Gamma 已提交
1885 1886
	}

A
Alex Dima 已提交
1887
	protected _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null {
A
Alex Dima 已提交
1888 1889 1890
		return null;
	}

A
Alex Dima 已提交
1891
	protected _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {
E
Erich Gamma 已提交
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901
		if (lineChangeModifiedLength > lineChangeOriginalLength) {
			return {
				afterLineNumber: Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber),
				heightInLines: (lineChangeModifiedLength - lineChangeOriginalLength),
				domNode: null
			};
		}
		return null;
	}

A
Alex Dima 已提交
1902
	protected _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {
E
Erich Gamma 已提交
1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913
		if (lineChangeOriginalLength > lineChangeModifiedLength) {
			return {
				afterLineNumber: Math.max(lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber),
				heightInLines: (lineChangeOriginalLength - lineChangeModifiedLength),
				domNode: null
			};
		}
		return null;
	}
}

H
Howard Hung 已提交
1914
class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle {
E
Erich Gamma 已提交
1915 1916 1917

	private decorationsLeft: number;

J
Johannes Rieken 已提交
1918
	constructor(dataSource: IDataSource, enableSplitViewResizing: boolean) {
E
Erich Gamma 已提交
1919 1920
		super(dataSource);

1921
		this.decorationsLeft = dataSource.getOriginalEditor().getLayoutInfo().decorationsLeft;
E
Erich Gamma 已提交
1922

1923
		this._register(dataSource.getOriginalEditor().onDidLayoutChange((layoutInfo: EditorLayoutInfo) => {
E
Erich Gamma 已提交
1924 1925 1926 1927 1928 1929 1930
			if (this.decorationsLeft !== layoutInfo.decorationsLeft) {
				this.decorationsLeft = layoutInfo.decorationsLeft;
				dataSource.relayoutEditors();
			}
		}));
	}

J
Johannes Rieken 已提交
1931
	public setEnableSplitViewResizing(enableSplitViewResizing: boolean): void {
E
Erich Gamma 已提交
1932 1933 1934
		// Nothing to do..
	}

1935
	protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones {
1936
		let computer = new InlineViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor, renderIndicators);
E
Erich Gamma 已提交
1937 1938 1939
		return computer.getViewZones();
	}

1940
	protected _getOriginalEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
A
Alex Dima 已提交
1941
		const overviewZoneColor = String(this._removeColor);
A
Alex Dima 已提交
1942

A
Alex Dima 已提交
1943
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1944 1945
			decorations: [],
			overviewZones: []
A
Alex Dima 已提交
1946
		};
E
Erich Gamma 已提交
1947

A
Alex Dima 已提交
1948 1949
		for (let i = 0, length = lineChanges.length; i < length; i++) {
			let lineChange = lineChanges[i];
E
Erich Gamma 已提交
1950 1951 1952

			// Add overview zones in the overview ruler
			if (isChangeOrDelete(lineChange)) {
1953
				result.decorations.push({
1954
					range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1955
					options: DECORATIONS.lineDeleteMargin
1956 1957
				});

A
Alex Dima 已提交
1958
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1959 1960
					lineChange.originalStartLineNumber,
					lineChange.originalEndLineNumber,
A
Alex Dima 已提交
1961
					overviewZoneColor
A
Alex Dima 已提交
1962
				));
E
Erich Gamma 已提交
1963 1964 1965 1966 1967 1968
			}
		}

		return result;
	}

1969
	protected _getModifiedEditorDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorDiffDecorations {
A
Alex Dima 已提交
1970
		const overviewZoneColor = String(this._insertColor);
E
Erich Gamma 已提交
1971

A
Alex Dima 已提交
1972
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1973 1974
			decorations: [],
			overviewZones: []
A
Alex Dima 已提交
1975 1976
		};

A
Alex Dima 已提交
1977
		let modifiedModel = modifiedEditor.getModel()!;
A
Alex Dima 已提交
1978 1979 1980

		for (let i = 0, length = lineChanges.length; i < length; i++) {
			let lineChange = lineChanges[i];
E
Erich Gamma 已提交
1981 1982 1983

			// Add decorations & overview zones
			if (isChangeOrInsert(lineChange)) {
1984
				result.decorations.push({
1985
					range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1986
					options: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert)
1987
				});
E
Erich Gamma 已提交
1988

A
Alex Dima 已提交
1989
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1990 1991
					lineChange.modifiedStartLineNumber,
					lineChange.modifiedEndLineNumber,
A
Alex Dima 已提交
1992
					overviewZoneColor
A
Alex Dima 已提交
1993
				));
E
Erich Gamma 已提交
1994 1995

				if (lineChange.charChanges) {
A
Alex Dima 已提交
1996 1997
					for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
						let charChange = lineChange.charChanges[j];
E
Erich Gamma 已提交
1998 1999
						if (isChangeOrInsert(charChange)) {
							if (ignoreTrimWhitespace) {
A
Alex Dima 已提交
2000 2001 2002
								for (let lineNumber = charChange.modifiedStartLineNumber; lineNumber <= charChange.modifiedEndLineNumber; lineNumber++) {
									let startColumn: number;
									let endColumn: number;
E
Erich Gamma 已提交
2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
									if (lineNumber === charChange.modifiedStartLineNumber) {
										startColumn = charChange.modifiedStartColumn;
									} else {
										startColumn = modifiedModel.getLineFirstNonWhitespaceColumn(lineNumber);
									}
									if (lineNumber === charChange.modifiedEndLineNumber) {
										endColumn = charChange.modifiedEndColumn;
									} else {
										endColumn = modifiedModel.getLineLastNonWhitespaceColumn(lineNumber);
									}
2013
									result.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charInsert));
E
Erich Gamma 已提交
2014 2015
								}
							} else {
2016
								result.decorations.push(createDecoration(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn, DECORATIONS.charInsert));
E
Erich Gamma 已提交
2017 2018 2019 2020
							}
						}
					}
				} else {
2021
					result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charInsertWholeLine));
E
Erich Gamma 已提交
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
				}
			}
		}

		return result;
	}

	public layout(): number {
		// An editor should not be smaller than 5px
		return Math.max(5, this.decorationsLeft);
	}

}

class InlineViewZonesComputer extends ViewZonesComputer {

2038
	private readonly originalModel: ITextModel;
2039
	private readonly modifiedEditorOptions: IComputedEditorOptions;
2040 2041
	private readonly modifiedEditorTabSize: number;
	private readonly renderIndicators: boolean;
E
Erich Gamma 已提交
2042

A
Alex Dima 已提交
2043
	constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) {
2044
		super(lineChanges, originalForeignVZ, originalEditor.getOption(EditorOption.lineHeight), modifiedForeignVZ, modifiedEditor.getOption(EditorOption.lineHeight));
A
Alex Dima 已提交
2045
		this.originalModel = originalEditor.getModel()!;
A
Alex Dima 已提交
2046
		this.modifiedEditorOptions = modifiedEditor.getOptions();
A
Alex Dima 已提交
2047
		this.modifiedEditorTabSize = modifiedEditor.getModel()!.getOptions().tabSize;
R
rebornix 已提交
2048
		this.renderIndicators = renderIndicators;
E
Erich Gamma 已提交
2049 2050
	}

A
Alex Dima 已提交
2051
	protected _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null {
A
Alex Dima 已提交
2052 2053 2054 2055 2056
		let result = document.createElement('div');
		result.className = 'inline-added-margin-view-zone';
		return result;
	}

A
Alex Dima 已提交
2057
	protected _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {
2058 2059 2060
		let marginDomNode = document.createElement('div');
		marginDomNode.className = 'inline-added-margin-view-zone';

E
Erich Gamma 已提交
2061
		return {
J
Johannes Rieken 已提交
2062
			afterLineNumber: Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber),
E
Erich Gamma 已提交
2063
			heightInLines: lineChangeModifiedLength,
2064 2065
			domNode: document.createElement('div'),
			marginDomNode: marginDomNode
E
Erich Gamma 已提交
2066 2067 2068
		};
	}

A
Alex Dima 已提交
2069
	protected _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {
A
Alex Dima 已提交
2070
		let decorations: InlineDecoration[] = [];
E
Erich Gamma 已提交
2071
		if (lineChange.charChanges) {
A
Alex Dima 已提交
2072 2073
			for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
				let charChange = lineChange.charChanges[j];
E
Erich Gamma 已提交
2074
				if (isChangeOrDelete(charChange)) {
2075 2076
					decorations.push(new InlineDecoration(
						new Range(charChange.originalStartLineNumber, charChange.originalStartColumn, charChange.originalEndLineNumber, charChange.originalEndColumn),
2077
						'char-delete',
2078
						InlineDecorationType.Regular
2079
					));
E
Erich Gamma 已提交
2080 2081 2082 2083
				}
			}
		}

2084
		let sb = createStringBuilder(10000);
2085
		let marginHTML: string[] = [];
A
renames  
Alex Dima 已提交
2086
		const layoutInfo = this.modifiedEditorOptions.get(EditorOption.layoutInfo);
2087
		const fontInfo = this.modifiedEditorOptions.get(EditorOption.fontInfo);
A
Alex Dima 已提交
2088 2089
		const lineDecorationsWidth = layoutInfo.decorationsWidth;

A
Alex Dima 已提交
2090
		let lineHeight = this.modifiedEditorOptions.get(EditorOption.lineHeight);
2091
		const typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
2092
		let maxCharsPerLine = 0;
2093
		const originalContent: string[] = [];
A
Alex Dima 已提交
2094
		for (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) {
2095
			maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorOptions, this.modifiedEditorTabSize, lineNumber, decorations, sb));
2096
			originalContent.push(this.originalModel.getLineContent(lineNumber));
2097

R
rebornix 已提交
2098
			if (this.renderIndicators) {
2099 2100
				let index = lineNumber - lineChange.originalStartLineNumber;
				marginHTML = marginHTML.concat([
2101
					`<div class="delete-sign codicon codicon-remove" style="position:absolute;top:${index * lineHeight}px;width:${lineDecorationsWidth}px;height:${lineHeight}px;right:0;"></div>`
2102 2103
				]);
			}
E
Erich Gamma 已提交
2104
		}
A
Alex Dima 已提交
2105
		maxCharsPerLine += this.modifiedEditorOptions.get(EditorOption.scrollBeyondLastColumn);
E
Erich Gamma 已提交
2106

A
Alex Dima 已提交
2107
		let domNode = document.createElement('div');
E
Erich Gamma 已提交
2108
		domNode.className = 'view-lines line-delete';
2109
		domNode.innerHTML = sb.build();
2110
		Configuration.applyFontInfoSlow(domNode, fontInfo);
E
Erich Gamma 已提交
2111

2112 2113 2114
		let marginDomNode = document.createElement('div');
		marginDomNode.className = 'inline-deleted-margin-view-zone';
		marginDomNode.innerHTML = marginHTML.join('');
2115
		Configuration.applyFontInfoSlow(marginDomNode, fontInfo);
2116

E
Erich Gamma 已提交
2117 2118 2119 2120
		return {
			shouldNotShrink: true,
			afterLineNumber: (lineChange.modifiedEndLineNumber === 0 ? lineChange.modifiedStartLineNumber : lineChange.modifiedStartLineNumber - 1),
			heightInLines: lineChangeOriginalLength,
2121
			minWidthInPx: (maxCharsPerLine * typicalHalfwidthCharacterWidth),
2122
			domNode: domNode,
2123 2124 2125 2126 2127 2128 2129 2130
			marginDomNode: marginDomNode,
			diff: {
				originalStartLineNumber: lineChange.originalStartLineNumber,
				originalEndLineNumber: lineChange.originalEndLineNumber,
				modifiedStartLineNumber: lineChange.modifiedStartLineNumber,
				modifiedEndLineNumber: lineChange.modifiedEndLineNumber,
				originalContent: originalContent
			}
E
Erich Gamma 已提交
2131 2132 2133
		};
	}

2134
	private _renderOriginalLine(count: number, originalModel: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): number {
2135 2136
		const lineTokens = originalModel.getLineTokens(lineNumber);
		const lineContent = lineTokens.getLineContent();
2137
		const fontInfo = options.get(EditorOption.fontInfo);
A
Alex Dima 已提交
2138

2139
		const actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, lineContent.length + 1);
A
Alex Dima 已提交
2140

2141 2142 2143 2144 2145 2146
		sb.appendASCIIString('<div class="view-line');
		if (decorations.length === 0) {
			// No char changes
			sb.appendASCIIString(' char-delete');
		}
		sb.appendASCIIString('" style="top:');
A
Alex Dima 已提交
2147
		sb.appendASCIIString(String(count * options.get(EditorOption.lineHeight)));
2148 2149
		sb.appendASCIIString('px;width:1000000px;">');

2150 2151
		const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII());
		const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL());
2152
		const output = renderViewLine(new RenderLineInput(
2153
			(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)),
2154
			fontInfo.canUseHalfwidthRightwardsArrow,
A
Alex Dima 已提交
2155
			lineContent,
A
Alex Dima 已提交
2156
			false,
2157 2158
			isBasicASCII,
			containsRTL,
2159
			0,
A
Alex Dima 已提交
2160
			lineTokens,
2161
			actualDecorations,
A
Alex Dima 已提交
2162
			tabSize,
2163
			0,
2164
			fontInfo.spaceWidth,
2165
			fontInfo.middotWidth,
A
Alex Dima 已提交
2166 2167 2168
			options.get(EditorOption.stopRenderingLineAfter),
			options.get(EditorOption.renderWhitespace),
			options.get(EditorOption.renderControlCharacters),
2169
			options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF,
2170
			null // Send no selections, original line cannot be selected
2171
		), sb);
E
Erich Gamma 已提交
2172

2173
		sb.appendASCIIString('</div>');
2174 2175 2176

		const absoluteOffsets = output.characterMapping.getAbsoluteOffsets();
		return absoluteOffsets.length > 0 ? absoluteOffsets[absoluteOffsets.length - 1] : 0;
E
Erich Gamma 已提交
2177 2178 2179
	}
}

J
Johannes Rieken 已提交
2180
function isChangeOrInsert(lineChange: editorCommon.IChange): boolean {
E
Erich Gamma 已提交
2181 2182 2183
	return lineChange.modifiedEndLineNumber > 0;
}

J
Johannes Rieken 已提交
2184
function isChangeOrDelete(lineChange: editorCommon.IChange): boolean {
E
Erich Gamma 已提交
2185 2186 2187 2188
	return lineChange.originalEndLineNumber > 0;
}

function createFakeLinesDiv(): HTMLElement {
A
Alex Dima 已提交
2189
	let r = document.createElement('div');
E
Erich Gamma 已提交
2190 2191 2192
	r.className = 'diagonal-fill';
	return r;
}
2193 2194

registerThemingParticipant((theme, collector) => {
2195
	const added = theme.getColor(diffInserted);
2196 2197
	if (added) {
		collector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { background-color: ${added}; }`);
A
Alex Dima 已提交
2198
		collector.addRule(`.monaco-diff-editor .line-insert, .monaco-diff-editor .char-insert { background-color: ${added}; }`);
2199 2200
		collector.addRule(`.monaco-editor .inline-added-margin-view-zone { background-color: ${added}; }`);
	}
2201 2202

	const removed = theme.getColor(diffRemoved);
2203 2204
	if (removed) {
		collector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { background-color: ${removed}; }`);
A
Alex Dima 已提交
2205
		collector.addRule(`.monaco-diff-editor .line-delete, .monaco-diff-editor .char-delete { background-color: ${removed}; }`);
2206 2207
		collector.addRule(`.monaco-editor .inline-deleted-margin-view-zone { background-color: ${removed}; }`);
	}
2208 2209

	const addedOutline = theme.getColor(diffInsertedOutline);
2210
	if (addedOutline) {
2211
		collector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${addedOutline}; }`);
2212
	}
2213 2214

	const removedOutline = theme.getColor(diffRemovedOutline);
2215
	if (removedOutline) {
2216
		collector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${removedOutline}; }`);
2217
	}
2218 2219

	const shadow = theme.getColor(scrollbarShadow);
2220 2221 2222
	if (shadow) {
		collector.addRule(`.monaco-diff-editor.side-by-side .editor.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`);
	}
2223

M
Matt Bierner 已提交
2224
	const border = theme.getColor(diffBorder);
2225 2226 2227
	if (border) {
		collector.addRule(`.monaco-diff-editor.side-by-side .editor.modified { border-left: 1px solid ${border}; }`);
	}
2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255

	const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground);
	if (scrollbarSliderBackgroundColor) {
		collector.addRule(`
			.monaco-diff-editor .diffViewport {
				background: ${scrollbarSliderBackgroundColor};
			}
		`);
	}

	const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground);
	if (scrollbarSliderHoverBackgroundColor) {
		collector.addRule(`
			.monaco-diff-editor .diffViewport:hover {
				background: ${scrollbarSliderHoverBackgroundColor};
			}
		`);
	}

	const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground);
	if (scrollbarSliderActiveBackgroundColor) {
		collector.addRule(`
			.monaco-diff-editor .diffViewport:active {
				background: ${scrollbarSliderActiveBackgroundColor};
			}
		`);
	}

2256
});