diffEditorWidget.ts 84.6 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';
11
import { RunOnceScheduler } 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';
M
Martin Aeschlimann 已提交
42
import { IColorTheme, 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';
50
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
M
Martin Aeschlimann 已提交
51
import { Codicon, registerIcon } from 'vs/base/browser/ui/codicons/codicons';
E
Erich Gamma 已提交
52 53

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

A
Alex Dima 已提交
159
let DIFF_EDITOR_ID = 0;
E
Erich Gamma 已提交
160

M
Martin Aeschlimann 已提交
161 162 163 164

const diffInsertIcon = registerIcon('diff-insert', Codicon.add);
const diffRemoveIcon = registerIcon('diff-remove', Codicon.remove);

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

167
	private static readonly ONE_OVERVIEW_WIDTH = 15;
M
Matt Bierner 已提交
168
	public static readonly ENTIRE_DIFF_OVERVIEW_WIDTH = 30;
169
	private static readonly UPDATE_DIFF_DECORATIONS_DELAY = 200; // ms
E
Erich Gamma 已提交
170

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

A
Alex Dima 已提交
174 175 176 177
	private readonly _onDidUpdateDiff: Emitter<void> = this._register(new Emitter<void>());
	public readonly onDidUpdateDiff: Event<void> = this._onDidUpdateDiff.event;

	private readonly id: number;
178
	private _state: editorBrowser.DiffEditorState;
179
	private _updatingDiffProgress: IProgressRunner | null;
E
Erich Gamma 已提交
180

181
	private readonly _domElement: HTMLElement;
A
Alex Dima 已提交
182 183 184
	protected readonly _containerDomElement: HTMLElement;
	private readonly _overviewDomElement: HTMLElement;
	private readonly _overviewViewportDomElement: FastDomNode<HTMLElement>;
E
Erich Gamma 已提交
185

186
	private readonly _elementSizeObserver: ElementSizeObserver;
E
Erich Gamma 已提交
187

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

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

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

J
Johannes Rieken 已提交
203 204
	private _isVisible: boolean;
	private _isHandlingScrollEvent: boolean;
E
Erich Gamma 已提交
205 206

	private _ignoreTrimWhitespace: boolean;
207
	private _originalIsEditable: boolean;
E
Erich Gamma 已提交
208

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

215
	private readonly _updateDecorationsRunner: RunOnceScheduler;
E
Erich Gamma 已提交
216

217
	private readonly _editorWorkerService: IEditorWorkerService;
218
	protected _contextKeyService: IContextKeyService;
219 220 221
	private readonly _codeEditorService: ICodeEditorService;
	private readonly _themeService: IThemeService;
	private readonly _notificationService: INotificationService;
222

223
	private readonly _reviewPane: DiffReview;
A
Alex Dima 已提交
224

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

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

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

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

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

260 261 262 263
		// maxComputationTime
		this._maxComputationTime = 5000;
		if (typeof options.maxComputationTime !== 'undefined') {
			this._maxComputationTime = options.maxComputationTime;
264 265
		}

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

272 273 274 275 276 277
		// renderIndicators
		this._renderIndicators = true;
		if (typeof options.renderIndicators !== 'undefined') {
			this._renderIndicators = options.renderIndicators;
		}

278 279 280 281 282
		this._originalIsEditable = false;
		if (typeof options.originalEditable !== 'undefined') {
			this._originalIsEditable = Boolean(options.originalEditable);
		}

A
Alex Dima 已提交
283
		this._updateDecorationsRunner = this._register(new RunOnceScheduler(() => this._updateDecorations(), 0));
E
Erich Gamma 已提交
284 285

		this._containerDomElement = document.createElement('div');
M
Martin Aeschlimann 已提交
286
		this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._renderSideBySide);
E
Erich Gamma 已提交
287 288 289 290
		this._containerDomElement.style.position = 'relative';
		this._containerDomElement.style.height = '100%';
		this._domElement.appendChild(this._containerDomElement);

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

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

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

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

A
Alex Dima 已提交
306 307 308 309 310 311 312 313 314 315 316 317 318
		// 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 已提交
319 320 321 322 323

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

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

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

330 331 332 333
		this._elementSizeObserver = this._register(new ElementSizeObserver(this._containerDomElement, undefined, () => this._onDidContainerSizeChanged()));
		if (options.automaticLayout) {
			this._elementSizeObserver.startObserving();
		}
E
Erich Gamma 已提交
334

A
Alex Dima 已提交
335
		this._diffComputationResult = null;
E
Erich Gamma 已提交
336

337 338
		const leftContextKeyService = this._contextKeyService.createScoped();
		leftContextKeyService.createKey('isInDiffLeftEditor', true);
J
Joao Moreno 已提交
339

340 341 342
		const leftServices = new ServiceCollection();
		leftServices.set(IContextKeyService, leftContextKeyService);
		const leftScopedInstantiationService = instantiationService.createChild(leftServices);
J
Joao Moreno 已提交
343

344 345 346 347 348 349 350
		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 已提交
351 352 353 354 355
		this.originalEditor = this._createLeftHandSideEditor(options, leftScopedInstantiationService);
		this.modifiedEditor = this._createRightHandSideEditor(options, rightScopedInstantiationService);

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

357 358 359
		this._reviewPane = new DiffReview(this);
		this._containerDomElement.appendChild(this._reviewPane.domNode.domNode);
		this._containerDomElement.appendChild(this._reviewPane.shadow.domNode);
360
		this._containerDomElement.appendChild(this._reviewPane.actionBarContainer.domNode);
361

362

E
Erich Gamma 已提交
363 364 365 366 367 368 369 370

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

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

M
Martin Aeschlimann 已提交
376
		this._register(themeService.onDidColorThemeChange(t => {
377 378 379
			if (this._strategy && this._strategy.applyColors(t)) {
				this._updateDecorationsRunner.schedule();
			}
M
Martin Aeschlimann 已提交
380
			this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._renderSideBySide);
381
		}));
382

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		this._layoutOverviewRulers();
	}

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

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

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

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

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

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

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

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

			this._layoutOverviewViewport();
		}));

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

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

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

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

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

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

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

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

E
Erich Gamma 已提交
560 561
		this._cleanViewZonesAndDecorations();

562 563 564 565 566 567 568 569
		if (this._originalOverviewRuler) {
			this._overviewDomElement.removeChild(this._originalOverviewRuler.getDomNode());
			this._originalOverviewRuler.dispose();
		}
		if (this._modifiedOverviewRuler) {
			this._overviewDomElement.removeChild(this._modifiedOverviewRuler.getDomNode());
			this._modifiedOverviewRuler.dispose();
		}
570 571
		this._overviewDomElement.removeChild(this._overviewViewportDomElement.domNode);
		this._containerDomElement.removeChild(this._overviewDomElement);
E
Erich Gamma 已提交
572

573
		this._containerDomElement.removeChild(this._originalDomNode);
A
Alex Dima 已提交
574
		this.originalEditor.dispose();
575 576

		this._containerDomElement.removeChild(this._modifiedDomNode);
A
Alex Dima 已提交
577
		this.modifiedEditor.dispose();
E
Erich Gamma 已提交
578 579 580

		this._strategy.dispose();

581 582 583
		this._containerDomElement.removeChild(this._reviewPane.domNode.domNode);
		this._containerDomElement.removeChild(this._reviewPane.shadow.domNode);
		this._containerDomElement.removeChild(this._reviewPane.actionBarContainer.domNode);
584 585
		this._reviewPane.dispose();

586 587
		this._domElement.removeChild(this._containerDomElement);

A
Alex Dima 已提交
588
		this._onDidDispose.fire();
A
Alex Dima 已提交
589

E
Erich Gamma 已提交
590 591 592 593 594 595 596 597 598 599
		super.dispose();
	}

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

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

	public getEditorType(): string {
A
Alex Dima 已提交
600
		return editorCommon.EditorType.IDiffEditor;
E
Erich Gamma 已提交
601 602
	}

A
Alex Dima 已提交
603
	public getLineChanges(): editorCommon.ILineChange[] | null {
A
Alex Dima 已提交
604 605 606 607
		if (!this._diffComputationResult) {
			return null;
		}
		return this._diffComputationResult.changes;
E
Erich Gamma 已提交
608 609
	}

610 611 612 613
	public getDiffComputationResult(): IDiffComputationResult | null {
		return this._diffComputationResult;
	}

