Skip to content

Commit 3e19ba9

Browse files
authored
Allows to pass in a custom diffing algorithm when instantiating the monaco diff editor. (microsoft#165179)
* Allows to pass in a custom diffing algorithm when instantiating the monaco diff editor. * Undo launch.json change
1 parent 8bd0521 commit 3e19ba9

19 files changed

+425
-206
lines changed

build/monaco/monaco.d.ts.recipe

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ export interface ICommandHandler {
7373
#include(vs/editor/common/core/wordHelper): IWordAtPosition
7474
#includeAll(vs/editor/common/model): IScrollEvent
7575
#include(vs/editor/common/diff/smartLinesDiffComputer): IChange, ICharChange, ILineChange
76+
#include(vs/editor/common/diff/documentDiffProvider): IDocumentDiffProvider, IDocumentDiffProviderOptions, IDocumentDiff
77+
#include(vs/editor/common/diff/linesDiffComputer): LineRangeMapping, LineRange, RangeMapping
7678
#include(vs/editor/common/core/dimension): IDimension
7779
#includeAll(vs/editor/common/editorCommon): IScrollEvent
7880
#includeAll(vs/editor/common/textModelEvents):

src/vs/editor/browser/services/editorWorkerService.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { ITextModel } from 'vs/editor/common/model';
1414
import * as languages from 'vs/editor/common/languages';
1515
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
1616
import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';
17-
import { IDiffComputationResult, IEditorWorkerService, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorker';
17+
import { DiffAlgorithmName, IDiffComputationResult, IEditorWorkerService, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorker';
1818
import { IModelService } from 'vs/editor/common/services/model';
1919
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';
2020
import { regExpFlags } from 'vs/base/common/strings';
@@ -26,7 +26,8 @@ import { UnicodeHighlighterOptions } from 'vs/editor/common/services/unicodeText
2626
import { IEditorWorkerHost } from 'vs/editor/common/services/editorWorkerHost';
2727
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
2828
import { IChange } from 'vs/editor/common/diff/smartLinesDiffComputer';
29-
import { IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';
29+
import { IDocumentDiff, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';
30+
import { LineRangeMapping, LineRange, RangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
3031

3132
/**
3233
* Stop syncing a model to the worker if it was not needed for 1 min.
@@ -95,8 +96,31 @@ export class EditorWorkerService extends Disposable implements IEditorWorkerServ
9596
return this._workerManager.withWorker().then(client => client.computedUnicodeHighlights(uri, options, range));
9697
}
9798

98-
public computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions): Promise<IDiffComputationResult | null> {
99-
return this._workerManager.withWorker().then(client => client.computeDiff(original, modified, options));
99+
public async computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise<IDocumentDiff | null> {
100+
const result = await this._workerManager.withWorker().then(client => client.computeDiff(original, modified, options, algorithm));
101+
if (!result) {
102+
return null;
103+
}
104+
// Convert from space efficient JSON data to rich objects.
105+
const diff: IDocumentDiff = {
106+
identical: result.identical,
107+
quitEarly: result.quitEarly,
108+
changes: result.changes.map(
109+
(c) =>
110+
new LineRangeMapping(
111+
new LineRange(c[0], c[1]),
112+
new LineRange(c[2], c[3]),
113+
c[4]?.map(
114+
(c) =>
115+
new RangeMapping(
116+
new Range(c[0], c[1], c[2], c[3]),
117+
new Range(c[4], c[5], c[6], c[7])
118+
)
119+
)
120+
)
121+
),
122+
};
123+
return diff;
100124
}
101125

102126
public canComputeDirtyDiff(original: URI, modified: URI): boolean {
@@ -492,9 +516,9 @@ export class EditorWorkerClient extends Disposable implements IEditorWorkerClien
492516
});
493517
}
494518

495-
public computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions): Promise<IDiffComputationResult | null> {
519+
public computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise<IDiffComputationResult | null> {
496520
return this._withSyncedResources([original, modified], /* forceLargeModels */true).then(proxy => {
497-
return proxy.computeDiff(original.toString(), modified.toString(), options);
521+
return proxy.computeDiff(original.toString(), modified.toString(), options, algorithm);
498522
});
499523
}
500524

src/vs/editor/browser/widget/diffEditorWidget.ts

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,60 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import 'vs/css!./media/diffEditor';
7-
import * as nls from 'vs/nls';
86
import * as dom from 'vs/base/browser/dom';
7+
import { createFastDomNode, FastDomNode } from 'vs/base/browser/fastDomNode';
8+
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
9+
import { ISashEvent, IVerticalSashLayoutProvider, Orientation, Sash, SashState } from 'vs/base/browser/ui/sash/sash';
910
import * as assert from 'vs/base/common/assert';
10-
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
11-
import { ISashEvent, IVerticalSashLayoutProvider, Sash, SashState, Orientation } from 'vs/base/browser/ui/sash/sash';
1211
import { RunOnceScheduler } from 'vs/base/common/async';
12+
import { Codicon } from 'vs/base/common/codicons';
1313
import { Color } from 'vs/base/common/color';
14+
import { onUnexpectedError } from 'vs/base/common/errors';
1415
import { Emitter, Event } from 'vs/base/common/event';
1516
import { Disposable } from 'vs/base/common/lifecycle';
17+
import { Constants } from 'vs/base/common/uint';
1618
import { URI } from 'vs/base/common/uri';
19+
import 'vs/css!./media/diffEditor';
1720
import { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';
18-
import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll';
21+
import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration';
22+
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
1923
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
24+
import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
2025
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
26+
import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll';
2127
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
2228
import { DiffReview } from 'vs/editor/browser/widget/diffReview';
23-
import { IDiffEditorOptions, EditorLayoutInfo, EditorOption, EditorOptions, EditorFontLigatures, stringSet as validateStringSetOption, boolean as validateBooleanOption, ValidDiffEditorBaseOptions, clampedInt } from 'vs/editor/common/config/editorOptions';
29+
import { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin';
30+
import { WorkerBasedDocumentDiffProvider } from 'vs/editor/browser/widget/workerBasedDocumentDiffProvider';
31+
import { boolean as validateBooleanOption, clampedInt, EditorFontLigatures, EditorLayoutInfo, EditorOption, EditorOptions, IDiffEditorOptions, stringSet as validateStringSetOption, ValidDiffEditorBaseOptions } from 'vs/editor/common/config/editorOptions';
32+
import { FontInfo } from 'vs/editor/common/config/fontInfo';
33+
import { IDimension } from 'vs/editor/common/core/dimension';
2434
import { IPosition, Position } from 'vs/editor/common/core/position';
2535
import { IRange, Range } from 'vs/editor/common/core/range';
2636
import { ISelection, Selection } from 'vs/editor/common/core/selection';
2737
import { StringBuilder } from 'vs/editor/common/core/stringBuilder';
38+
import { IChange, ICharChange, IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer';
2839
import * as editorCommon from 'vs/editor/common/editorCommon';
2940
import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';
3041
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
31-
import { OverviewRulerZone } from 'vs/editor/common/viewModel/overviewZoneManager';
42+
import { ILineBreaksComputer } from 'vs/editor/common/modelLineProjectionData';
43+
import { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens';
3244
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
3345
import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';
3446
import { IEditorWhitespace, InlineDecoration, InlineDecorationType, IViewModel, ViewLineRenderingData } from 'vs/editor/common/viewModel';
47+
import { OverviewRulerZone } from 'vs/editor/common/viewModel/overviewZoneManager';
48+
import * as nls from 'vs/nls';
49+
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
3550
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
51+
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
3652
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
3753
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
3854
import { INotificationService } from 'vs/platform/notification/common/notification';
39-
import { defaultInsertColor, defaultRemoveColor, diffBorder, diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, scrollbarShadow, scrollbarSliderBackground, scrollbarSliderHoverBackground, scrollbarSliderActiveBackground, diffDiagonalFill, diffInsertedLineGutter, diffRemovedLineGutter, diffInsertedLine, diffRemovedLine, diffOverviewRulerInserted, diffOverviewRulerRemoved } from 'vs/platform/theme/common/colorRegistry';
40-
import { IColorTheme, IThemeService, getThemeTypeSelector, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
41-
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
42-
import { IDiffLinesChange, InlineDiffMargin } from 'vs/editor/browser/widget/inlineDiffMargin';
43-
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
44-
import { Constants } from 'vs/base/common/uint';
45-
import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
46-
import { onUnexpectedError } from 'vs/base/common/errors';
4755
import { IEditorProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
48-
import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';
49-
import { Codicon } from 'vs/base/common/codicons';
50-
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
51-
import { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens';
52-
import { FontInfo } from 'vs/editor/common/config/fontInfo';
56+
import { defaultInsertColor, defaultRemoveColor, diffBorder, diffDiagonalFill, diffInserted, diffInsertedLine, diffInsertedLineGutter, diffInsertedOutline, diffOverviewRulerInserted, diffOverviewRulerRemoved, diffRemoved, diffRemovedLine, diffRemovedLineGutter, diffRemovedOutline, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry';
5357
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
54-
import { ILineBreaksComputer } from 'vs/editor/common/modelLineProjectionData';
55-
import { IChange, ICharChange, IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer';
56-
import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration';
57-
import { IDimension } from 'vs/editor/common/core/dimension';
5858
import { isHighContrast } from 'vs/platform/theme/common/theme';
59-
import { IDocumentDiffProvider } from 'vs/editor/common/diff/documentDiffProvider';
60-
import { WorkerBasedDocumentDiffProvider } from 'vs/editor/browser/widget/workerBasedDocumentDiffProvider';
59+
import { getThemeTypeSelector, IColorTheme, IThemeService, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
6160

6261
export interface IDiffCodeEditorWidgetOptions {
6362
originalEditor?: ICodeEditorWidgetOptions;
@@ -227,7 +226,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
227226

228227
private readonly _updateDecorationsRunner: RunOnceScheduler;
229228

230-
private readonly _documentDiffProvider: IDocumentDiffProvider;
229+
private readonly _documentDiffProvider: WorkerBasedDocumentDiffProvider;
231230
private readonly _contextKeyService: IContextKeyService;
232231
private readonly _instantiationService: IInstantiationService;
233232
private readonly _codeEditorService: ICodeEditorService;
@@ -251,7 +250,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
251250
) {
252251
super();
253252

254-
this._documentDiffProvider = instantiationService.createInstance(WorkerBasedDocumentDiffProvider);
253+
this._documentDiffProvider = this._register(instantiationService.createInstance(WorkerBasedDocumentDiffProvider, options));
254+
this._register(this._documentDiffProvider.onDidChange(e => this._beginUpdateDecorationsSoon()));
255+
255256
this._codeEditorService = codeEditorService;
256257
this._contextKeyService = this._register(contextKeyService.createScoped(domElement));
257258
this._instantiationService = instantiationService.createChild(new ServiceCollection([IContextKeyService, this._contextKeyService]));
@@ -762,7 +763,8 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
762763
this._options = newOptions;
763764

764765
const beginUpdateDecorations = (changed.ignoreTrimWhitespace || changed.renderIndicators || changed.renderMarginRevertIcon);
765-
const beginUpdateDecorationsSoon = (this._isVisible && (changed.maxComputationTime || changed.maxFileSize || changed.diffAlgorithm));
766+
const beginUpdateDecorationsSoon = (this._isVisible && (changed.maxComputationTime || changed.maxFileSize));
767+
this._documentDiffProvider.setOptions(newOptions);
766768

767769
if (beginUpdateDecorations) {
768770
this._beginUpdateDecorations();
@@ -1092,7 +1094,11 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
10921094
}
10931095

10941096
private _beginUpdateDecorations(): void {
1095-
this._beginUpdateDecorationsTimeout = -1;
1097+
if (this._beginUpdateDecorationsTimeout !== -1) {
1098+
// Cancel any pending requests in case this method is called directly
1099+
window.clearTimeout(this._beginUpdateDecorationsTimeout);
1100+
this._beginUpdateDecorationsTimeout = -1;
1101+
}
10961102
const currentOriginalModel = this._originalEditor.getModel();
10971103
const currentModifiedModel = this._modifiedEditor.getModel();
10981104
if (!currentOriginalModel || !currentModifiedModel) {
@@ -1126,8 +1132,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
11261132
this._setState(editorBrowser.DiffEditorState.ComputingDiff);
11271133
this._documentDiffProvider.computeDiff(currentOriginalModel, currentModifiedModel, {
11281134
ignoreTrimWhitespace: this._options.ignoreTrimWhitespace,
1129-
maxComputationTime: this._options.maxComputationTime,
1130-
diffAlgorithm: this._options.diffAlgorithm,
1135+
maxComputationTimeMs: this._options.maxComputationTime,
11311136
}).then(result => {
11321137
if (currentToken === this._diffComputationToken
11331138
&& currentOriginalModel === this._originalEditor.getModel()

src/vs/editor/browser/widget/workerBasedDocumentDiffProvider.ts

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,63 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { LineRange, LineRangeMapping, RangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
7-
import { Range } from 'vs/editor/common/core/range';
6+
import { Emitter, Event } from 'vs/base/common/event';
7+
import { IDisposable } from 'vs/base/common/lifecycle';
88
import { IDocumentDiff, IDocumentDiffProvider, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';
9-
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
109
import { ITextModel } from 'vs/editor/common/model';
10+
import { DiffAlgorithmName, IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
11+
12+
export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, IDisposable {
13+
private onDidChangeEventEmitter = new Emitter<void>();
14+
public readonly onDidChange: Event<void> = this.onDidChangeEventEmitter.event;
15+
16+
private diffAlgorithm: DiffAlgorithmName | IDocumentDiffProvider = 'smart';
17+
private diffAlgorithmOnDidChangeSubscription: IDisposable | undefined = undefined;
1118

12-
export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider {
1319
constructor(
20+
options: IWorkerBasedDocumentDiffProviderOptions,
1421
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,
1522
) {
23+
this.setOptions(options);
24+
}
25+
26+
public dispose(): void {
27+
this.diffAlgorithmOnDidChangeSubscription?.dispose();
1628
}
1729

1830
async computeDiff(original: ITextModel, modified: ITextModel, options: IDocumentDiffProviderOptions): Promise<IDocumentDiff> {
19-
const result = await this.editorWorkerService.computeDiff(original.uri, modified.uri, options);
31+
if (typeof this.diffAlgorithm !== 'string') {
32+
return this.diffAlgorithm.computeDiff(original, modified, options);
33+
}
34+
35+
const result = await this.editorWorkerService.computeDiff(original.uri, modified.uri, options, this.diffAlgorithm);
2036
if (!result) {
2137
throw new Error('no diff result available');
2238
}
2339

24-
// Convert from space efficient JSON data to rich objects.
25-
const diff: IDocumentDiff = {
26-
identical: result.identical,
27-
quitEarly: result.quitEarly,
28-
changes: result.changes.map(
29-
(c) =>
30-
new LineRangeMapping(
31-
new LineRange(c[0], c[1]),
32-
new LineRange(c[2], c[3]),
33-
c[4]?.map(
34-
(c) =>
35-
new RangeMapping(
36-
new Range(c[0], c[1], c[2], c[3]),
37-
new Range(c[4], c[5], c[6], c[7])
38-
)
39-
)
40-
)
41-
),
42-
};
43-
return diff;
40+
return result;
4441
}
42+
43+
public setOptions(newOptions: IWorkerBasedDocumentDiffProviderOptions): void {
44+
let didChange = false;
45+
if (newOptions.diffAlgorithm) {
46+
if (this.diffAlgorithm !== newOptions.diffAlgorithm) {
47+
this.diffAlgorithmOnDidChangeSubscription?.dispose();
48+
this.diffAlgorithmOnDidChangeSubscription = undefined;
49+
50+
this.diffAlgorithm = newOptions.diffAlgorithm;
51+
if (typeof newOptions.diffAlgorithm !== 'string') {
52+
this.diffAlgorithmOnDidChangeSubscription = newOptions.diffAlgorithm.onDidChange(() => this.onDidChangeEventEmitter.fire());
53+
}
54+
didChange = true;
55+
}
56+
}
57+
if (didChange) {
58+
this.onDidChangeEventEmitter.fire();
59+
}
60+
}
61+
}
62+
63+
interface IWorkerBasedDocumentDiffProviderOptions {
64+
readonly diffAlgorithm?: 'smart' | 'experimental' | IDocumentDiffProvider;
4565
}

src/vs/editor/common/config/editorOptions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
1515
import * as arrays from 'vs/base/common/arrays';
1616
import * as objects from 'vs/base/common/objects';
1717
import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/core/textModelDefaults';
18+
import { IDocumentDiffProvider } from 'vs/editor/common/diff/documentDiffProvider';
1819

1920
//#region typed options
2021

@@ -739,7 +740,7 @@ export interface IDiffEditorBaseOptions {
739740
/**
740741
* Diff Algorithm
741742
*/
742-
diffAlgorithm?: 'smart' | 'experimental';
743+
diffAlgorithm?: 'smart' | 'experimental' | IDocumentDiffProvider;
743744
}
744745

745746
/**

0 commit comments

Comments
 (0)