A
Alex Dima 已提交
614
	public getOriginalEditor(): editorBrowser.ICodeEditor {
E
Erich Gamma 已提交
615 616 617
		return this.originalEditor;
	}

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

622
	public updateOptions(newOptions: IDiffEditorOptions): void {
E
Erich Gamma 已提交
623 624

		// Handle side by side
A
Alex Dima 已提交
625
		let renderSideBySideChanged = false;
E
Erich Gamma 已提交
626 627 628 629 630 631 632
		if (typeof newOptions.renderSideBySide !== 'undefined') {
			if (this._renderSideBySide !== newOptions.renderSideBySide) {
				this._renderSideBySide = newOptions.renderSideBySide;
				renderSideBySideChanged = true;
			}
		}

633 634
		if (typeof newOptions.maxComputationTime !== 'undefined') {
			this._maxComputationTime = newOptions.maxComputationTime;
635 636 637
			if (this._isVisible) {
				this._beginUpdateDecorationsSoon();
			}
638 639
		}

640 641
		let beginUpdateDecorations = false;

E
Erich Gamma 已提交
642 643 644 645
		if (typeof newOptions.ignoreTrimWhitespace !== 'undefined') {
			if (this._ignoreTrimWhitespace !== newOptions.ignoreTrimWhitespace) {
				this._ignoreTrimWhitespace = newOptions.ignoreTrimWhitespace;
				// Begin comparing
646 647 648 649 650 651 652 653
				beginUpdateDecorations = true;
			}
		}

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

657 658 659 660
		if (beginUpdateDecorations) {
			this._beginUpdateDecorations();
		}

661 662 663 664
		if (typeof newOptions.originalEditable !== 'undefined') {
			this._originalIsEditable = Boolean(newOptions.originalEditable);
		}

E
Erich Gamma 已提交
665
		this.modifiedEditor.updateOptions(this._adjustOptionsForRightHandSide(newOptions));
666
		this.originalEditor.updateOptions(this._adjustOptionsForLeftHandSide(newOptions, this._originalIsEditable));
E
Erich Gamma 已提交
667 668 669 670 671 672 673 674 675 676

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

		// renderSideBySide
		if (renderSideBySideChanged) {
			if (this._renderSideBySide) {
H
Howard Hung 已提交
677
				this._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing));
E
Erich Gamma 已提交
678
			} else {
H
Howard Hung 已提交
679
				this._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing));
E
Erich Gamma 已提交
680
			}
681
			// Update class name
M
Martin Aeschlimann 已提交
682
			this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getColorTheme(), this._renderSideBySide);
E
Erich Gamma 已提交
683 684 685
		}
	}

A
Alex Dima 已提交
686
	public getModel(): editorCommon.IDiffEditorModel {
E
Erich Gamma 已提交
687
		return {
A
Alex Dima 已提交
688 689
			original: this.originalEditor.getModel()!,
			modified: this.modifiedEditor.getModel()!
E
Erich Gamma 已提交
690 691 692
		};
	}

J
Johannes Rieken 已提交
693
	public setModel(model: editorCommon.IDiffEditorModel): void {
E
Erich Gamma 已提交
694 695 696 697 698 699 700 701 702 703 704 705 706
		// 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();

707 708
		// this.originalEditor.onDidChangeModelOptions

E
Erich Gamma 已提交
709 710 711 712 713 714
		if (model) {
			this.originalEditor.setScrollTop(0);
			this.modifiedEditor.setScrollTop(0);
		}

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

		if (model) {
			this._recreateOverviewRulers();

			// Begin comparing
			this._beginUpdateDecorations();
		}

		this._layoutOverviewViewport();
	}

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

A
Alex Dima 已提交
733
	public getVisibleColumnFromPosition(position: IPosition): number {
E
Erich Gamma 已提交
734 735 736
		return this.modifiedEditor.getVisibleColumnFromPosition(position);
	}

737 738 739 740
	public getStatusbarColumn(position: IPosition): number {
		return this.modifiedEditor.getStatusbarColumn(position);
	}

A
Alex Dima 已提交
741
	public getPosition(): Position | null {
E
Erich Gamma 已提交
742 743 744
		return this.modifiedEditor.getPosition();
	}

745 746
	public setPosition(position: IPosition): void {
		this.modifiedEditor.setPosition(position);
E
Erich Gamma 已提交
747 748
	}

749 750
	public revealLine(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLine(lineNumber, scrollType);
E
Erich Gamma 已提交
751 752
	}

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

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

761 762
	public revealLineNearTop(lineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLineNearTop(lineNumber, scrollType);
763 764
	}

765 766
	public revealPosition(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealPosition(position, scrollType);
E
Erich Gamma 已提交
767 768
	}

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

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

777 778
	public revealPositionNearTop(position: IPosition, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealPositionNearTop(position, scrollType);
779 780
	}

A
Alex Dima 已提交
781
	public getSelection(): Selection | null {
E
Erich Gamma 已提交
782 783 784
		return this.modifiedEditor.getSelection();
	}

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

789 790 791 792 793 794
	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 已提交
795 796
	}

797
	public setSelections(ranges: readonly ISelection[]): void {
E
Erich Gamma 已提交
798 799 800
		this.modifiedEditor.setSelections(ranges);
	}

801 802
	public revealLines(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLines(startLineNumber, endLineNumber, scrollType);
E
Erich Gamma 已提交
803 804
	}

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

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

813 814
	public revealLinesNearTop(startLineNumber: number, endLineNumber: number, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealLinesNearTop(startLineNumber, endLineNumber, scrollType);
815 816
	}

817 818
	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 已提交
819 820
	}

821 822
	public revealRangeInCenter(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealRangeInCenter(range, scrollType);
E
Erich Gamma 已提交
823 824
	}

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

829 830
	public revealRangeNearTop(range: IRange, scrollType: editorCommon.ScrollType = editorCommon.ScrollType.Smooth): void {
		this.modifiedEditor.revealRangeNearTop(range, scrollType);
831 832
	}

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

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

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

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

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

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

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

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

	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 已提交
890
	public trigger(source: string, handlerId: string, payload: any): void {
E
Erich Gamma 已提交
891 892 893
		this.modifiedEditor.trigger(source, handlerId, payload);
	}

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

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



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

904
	private _onDidContainerSizeChanged(): void {
E
Erich Gamma 已提交
905 906 907
		this._doLayout();
	}

908 909 910 911
	private _getReviewHeight(): number {
		return this._reviewPane.isVisible() ? this._elementSizeObserver.getHeight() : 0;
	}

E
Erich Gamma 已提交
912
	private _layoutOverviewRulers(): void {
A
Alex Dima 已提交
913 914 915
		if (!this._originalOverviewRuler || !this._modifiedOverviewRuler) {
			return;
		}
916 917 918
		const height = this._elementSizeObserver.getHeight();
		const reviewHeight = this._getReviewHeight();

A
Alex Dima 已提交
919 920
		let freeSpace = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH - 2 * DiffEditorWidget.ONE_OVERVIEW_WIDTH;
		let layoutInfo = this.modifiedEditor.getLayoutInfo();
E
Erich Gamma 已提交
921
		if (layoutInfo) {
A
Alex Dima 已提交
922
			this._originalOverviewRuler.setLayout({
E
Erich Gamma 已提交
923 924 925
				top: 0,
				width: DiffEditorWidget.ONE_OVERVIEW_WIDTH,
				right: freeSpace + DiffEditorWidget.ONE_OVERVIEW_WIDTH,
926
				height: (height - reviewHeight)
A
Alex Dima 已提交
927 928
			});
			this._modifiedOverviewRuler.setLayout({
E
Erich Gamma 已提交
929 930 931
				top: 0,
				right: 0,
				width: DiffEditorWidget.ONE_OVERVIEW_WIDTH,
932
				height: (height - reviewHeight)
A
Alex Dima 已提交
933
			});
E
Erich Gamma 已提交
934 935 936 937 938 939 940 941 942 943 944 945
		}
	}

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

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

A
Alex Dima 已提交
946 947 948 949 950 951 952 953 954
	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);
	}

955 956
	private _lastOriginalWarning: URI | null = null;
	private _lastModifiedWarning: URI | null = null;
957

A
Alex Dima 已提交
958
	private static _equals(a: URI | null, b: URI | null): boolean {
959 960 961 962 963 964 965 966 967
		if (!a && !b) {
			return true;
		}
		if (!a || !b) {
			return false;
		}
		return (a.toString() === b.toString());
	}

E
Erich Gamma 已提交
968 969
	private _beginUpdateDecorations(): void {
		this._beginUpdateDecorationsTimeout = -1;
970 971 972
		const currentOriginalModel = this.originalEditor.getModel();
		const currentModifiedModel = this.modifiedEditor.getModel();
		if (!currentOriginalModel || !currentModifiedModel) {
E
Erich Gamma 已提交
973 974 975 976 977 978 979
			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 已提交
980
		let currentToken = this._diffComputationToken;
981
		this._setState(editorBrowser.DiffEditorState.ComputingDiff);
E
Erich Gamma 已提交
982

983 984 985 986 987 988 989
		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;
990
				this._notificationService.warn(nls.localize("diff.tooLarge", "Cannot compare files because one file is too large."));
991 992 993 994
			}
			return;
		}

995
		this._editorWorkerService.computeDiff(currentOriginalModel.uri, currentModifiedModel.uri, this._ignoreTrimWhitespace, this._maxComputationTime).then((result) => {
996 997 998
			if (currentToken === this._diffComputationToken
				&& currentOriginalModel === this.originalEditor.getModel()
				&& currentModifiedModel === this.modifiedEditor.getModel()
J
Johannes Rieken 已提交
999
			) {
1000
				this._setState(editorBrowser.DiffEditorState.DiffComputed);
A
Alex Dima 已提交
1001
				this._diffComputationResult = result;
1002
				this._updateDecorationsRunner.schedule();
A
Alex Dima 已提交
1003
				this._onDidUpdateDiff.fire();
1004 1005 1006 1007 1008
			}
		}, (error) => {
			if (currentToken === this._diffComputationToken
				&& currentOriginalModel === this.originalEditor.getModel()
				&& currentModifiedModel === this.modifiedEditor.getModel()
J
Johannes Rieken 已提交
1009
			) {
1010
				this._setState(editorBrowser.DiffEditorState.DiffComputed);
A
Alex Dima 已提交
1011
				this._diffComputationResult = null;
E
Erich Gamma 已提交
1012 1013
				this._updateDecorationsRunner.schedule();
			}
1014
		});
E
Erich Gamma 已提交
1015 1016 1017 1018 1019 1020 1021 1022
	}

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

	private _updateDecorations(): void {
A
Alex Dima 已提交
1023
		if (!this.originalEditor.getModel() || !this.modifiedEditor.getModel() || !this._originalOverviewRuler || !this._modifiedOverviewRuler) {
1024 1025
			return;
		}
A
Alex Dima 已提交
1026
		const lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);
E
Erich Gamma 已提交
1027

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

1031
		let diffDecorations = this._strategy.getEditorsDiffDecorations(lineChanges, this._ignoreTrimWhitespace, this._renderIndicators, foreignOriginal, foreignModified, this.originalEditor, this.modifiedEditor);
E
Erich Gamma 已提交
1032 1033 1034

		try {
			this._currentlyChangingViewZones = true;
A
Alex Dima 已提交
1035 1036
			this._originalEditorState.apply(this.originalEditor, this._originalOverviewRuler, diffDecorations.original, false);
			this._modifiedEditorState.apply(this.modifiedEditor, this._modifiedOverviewRuler, diffDecorations.modified, true);
E
Erich Gamma 已提交
1037 1038 1039 1040 1041
		} finally {
			this._currentlyChangingViewZones = false;
		}
	}

1042 1043
	private _adjustOptionsForSubEditor(options: IDiffEditorOptions): IDiffEditorOptions {
		let clonedOptions: IDiffEditorOptions = objects.deepClone(options || {});
A
Alex Dima 已提交
1044
		clonedOptions.inDiffEditor = true;
1045
		clonedOptions.wordWrap = 'off';
1046
		clonedOptions.wordWrapMinified = false;
E
Erich Gamma 已提交
1047 1048 1049
		clonedOptions.automaticLayout = false;
		clonedOptions.scrollbar = clonedOptions.scrollbar || {};
		clonedOptions.scrollbar.vertical = 'visible';
A
Alex Dima 已提交
1050
		clonedOptions.folding = false;
1051
		clonedOptions.codeLens = false;
J
Joao Moreno 已提交
1052
		clonedOptions.fixedOverflowWidgets = true;
1053
		// clonedOptions.lineDecorationsWidth = '2ch';
1054 1055 1056
		if (!clonedOptions.minimap) {
			clonedOptions.minimap = {};
		}
1057
		clonedOptions.minimap.enabled = false;
E
Erich Gamma 已提交
1058 1059 1060
		return clonedOptions;
	}

1061
	private _adjustOptionsForLeftHandSide(options: IDiffEditorOptions, isEditable: boolean): IEditorOptions {
1062 1063
		let result = this._adjustOptionsForSubEditor(options);
		result.readOnly = !isEditable;
1064
		result.extraEditorClassName = 'original-in-monaco-diff-editor';
1065 1066 1067
		return result;
	}

1068
	private _adjustOptionsForRightHandSide(options: IDiffEditorOptions): IEditorOptions {
1069
		let result = this._adjustOptionsForSubEditor(options);
A
Alex Dima 已提交
1070
		result.revealHorizontalRightPadding = EditorOptions.revealHorizontalRightPadding.defaultValue + DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
A
Alex Dima 已提交
1071
		result.scrollbar!.verticalHasArrows = false;
1072
		result.extraEditorClassName = 'modified-in-monaco-diff-editor';
1073
		return result;
E
Erich Gamma 已提交
1074 1075
	}

1076
	public doLayout(): void {
1077 1078
		this._elementSizeObserver.observe();
		this._doLayout();
1079 1080
	}

E
Erich Gamma 已提交
1081
	private _doLayout(): void {
1082 1083 1084 1085
		const width = this._elementSizeObserver.getWidth();
		const height = this._elementSizeObserver.getHeight();
		const reviewHeight = this._getReviewHeight();

A
Alex Dima 已提交
1086
		let splitPoint = this._strategy.layout();
E
Erich Gamma 已提交
1087 1088 1089 1090

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

1091
		this._modifiedDomNode.style.width = (width - splitPoint) + 'px';
E
Erich Gamma 已提交
1092 1093 1094
		this._modifiedDomNode.style.left = splitPoint + 'px';

		this._overviewDomElement.style.top = '0px';
1095
		this._overviewDomElement.style.height = (height - reviewHeight) + 'px';
E
Erich Gamma 已提交
1096
		this._overviewDomElement.style.width = DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH + 'px';
1097
		this._overviewDomElement.style.left = (width - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH) + 'px';
A
Alex Dima 已提交
1098 1099
		this._overviewViewportDomElement.setWidth(DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH);
		this._overviewViewportDomElement.setHeight(30);
E
Erich Gamma 已提交
1100

1101 1102
		this.originalEditor.layout({ width: splitPoint, height: (height - reviewHeight) });
		this.modifiedEditor.layout({ width: width - splitPoint - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH, height: (height - reviewHeight) });
E
Erich Gamma 已提交
1103 1104 1105 1106 1107

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

1108
		this._reviewPane.layout(height - reviewHeight, width, reviewHeight);
A
Alex Dima 已提交
1109

E
Erich Gamma 已提交
1110 1111 1112 1113
		this._layoutOverviewViewport();
	}

	private _layoutOverviewViewport(): void {
A
Alex Dima 已提交
1114
		let layout = this._computeOverviewViewport();
E
Erich Gamma 已提交
1115
		if (!layout) {
A
Alex Dima 已提交
1116 1117
			this._overviewViewportDomElement.setTop(0);
			this._overviewViewportDomElement.setHeight(0);
E
Erich Gamma 已提交
1118
		} else {
A
Alex Dima 已提交
1119 1120
			this._overviewViewportDomElement.setTop(layout.top);
			this._overviewViewportDomElement.setHeight(layout.height);
E
Erich Gamma 已提交
1121 1122 1123
		}
	}

A
Alex Dima 已提交
1124
	private _computeOverviewViewport(): { height: number; top: number; } | null {
A
Alex Dima 已提交
1125
		let layoutInfo = this.modifiedEditor.getLayoutInfo();
E
Erich Gamma 已提交
1126 1127 1128 1129
		if (!layoutInfo) {
			return null;
		}

A
Alex Dima 已提交
1130 1131
		let scrollTop = this.modifiedEditor.getScrollTop();
		let scrollHeight = this.modifiedEditor.getScrollHeight();
E
Erich Gamma 已提交
1132

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

1137
		let computedSliderSize = Math.max(0, Math.floor(layoutInfo.height * computedRatio));
A
Alex Dima 已提交
1138
		let computedSliderPosition = Math.floor(scrollTop * computedRatio);
E
Erich Gamma 已提交
1139 1140 1141 1142 1143 1144 1145

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

J
Johannes Rieken 已提交
1146
	private _createDataSource(): IDataSource {
E
Erich Gamma 已提交
1147 1148
		return {
			getWidth: () => {
1149
				return this._elementSizeObserver.getWidth();
E
Erich Gamma 已提交
1150 1151 1152
			},

			getHeight: () => {
1153
				return (this._elementSizeObserver.getHeight() - this._getReviewHeight());
E
Erich Gamma 已提交
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
			},

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

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

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

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

J
Johannes Rieken 已提交
1174
	private _setStrategy(newStrategy: IDiffEditorWidgetStyle): void {
E
Erich Gamma 已提交
1175 1176 1177 1178 1179
		if (this._strategy) {
			this._strategy.dispose();
		}

		this._strategy = newStrategy;
M
Martin Aeschlimann 已提交
1180
		newStrategy.applyColors(this._themeService.getColorTheme());
E
Erich Gamma 已提交
1181

A
Alex Dima 已提交
1182
		if (this._diffComputationResult) {
E
Erich Gamma 已提交
1183 1184 1185 1186
			this._updateDecorations();
		}

		// Just do a layout, the strategy might need it
1187
		this._doLayout();
E
Erich Gamma 已提交
1188 1189
	}

A
Alex Dima 已提交
1190
	private _getLineChangeAtOrBeforeLineNumber(lineNumber: number, startLineNumberExtractor: (lineChange: editorCommon.ILineChange) => number): editorCommon.ILineChange | null {
A
Alex Dima 已提交
1191 1192
		const lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);
		if (lineChanges.length === 0 || lineNumber < startLineNumberExtractor(lineChanges[0])) {
E
Erich Gamma 已提交
1193 1194 1195 1196
			// There are no changes or `lineNumber` is before the first change
			return null;
		}

A
Alex Dima 已提交
1197
		let min = 0, max = lineChanges.length - 1;
E
Erich Gamma 已提交
1198
		while (min < max) {
A
Alex Dima 已提交
1199
			let mid = Math.floor((min + max) / 2);
A
Alex Dima 已提交
1200
			let midStart = startLineNumberExtractor(lineChanges[mid]);
1201
			let midEnd = (mid + 1 <= max ? startLineNumberExtractor(lineChanges[mid + 1]) : Constants.MAX_SAFE_SMALL_INTEGER);
E
Erich Gamma 已提交
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212

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

	private _getEquivalentLineForOriginalLineNumber(lineNumber: number): number {
A
Alex Dima 已提交
1217
		let lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.originalStartLineNumber);
E
Erich Gamma 已提交
1218 1219 1220 1221 1222

		if (!lineChange) {
			return lineNumber;
		}

A
Alex Dima 已提交
1223 1224 1225 1226
		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 已提交
1227 1228


A
Alex Dima 已提交
1229
		let delta = lineNumber - originalEquivalentLineNumber;
E
Erich Gamma 已提交
1230 1231 1232 1233 1234

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

J
Johannes Rieken 已提交
1235
		return modifiedEquivalentLineNumber + lineChangeModifiedLength - lineChangeOriginalLength + delta;
E
Erich Gamma 已提交
1236 1237 1238
	}

	private _getEquivalentLineForModifiedLineNumber(lineNumber: number): number {
A
Alex Dima 已提交
1239
		let lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.modifiedStartLineNumber);
E
Erich Gamma 已提交
1240 1241 1242 1243 1244

		if (!lineChange) {
			return lineNumber;
		}

A
Alex Dima 已提交
1245 1246 1247 1248
		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 已提交
1249 1250


A
Alex Dima 已提交
1251
		let delta = lineNumber - modifiedEquivalentLineNumber;
E
Erich Gamma 已提交
1252 1253 1254 1255 1256

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

J
Johannes Rieken 已提交
1257
		return originalEquivalentLineNumber + lineChangeOriginalLength - lineChangeModifiedLength + delta;
E
Erich Gamma 已提交
1258 1259
	}

A
Alex Dima 已提交
1260
	public getDiffLineInformationForOriginal(lineNumber: number): editorBrowser.IDiffLineInformation | null {
A
Alex Dima 已提交
1261
		if (!this._diffComputationResult) {
E
Erich Gamma 已提交
1262 1263 1264 1265 1266 1267 1268 1269
			// Cannot answer that which I don't know
			return null;
		}
		return {
			equivalentLineNumber: this._getEquivalentLineForOriginalLineNumber(lineNumber)
		};
	}

A
Alex Dima 已提交
1270
	public getDiffLineInformationForModified(lineNumber: number): editorBrowser.IDiffLineInformation | null {
A
Alex Dima 已提交
1271
		if (!this._diffComputationResult) {
E
Erich Gamma 已提交
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
			// 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 已提交
1287 1288
	getOriginalEditor(): editorBrowser.ICodeEditor;
	getModifiedEditor(): editorBrowser.ICodeEditor;
E
Erich Gamma 已提交
1289 1290
}

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

J
Johannes Rieken 已提交
1293
	_dataSource: IDataSource;
A
Alex Dima 已提交
1294 1295
	_insertColor: Color | null;
	_removeColor: Color | null;
E
Erich Gamma 已提交
1296

J
Johannes Rieken 已提交
1297
	constructor(dataSource: IDataSource) {
A
Alex Dima 已提交
1298
		super();
E
Erich Gamma 已提交
1299
		this._dataSource = dataSource;
A
Alex Dima 已提交
1300 1301
		this._insertColor = null;
		this._removeColor = null;
E
Erich Gamma 已提交
1302 1303
	}

M
Martin Aeschlimann 已提交
1304
	public applyColors(theme: IColorTheme): boolean {
1305 1306 1307 1308 1309 1310 1311 1312
		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 已提交
1313
	public getEditorsDiffDecorations(lineChanges: editorCommon.ILineChange[], ignoreTrimWhitespace: boolean, renderIndicators: boolean, originalWhitespaces: IEditorWhitespace[], modifiedWhitespaces: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsDiffDecorationsWithZones {
E
Erich Gamma 已提交
1314 1315 1316 1317 1318 1319 1320
		// Get view zones
		modifiedWhitespaces = modifiedWhitespaces.sort((a, b) => {
			return a.afterLineNumber - b.afterLineNumber;
		});
		originalWhitespaces = originalWhitespaces.sort((a, b) => {
			return a.afterLineNumber - b.afterLineNumber;
		});
1321
		let zones = this._getViewZones(lineChanges, originalWhitespaces, modifiedWhitespaces, originalEditor, modifiedEditor, renderIndicators);
E
Erich Gamma 已提交
1322 1323

		// Get decorations & overview ruler zones
1324 1325
		let originalDecorations = this._getOriginalEditorDecorations(lineChanges, ignoreTrimWhitespace, renderIndicators, originalEditor, modifiedEditor);
		let modifiedDecorations = this._getModifiedEditorDecorations(lineChanges, ignoreTrimWhitespace, renderIndicators, originalEditor, modifiedEditor);
E
Erich Gamma 已提交
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340

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

1341 1342 1343
	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 已提交
1344 1345 1346

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

A
Alex Dima 已提交
1349
interface IMyViewZone {
E
Erich Gamma 已提交
1350
	shouldNotShrink?: boolean;
A
Alex Dima 已提交
1351 1352 1353 1354 1355
	afterLineNumber: number;
	heightInLines: number;
	minWidthInPx?: number;
	domNode: HTMLElement | null;
	marginDomNode?: HTMLElement | null;
1356
	diff?: IDiffLinesChange;
E
Erich Gamma 已提交
1357 1358 1359 1360 1361
}

class ForeignViewZonesIterator {

	private _index: number;
1362
	private readonly _source: IEditorWhitespace[];
A
Alex Dima 已提交
1363
	public current: IEditorWhitespace | null;
E
Erich Gamma 已提交
1364

A
Alex Dima 已提交
1365
	constructor(source: IEditorWhitespace[]) {
E
Erich Gamma 已提交
1366 1367
		this._source = source;
		this._index = -1;
A
Alex Dima 已提交
1368
		this.current = null;
E
Erich Gamma 已提交
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
		this.advance();
	}

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

1382
abstract class ViewZonesComputer {
E
Erich Gamma 已提交
1383

1384 1385
	private readonly lineChanges: editorCommon.ILineChange[];
	private readonly originalForeignVZ: IEditorWhitespace[];
1386
	private readonly originalLineHeight: number;
1387
	private readonly modifiedForeignVZ: IEditorWhitespace[];
1388
	private readonly modifiedLineHeight: number;
E
Erich Gamma 已提交
1389

1390
	constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], originalLineHeight: number, modifiedForeignVZ: IEditorWhitespace[], modifiedLineHeight: number) {
E
Erich Gamma 已提交
1391 1392
		this.lineChanges = lineChanges;
		this.originalForeignVZ = originalForeignVZ;
1393
		this.originalLineHeight = originalLineHeight;
E
Erich Gamma 已提交
1394
		this.modifiedForeignVZ = modifiedForeignVZ;
1395
		this.modifiedLineHeight = modifiedLineHeight;
E
Erich Gamma 已提交
1396 1397 1398
	}

	public getViewZones(): IEditorsZones {
A
Alex Dima 已提交
1399
		let result: { original: IMyViewZone[]; modified: IMyViewZone[]; } = {
E
Erich Gamma 已提交
1400 1401 1402 1403
			original: [],
			modified: []
		};

A
Alex Dima 已提交
1404 1405 1406 1407 1408 1409 1410 1411
		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 已提交
1412 1413 1414
			return a.afterLineNumber - b.afterLineNumber;
		};

A
Alex Dima 已提交
1415
		let addAndCombineIfPossible = (destination: IMyViewZone[], item: IMyViewZone) => {
E
Erich Gamma 已提交
1416
			if (item.domNode === null && destination.length > 0) {
A
Alex Dima 已提交
1417
				let lastItem = destination[destination.length - 1];
E
Erich Gamma 已提交
1418 1419 1420 1421 1422 1423 1424 1425
				if (lastItem.afterLineNumber === item.afterLineNumber && lastItem.domNode === null) {
					lastItem.heightInLines += item.heightInLines;
					return;
				}
			}
			destination.push(item);
		};

A
Alex Dima 已提交
1426 1427
		let modifiedForeignVZ = new ForeignViewZonesIterator(this.modifiedForeignVZ);
		let originalForeignVZ = new ForeignViewZonesIterator(this.originalForeignVZ);
E
Erich Gamma 已提交
1428 1429

		// 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 已提交
1430 1431
		for (let i = 0, length = this.lineChanges.length; i <= length; i++) {
			let lineChange = (i < length ? this.lineChanges[i] : null);
E
Erich Gamma 已提交
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448

			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 已提交
1449 1450
			let stepOriginal: IMyViewZone[] = [];
			let stepModified: IMyViewZone[] = [];
E
Erich Gamma 已提交
1451 1452 1453 1454 1455

			// ---------------------------- 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 已提交
1456
				let viewZoneLineNumber: number;
E
Erich Gamma 已提交
1457 1458 1459 1460 1461
				if (modifiedForeignVZ.current.afterLineNumber <= modifiedEquivalentLineNumber) {
					viewZoneLineNumber = originalEquivalentLineNumber - modifiedEquivalentLineNumber + modifiedForeignVZ.current.afterLineNumber;
				} else {
					viewZoneLineNumber = originalEndEquivalentLineNumber;
				}
A
Alex Dima 已提交
1462

1463
				let marginDomNode: HTMLDivElement | null = null;
A
Alex Dima 已提交
1464 1465 1466 1467
				if (lineChange && lineChange.modifiedStartLineNumber <= modifiedForeignVZ.current.afterLineNumber && modifiedForeignVZ.current.afterLineNumber <= lineChange.modifiedEndLineNumber) {
					marginDomNode = this._createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion();
				}

E
Erich Gamma 已提交
1468 1469
				stepOriginal.push({
					afterLineNumber: viewZoneLineNumber,
1470
					heightInLines: modifiedForeignVZ.current.height / this.modifiedLineHeight,
A
Alex Dima 已提交
1471 1472
					domNode: null,
					marginDomNode: marginDomNode
E
Erich Gamma 已提交
1473 1474 1475 1476 1477 1478
				});
				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 已提交
1479
				let viewZoneLineNumber: number;
E
Erich Gamma 已提交
1480 1481 1482 1483 1484 1485 1486
				if (originalForeignVZ.current.afterLineNumber <= originalEquivalentLineNumber) {
					viewZoneLineNumber = modifiedEquivalentLineNumber - originalEquivalentLineNumber + originalForeignVZ.current.afterLineNumber;
				} else {
					viewZoneLineNumber = modifiedEndEquivalentLineNumber;
				}
				stepModified.push({
					afterLineNumber: viewZoneLineNumber,
1487
					heightInLines: originalForeignVZ.current.height / this.originalLineHeight,
E
Erich Gamma 已提交
1488 1489 1490 1491 1492 1493
					domNode: null
				});
				originalForeignVZ.advance();
			}

			if (lineChange !== null && isChangeOrInsert(lineChange)) {
A
Alex Dima 已提交
1494
				let r = this._produceOriginalFromDiff(lineChange, lineChangeOriginalLength, lineChangeModifiedLength);
E
Erich Gamma 已提交
1495 1496 1497 1498 1499 1500
				if (r) {
					stepOriginal.push(r);
				}
			}

			if (lineChange !== null && isChangeOrDelete(lineChange)) {
A
Alex Dima 已提交
1501
				let r = this._produceModifiedFromDiff(lineChange, lineChangeOriginalLength, lineChangeModifiedLength);
E
Erich Gamma 已提交
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
				if (r) {
					stepModified.push(r);
				}
			}

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


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

			// [CANCEL & EMIT] Try to cancel view zones out
A
Alex Dima 已提交
1513 1514
			let stepOriginalIndex = 0;
			let stepModifiedIndex = 0;
E
Erich Gamma 已提交
1515 1516 1517 1518 1519

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

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

A
Alex Dima 已提交
1523 1524
				let originalDelta = original.afterLineNumber - originalEquivalentLineNumber;
				let modifiedDelta = modified.afterLineNumber - modifiedEquivalentLineNumber;
E
Erich Gamma 已提交
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 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

				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 已提交
1566 1567 1568 1569 1570 1571
		return {
			original: ViewZonesComputer._ensureDomNodes(result.original),
			modified: ViewZonesComputer._ensureDomNodes(result.modified),
		};
	}

1572
	private static _ensureDomNodes(zones: IMyViewZone[]): IMyViewZone[] {
A
Alex Dima 已提交
1573
		return zones.map((z) => {
E
Erich Gamma 已提交
1574 1575 1576
			if (!z.domNode) {
				z.domNode = createFakeLinesDiv();
			}
1577
			return z;
A
Alex Dima 已提交
1578
		});
E
Erich Gamma 已提交
1579 1580
	}

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

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

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

1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619
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',
M
Martin Aeschlimann 已提交
1620
		linesDecorationsClassName: 'insert-sign ' + diffInsertIcon.classNames,
1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631
		marginClassName: 'line-insert',
		isWholeLine: true
	}),

	lineDelete: ModelDecorationOptions.register({
		className: 'line-delete',
		marginClassName: 'line-delete',
		isWholeLine: true
	}),
	lineDeleteWithSign: ModelDecorationOptions.register({
		className: 'line-delete',
M
Martin Aeschlimann 已提交
1632
		linesDecorationsClassName: 'delete-sign ' + diffRemoveIcon.classNames,
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
		marginClassName: 'line-delete',
		isWholeLine: true

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

};

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

1645
	static readonly MINIMUM_EDITOR_WIDTH = 100;
E
Erich Gamma 已提交
1646 1647

	private _disableSash: boolean;
1648
	private readonly _sash: Sash;
A
Alex Dima 已提交
1649 1650
	private _sashRatio: number | null;
	private _sashPosition: number | null;
A
Alex Dima 已提交
1651
	private _startSashPosition: number | null;
E
Erich Gamma 已提交
1652

J
Johannes Rieken 已提交
1653
	constructor(dataSource: IDataSource, enableSplitViewResizing: boolean) {
E
Erich Gamma 已提交
1654 1655 1656 1657 1658
		super(dataSource);

		this._disableSash = (enableSplitViewResizing === false);
		this._sashRatio = null;
		this._sashPosition = null;
A
Alex Dima 已提交
1659
		this._startSashPosition = null;
A
Alex Dima 已提交
1660
		this._sash = this._register(new Sash(this._dataSource.getContainerDomNode(), this));
E
Erich Gamma 已提交
1661 1662

		if (this._disableSash) {
J
Joao Moreno 已提交
1663
			this._sash.state = SashState.Disabled;
E
Erich Gamma 已提交
1664 1665
		}

I
isidor 已提交
1666 1667 1668 1669
		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 已提交
1670 1671
	}

J
Johannes Rieken 已提交
1672
	public setEnableSplitViewResizing(enableSplitViewResizing: boolean): void {
A
Alex Dima 已提交
1673
		let newDisableSash = (enableSplitViewResizing === false);
E
Erich Gamma 已提交
1674 1675
		if (this._disableSash !== newDisableSash) {
			this._disableSash = newDisableSash;
J
Joao Moreno 已提交
1676
			this._sash.state = this._disableSash ? SashState.Disabled : SashState.Enabled;
E
Erich Gamma 已提交
1677 1678 1679
		}
	}

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

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

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

H
Howard Hung 已提交
1689 1690 1691
		if (contentWidth > DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH * 2) {
			if (sashPosition < DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
				sashPosition = DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
E
Erich Gamma 已提交
1692 1693
			}

H
Howard Hung 已提交
1694 1695
			if (sashPosition > contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) {
				sashPosition = contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH;
E
Erich Gamma 已提交
1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708
			}
		} else {
			sashPosition = midPoint;
		}

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

		return this._sashPosition;
	}

M
Maxime Quandalle 已提交
1709
	private onSashDragStart(): void {
A
Alex Dima 已提交
1710
		this._startSashPosition = this._sashPosition!;
E
Erich Gamma 已提交
1711 1712
	}

J
Johannes Rieken 已提交
1713
	private onSashDrag(e: ISashEvent): void {
A
Alex Dima 已提交
1714 1715
		let w = this._dataSource.getWidth();
		let contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
A
Alex Dima 已提交
1716
		let sashPosition = this.layout((this._startSashPosition! + (e.currentX - e.startX)) / contentWidth);
E
Erich Gamma 已提交
1717 1718 1719 1720 1721 1722

		this._sashRatio = sashPosition / contentWidth;

		this._dataSource.relayoutEditors();
	}

M
Maxime Quandalle 已提交
1723 1724 1725 1726 1727 1728 1729
	private onSashDragEnd(): void {
		this._sash.layout();
	}

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

A
Alex Dima 已提交
1733
	public getVerticalSashTop(sash: Sash): number {
E
Erich Gamma 已提交
1734 1735 1736
		return 0;
	}

A
Alex Dima 已提交
1737
	public getVerticalSashLeft(sash: Sash): number {
A
Alex Dima 已提交
1738
		return this._sashPosition!;
E
Erich Gamma 已提交
1739 1740
	}

A
Alex Dima 已提交
1741
	public getVerticalSashHeight(sash: Sash): number {
E
Erich Gamma 已提交
1742 1743 1744
		return this._dataSource.getHeight();
	}

1745
	protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor): IEditorsZones {
1746
		let c = new SideBySideViewZonesComputer(lineChanges, originalForeignVZ, originalEditor.getOption(EditorOption.lineHeight), modifiedForeignVZ, modifiedEditor.getOption(EditorOption.lineHeight));
E
Erich Gamma 已提交
1747 1748 1749
		return c.getViewZones();
	}

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

A
Alex Dima 已提交
1753
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1754 1755
			decorations: [],
			overviewZones: []
P
Peng Lyu 已提交
1756
		};
A
Alex Dima 已提交
1757

A
Alex Dima 已提交
1758
		let originalModel = originalEditor.getModel()!;
A
Alex Dima 已提交
1759 1760 1761

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

			if (isChangeOrDelete(lineChange)) {
1764
				result.decorations.push({
1765
					range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1766
					options: (renderIndicators ? DECORATIONS.lineDeleteWithSign : DECORATIONS.lineDelete)
1767
				});
E
Erich Gamma 已提交
1768
				if (!isChangeOrInsert(lineChange) || !lineChange.charChanges) {
1769
					result.decorations.push(createDecoration(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charDeleteWholeLine));
E
Erich Gamma 已提交
1770 1771
				}

A
Alex Dima 已提交
1772
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1773 1774
					lineChange.originalStartLineNumber,
					lineChange.originalEndLineNumber,
A
Alex Dima 已提交
1775
					overviewZoneColor
A
Alex Dima 已提交
1776
				));
E
Erich Gamma 已提交
1777 1778

				if (lineChange.charChanges) {
A
Alex Dima 已提交
1779 1780
					for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
						let charChange = lineChange.charChanges[j];
E
Erich Gamma 已提交
1781 1782
						if (isChangeOrDelete(charChange)) {
							if (ignoreTrimWhitespace) {
A
Alex Dima 已提交
1783 1784 1785
								for (let lineNumber = charChange.originalStartLineNumber; lineNumber <= charChange.originalEndLineNumber; lineNumber++) {
									let startColumn: number;
									let endColumn: number;
E
Erich Gamma 已提交
1786 1787 1788 1789 1790 1791 1792 1793 1794 1795
									if (lineNumber === charChange.originalStartLineNumber) {
										startColumn = charChange.originalStartColumn;
									} else {
										startColumn = originalModel.getLineFirstNonWhitespaceColumn(lineNumber);
									}
									if (lineNumber === charChange.originalEndLineNumber) {
										endColumn = charChange.originalEndColumn;
									} else {
										endColumn = originalModel.getLineLastNonWhitespaceColumn(lineNumber);
									}
1796
									result.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charDelete));
E
Erich Gamma 已提交
1797 1798
								}
							} else {
1799
								result.decorations.push(createDecoration(charChange.originalStartLineNumber, charChange.originalStartColumn, charChange.originalEndLineNumber, charChange.originalEndColumn, DECORATIONS.charDelete));
E
Erich Gamma 已提交
1800 1801 1802 1803 1804 1805 1806 1807 1808 1809
							}
						}
					}
				}
			}
		}

		return result;
	}

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

A
Alex Dima 已提交
1813
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1814 1815
			decorations: [],
			overviewZones: []
A
Alex Dima 已提交
1816 1817
		};

A
Alex Dima 已提交
1818
		let modifiedModel = modifiedEditor.getModel()!;
A
Alex Dima 已提交
1819 1820 1821

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

			if (isChangeOrInsert(lineChange)) {

1825
				result.decorations.push({
1826
					range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1827
					options: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert)
1828
				});
E
Erich Gamma 已提交
1829
				if (!isChangeOrDelete(lineChange) || !lineChange.charChanges) {
1830
					result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER, DECORATIONS.charInsertWholeLine));
E
Erich Gamma 已提交
1831
				}
A
Alex Dima 已提交
1832
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1833 1834
					lineChange.modifiedStartLineNumber,
					lineChange.modifiedEndLineNumber,
A
Alex Dima 已提交
1835
					overviewZoneColor
A
Alex Dima 已提交
1836
				));
E
Erich Gamma 已提交
1837 1838

				if (lineChange.charChanges) {
A
Alex Dima 已提交
1839 1840
					for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
						let charChange = lineChange.charChanges[j];
E
Erich Gamma 已提交
1841 1842
						if (isChangeOrInsert(charChange)) {
							if (ignoreTrimWhitespace) {
A
Alex Dima 已提交
1843 1844 1845
								for (let lineNumber = charChange.modifiedStartLineNumber; lineNumber <= charChange.modifiedEndLineNumber; lineNumber++) {
									let startColumn: number;
									let endColumn: number;
E
Erich Gamma 已提交
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855
									if (lineNumber === charChange.modifiedStartLineNumber) {
										startColumn = charChange.modifiedStartColumn;
									} else {
										startColumn = modifiedModel.getLineFirstNonWhitespaceColumn(lineNumber);
									}
									if (lineNumber === charChange.modifiedEndLineNumber) {
										endColumn = charChange.modifiedEndColumn;
									} else {
										endColumn = modifiedModel.getLineLastNonWhitespaceColumn(lineNumber);
									}
1856
									result.decorations.push(createDecoration(lineNumber, startColumn, lineNumber, endColumn, DECORATIONS.charInsert));
E
Erich Gamma 已提交
1857 1858
								}
							} else {
1859
								result.decorations.push(createDecoration(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn, DECORATIONS.charInsert));
E
Erich Gamma 已提交
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872
							}
						}
					}
				}

			}
		}
		return result;
	}
}

class SideBySideViewZonesComputer extends ViewZonesComputer {

1873 1874
	constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], originalLineHeight: number, modifiedForeignVZ: IEditorWhitespace[], modifiedLineHeight: number) {
		super(lineChanges, originalForeignVZ, originalLineHeight, modifiedForeignVZ, modifiedLineHeight);
E
Erich Gamma 已提交
1875 1876
	}

A
Alex Dima 已提交
1877
	protected _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null {
A
Alex Dima 已提交
1878 1879 1880
		return null;
	}

A
Alex Dima 已提交
1881
	protected _produceOriginalFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {
E
Erich Gamma 已提交
1882 1883 1884 1885 1886 1887 1888 1889 1890 1891
		if (lineChangeModifiedLength > lineChangeOriginalLength) {
			return {
				afterLineNumber: Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber),
				heightInLines: (lineChangeModifiedLength - lineChangeOriginalLength),
				domNode: null
			};
		}
		return null;
	}

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

H
Howard Hung 已提交
1904
class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle {
E
Erich Gamma 已提交
1905 1906 1907

	private decorationsLeft: number;

J
Johannes Rieken 已提交
1908
	constructor(dataSource: IDataSource, enableSplitViewResizing: boolean) {
E
Erich Gamma 已提交
1909 1910
		super(dataSource);

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

1913
		this._register(dataSource.getOriginalEditor().onDidLayoutChange((layoutInfo: EditorLayoutInfo) => {
E
Erich Gamma 已提交
1914 1915 1916 1917 1918 1919 1920
			if (this.decorationsLeft !== layoutInfo.decorationsLeft) {
				this.decorationsLeft = layoutInfo.decorationsLeft;
				dataSource.relayoutEditors();
			}
		}));
	}

J
Johannes Rieken 已提交
1921
	public setEnableSplitViewResizing(enableSplitViewResizing: boolean): void {
E
Erich Gamma 已提交
1922 1923 1924
		// Nothing to do..
	}

1925
	protected _getViewZones(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean): IEditorsZones {
1926
		let computer = new InlineViewZonesComputer(lineChanges, originalForeignVZ, modifiedForeignVZ, originalEditor, modifiedEditor, renderIndicators);
E
Erich Gamma 已提交
1927 1928 1929
		return computer.getViewZones();
	}

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

A
Alex Dima 已提交
1933
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1934 1935
			decorations: [],
			overviewZones: []
A
Alex Dima 已提交
1936
		};
E
Erich Gamma 已提交
1937

A
Alex Dima 已提交
1938 1939
		for (let i = 0, length = lineChanges.length; i < length; i++) {
			let lineChange = lineChanges[i];
E
Erich Gamma 已提交
1940 1941 1942

			// Add overview zones in the overview ruler
			if (isChangeOrDelete(lineChange)) {
1943
				result.decorations.push({
1944
					range: new Range(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1945
					options: DECORATIONS.lineDeleteMargin
1946 1947
				});

A
Alex Dima 已提交
1948
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1949 1950
					lineChange.originalStartLineNumber,
					lineChange.originalEndLineNumber,
A
Alex Dima 已提交
1951
					overviewZoneColor
A
Alex Dima 已提交
1952
				));
E
Erich Gamma 已提交
1953 1954 1955 1956 1957 1958
			}
		}

		return result;
	}

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

A
Alex Dima 已提交
1962
		let result: IEditorDiffDecorations = {
J
Johannes Rieken 已提交
1963 1964
			decorations: [],
			overviewZones: []
A
Alex Dima 已提交
1965 1966
		};

A
Alex Dima 已提交
1967
		let modifiedModel = modifiedEditor.getModel()!;
A
Alex Dima 已提交
1968 1969 1970

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

			// Add decorations & overview zones
			if (isChangeOrInsert(lineChange)) {
1974
				result.decorations.push({
1975
					range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Constants.MAX_SAFE_SMALL_INTEGER),
1976
					options: (renderIndicators ? DECORATIONS.lineInsertWithSign : DECORATIONS.lineInsert)
1977
				});
E
Erich Gamma 已提交
1978

A
Alex Dima 已提交
1979
				result.overviewZones.push(new OverviewRulerZone(
A
Alex Dima 已提交
1980 1981
					lineChange.modifiedStartLineNumber,
					lineChange.modifiedEndLineNumber,
A
Alex Dima 已提交
1982
					overviewZoneColor
A
Alex Dima 已提交
1983
				));
E
Erich Gamma 已提交
1984 1985

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

		return result;
	}

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

}

class InlineViewZonesComputer extends ViewZonesComputer {

2028
	private readonly originalModel: ITextModel;
2029
	private readonly modifiedEditorOptions: IComputedEditorOptions;
2030 2031
	private readonly modifiedEditorTabSize: number;
	private readonly renderIndicators: boolean;
E
Erich Gamma 已提交
2032

A
Alex Dima 已提交
2033
	constructor(lineChanges: editorCommon.ILineChange[], originalForeignVZ: IEditorWhitespace[], modifiedForeignVZ: IEditorWhitespace[], originalEditor: editorBrowser.ICodeEditor, modifiedEditor: editorBrowser.ICodeEditor, renderIndicators: boolean) {
2034
		super(lineChanges, originalForeignVZ, originalEditor.getOption(EditorOption.lineHeight), modifiedForeignVZ, modifiedEditor.getOption(EditorOption.lineHeight));
A
Alex Dima 已提交
2035
		this.originalModel = originalEditor.getModel()!;
A
Alex Dima 已提交
2036
		this.modifiedEditorOptions = modifiedEditor.getOptions();
A
Alex Dima 已提交
2037
		this.modifiedEditorTabSize = modifiedEditor.getModel()!.getOptions().tabSize;
R
rebornix 已提交
2038
		this.renderIndicators = renderIndicators;
E
Erich Gamma 已提交
2039 2040
	}

A
Alex Dima 已提交
2041
	protected _createOriginalMarginDomNodeForModifiedForeignViewZoneInAddedRegion(): HTMLDivElement | null {
A
Alex Dima 已提交
2042 2043 2044 2045 2046
		let result = document.createElement('div');
		result.className = 'inline-added-margin-view-zone';
		return result;
	}

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

E
Erich Gamma 已提交
2051
		return {
J
Johannes Rieken 已提交
2052
			afterLineNumber: Math.max(lineChange.originalStartLineNumber, lineChange.originalEndLineNumber),
E
Erich Gamma 已提交
2053
			heightInLines: lineChangeModifiedLength,
2054 2055
			domNode: document.createElement('div'),
			marginDomNode: marginDomNode
E
Erich Gamma 已提交
2056 2057 2058
		};
	}

A
Alex Dima 已提交
2059
	protected _produceModifiedFromDiff(lineChange: editorCommon.ILineChange, lineChangeOriginalLength: number, lineChangeModifiedLength: number): IMyViewZone | null {
A
Alex Dima 已提交
2060
		let decorations: InlineDecoration[] = [];
E
Erich Gamma 已提交
2061
		if (lineChange.charChanges) {
A
Alex Dima 已提交
2062 2063
			for (let j = 0, lengthJ = lineChange.charChanges.length; j < lengthJ; j++) {
				let charChange = lineChange.charChanges[j];
E
Erich Gamma 已提交
2064
				if (isChangeOrDelete(charChange)) {
2065 2066
					decorations.push(new InlineDecoration(
						new Range(charChange.originalStartLineNumber, charChange.originalStartColumn, charChange.originalEndLineNumber, charChange.originalEndColumn),
2067
						'char-delete',
2068
						InlineDecorationType.Regular
2069
					));
E
Erich Gamma 已提交
2070 2071 2072 2073
				}
			}
		}

2074
		let sb = createStringBuilder(10000);
2075
		let marginHTML: string[] = [];
A
renames  
Alex Dima 已提交
2076
		const layoutInfo = this.modifiedEditorOptions.get(EditorOption.layoutInfo);
2077
		const fontInfo = this.modifiedEditorOptions.get(EditorOption.fontInfo);
A
Alex Dima 已提交
2078 2079
		const lineDecorationsWidth = layoutInfo.decorationsWidth;

A
Alex Dima 已提交
2080
		let lineHeight = this.modifiedEditorOptions.get(EditorOption.lineHeight);
2081
		const typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;
2082
		let maxCharsPerLine = 0;
2083
		const originalContent: string[] = [];
A
Alex Dima 已提交
2084
		for (let lineNumber = lineChange.originalStartLineNumber; lineNumber <= lineChange.originalEndLineNumber; lineNumber++) {
2085
			maxCharsPerLine = Math.max(maxCharsPerLine, this._renderOriginalLine(lineNumber - lineChange.originalStartLineNumber, this.originalModel, this.modifiedEditorOptions, this.modifiedEditorTabSize, lineNumber, decorations, sb));
2086
			originalContent.push(this.originalModel.getLineContent(lineNumber));
2087

R
rebornix 已提交
2088
			if (this.renderIndicators) {
2089 2090
				let index = lineNumber - lineChange.originalStartLineNumber;
				marginHTML = marginHTML.concat([
M
Martin Aeschlimann 已提交
2091
					`<div class="delete-sign ${diffRemoveIcon.classNames}" style="position:absolute;top:${index * lineHeight}px;width:${lineDecorationsWidth}px;height:${lineHeight}px;right:0;"></div>`
2092 2093
				]);
			}
E
Erich Gamma 已提交
2094
		}
A
Alex Dima 已提交
2095
		maxCharsPerLine += this.modifiedEditorOptions.get(EditorOption.scrollBeyondLastColumn);
E
Erich Gamma 已提交
2096

A
Alex Dima 已提交
2097
		let domNode = document.createElement('div');
E
Erich Gamma 已提交
2098
		domNode.className = 'view-lines line-delete';
2099
		domNode.innerHTML = sb.build();
2100
		Configuration.applyFontInfoSlow(domNode, fontInfo);
E
Erich Gamma 已提交
2101

2102 2103 2104
		let marginDomNode = document.createElement('div');
		marginDomNode.className = 'inline-deleted-margin-view-zone';
		marginDomNode.innerHTML = marginHTML.join('');
2105
		Configuration.applyFontInfoSlow(marginDomNode, fontInfo);
2106

E
Erich Gamma 已提交
2107 2108 2109 2110
		return {
			shouldNotShrink: true,
			afterLineNumber: (lineChange.modifiedEndLineNumber === 0 ? lineChange.modifiedStartLineNumber : lineChange.modifiedStartLineNumber - 1),
			heightInLines: lineChangeOriginalLength,
2111
			minWidthInPx: (maxCharsPerLine * typicalHalfwidthCharacterWidth),
2112
			domNode: domNode,
2113 2114 2115 2116 2117 2118 2119 2120
			marginDomNode: marginDomNode,
			diff: {
				originalStartLineNumber: lineChange.originalStartLineNumber,
				originalEndLineNumber: lineChange.originalEndLineNumber,
				modifiedStartLineNumber: lineChange.modifiedStartLineNumber,
				modifiedEndLineNumber: lineChange.modifiedEndLineNumber,
				originalContent: originalContent
			}
E
Erich Gamma 已提交
2121 2122 2123
		};
	}

2124
	private _renderOriginalLine(count: number, originalModel: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number, decorations: InlineDecoration[], sb: IStringBuilder): number {
2125 2126
		const lineTokens = originalModel.getLineTokens(lineNumber);
		const lineContent = lineTokens.getLineContent();
2127
		const fontInfo = options.get(EditorOption.fontInfo);
A
Alex Dima 已提交
2128

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

2131 2132 2133 2134 2135 2136
		sb.appendASCIIString('<div class="view-line');
		if (decorations.length === 0) {
			// No char changes
			sb.appendASCIIString(' char-delete');
		}
		sb.appendASCIIString('" style="top:');
A
Alex Dima 已提交
2137
		sb.appendASCIIString(String(count * options.get(EditorOption.lineHeight)));
2138 2139
		sb.appendASCIIString('px;width:1000000px;">');

2140 2141
		const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII());
		const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL());
2142
		const output = renderViewLine(new RenderLineInput(
2143
			(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)),
2144
			fontInfo.canUseHalfwidthRightwardsArrow,
A
Alex Dima 已提交
2145
			lineContent,
A
Alex Dima 已提交
2146
			false,
2147 2148
			isBasicASCII,
			containsRTL,
2149
			0,
A
Alex Dima 已提交
2150
			lineTokens,
2151
			actualDecorations,
A
Alex Dima 已提交
2152
			tabSize,
2153
			0,
2154
			fontInfo.spaceWidth,
2155
			fontInfo.middotWidth,
2156
			fontInfo.wsmiddotWidth,
A
Alex Dima 已提交
2157 2158 2159
			options.get(EditorOption.stopRenderingLineAfter),
			options.get(EditorOption.renderWhitespace),
			options.get(EditorOption.renderControlCharacters),
2160
			options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF,
2161
			null // Send no selections, original line cannot be selected
2162
		), sb);
E
Erich Gamma 已提交
2163

2164
		sb.appendASCIIString('</div>');
2165 2166 2167

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

J
Johannes Rieken 已提交
2171
function isChangeOrInsert(lineChange: editorCommon.IChange): boolean {
E
Erich Gamma 已提交
2172 2173 2174
	return lineChange.modifiedEndLineNumber > 0;
}

J
Johannes Rieken 已提交
2175
function isChangeOrDelete(lineChange: editorCommon.IChange): boolean {
E
Erich Gamma 已提交
2176 2177 2178 2179
	return lineChange.originalEndLineNumber > 0;
}

function createFakeLinesDiv(): HTMLElement {
A
Alex Dima 已提交
2180
	let r = document.createElement('div');
E
Erich Gamma 已提交
2181 2182 2183
	r.className = 'diagonal-fill';
	return r;
}
2184 2185

registerThemingParticipant((theme, collector) => {
2186
	const added = theme.getColor(diffInserted);
2187 2188
	if (added) {
		collector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { background-color: ${added}; }`);
A
Alex Dima 已提交
2189
		collector.addRule(`.monaco-diff-editor .line-insert, .monaco-diff-editor .char-insert { background-color: ${added}; }`);
2190 2191
		collector.addRule(`.monaco-editor .inline-added-margin-view-zone { background-color: ${added}; }`);
	}
2192 2193

	const removed = theme.getColor(diffRemoved);
2194 2195
	if (removed) {
		collector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { background-color: ${removed}; }`);
A
Alex Dima 已提交
2196
		collector.addRule(`.monaco-diff-editor .line-delete, .monaco-diff-editor .char-delete { background-color: ${removed}; }`);
2197 2198
		collector.addRule(`.monaco-editor .inline-deleted-margin-view-zone { background-color: ${removed}; }`);
	}
2199 2200

	const addedOutline = theme.getColor(diffInsertedOutline);
2201
	if (addedOutline) {
2202
		collector.addRule(`.monaco-editor .line-insert, .monaco-editor .char-insert { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${addedOutline}; }`);
2203
	}
2204 2205

	const removedOutline = theme.getColor(diffRemovedOutline);
2206
	if (removedOutline) {
2207
		collector.addRule(`.monaco-editor .line-delete, .monaco-editor .char-delete { border: 1px ${theme.type === 'hc' ? 'dashed' : 'solid'} ${removedOutline}; }`);
2208
	}
2209 2210

	const shadow = theme.getColor(scrollbarShadow);
2211 2212 2213
	if (shadow) {
		collector.addRule(`.monaco-diff-editor.side-by-side .editor.modified { box-shadow: -6px 0 5px -5px ${shadow}; }`);
	}
2214

M
Matt Bierner 已提交
2215
	const border = theme.getColor(diffBorder);
2216 2217 2218
	if (border) {
		collector.addRule(`.monaco-diff-editor.side-by-side .editor.modified { border-left: 1px solid ${border}; }`);
	}
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246

	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};
			}
		`);
	}

2247
});