Skip to content

Commit 89ec834

Browse files
authored
Diff Editor Rewrite Progress (microsoft#184857)
1 parent ef6abe4 commit 89ec834

File tree

5 files changed

+113
-36
lines changed

5 files changed

+113
-36
lines changed

src/vs/base/common/observableImpl/derived.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { BugIndicatingError } from 'vs/base/common/errors';
7+
import { DisposableStore } from 'vs/base/common/lifecycle';
78
import { IReader, IObservable, BaseObservable, IObserver, _setDerived, IChangeContext } from 'vs/base/common/observableImpl/base';
89
import { getLogger } from 'vs/base/common/observableImpl/logging';
910

1011
export function derived<T>(debugName: string | (() => string), computeFn: (reader: IReader) => T): IObservable<T> {
11-
return new Derived(debugName, computeFn, undefined, undefined);
12+
return new Derived(debugName, computeFn, undefined, undefined, undefined);
1213
}
1314

1415
export function derivedHandleChanges<T, TChangeSummary>(
@@ -18,7 +19,15 @@ export function derivedHandleChanges<T, TChangeSummary>(
1819
handleChange: (context: IChangeContext, changeSummary: TChangeSummary) => boolean;
1920
},
2021
computeFn: (reader: IReader, changeSummary: TChangeSummary) => T): IObservable<T> {
21-
return new Derived(debugName, computeFn, options.createEmptyChangeSummary, options.handleChange);
22+
return new Derived(debugName, computeFn, options.createEmptyChangeSummary, options.handleChange, undefined);
23+
}
24+
25+
export function derivedWithStore<T>(name: string, computeFn: (reader: IReader, store: DisposableStore) => T): IObservable<T> {
26+
const store = new DisposableStore();
27+
return new Derived(name, r => {
28+
store.clear();
29+
return computeFn(r, store);
30+
}, undefined, undefined, () => store.dispose());
2231
}
2332

2433
_setDerived(derived);
@@ -62,6 +71,7 @@ export class Derived<T, TChangeSummary = any> extends BaseObservable<T, void> im
6271
private readonly computeFn: (reader: IReader, changeSummary: TChangeSummary) => T,
6372
private readonly createChangeSummary: (() => TChangeSummary) | undefined,
6473
private readonly _handleChange: ((context: IChangeContext, summary: TChangeSummary) => boolean) | undefined,
74+
private readonly _handleLastObserverRemoved: (() => void) | undefined = undefined
6575
) {
6676
super();
6777
this.changeSummary = this.createChangeSummary?.();
@@ -79,6 +89,8 @@ export class Derived<T, TChangeSummary = any> extends BaseObservable<T, void> im
7989
d.removeObserver(this);
8090
}
8191
this.dependencies.clear();
92+
93+
this._handleLastObserverRemoved?.();
8294
}
8395

8496
public override get(): T {

src/vs/base/common/observableImpl/utils.ts

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

6+
import { Event } from 'vs/base/common/event';
67
import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
78
import { autorun } from 'vs/base/common/observableImpl/autorun';
8-
import { IObservable, BaseObservable, transaction, IReader, ITransaction, ConvenientObservable, IObserver, observableValue, getFunctionName } from 'vs/base/common/observableImpl/base';
9+
import { BaseObservable, ConvenientObservable, IObservable, IObserver, IReader, ITransaction, getFunctionName, observableValue, transaction } from 'vs/base/common/observableImpl/base';
910
import { derived } from 'vs/base/common/observableImpl/derived';
10-
import { Event } from 'vs/base/common/event';
1111
import { getLogger } from 'vs/base/common/observableImpl/logging';
1212

1313
export function constObservable<T>(value: T): IObservable<T> {

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

Lines changed: 91 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { findLast } from 'vs/base/common/arrays';
88
import { onUnexpectedError } from 'vs/base/common/errors';
99
import { Emitter, Event } from 'vs/base/common/event';
1010
import { IObservable, ISettableObservable, autorun, derived, keepAlive, observableValue, waitForState } from 'vs/base/common/observable';
11-
import { disposableObservableValue, transaction } from 'vs/base/common/observableImpl/base';
11+
import { disposableObservableValue } from 'vs/base/common/observableImpl/base';
12+
import { derivedWithStore } from 'vs/base/common/observableImpl/derived';
1213
import { isDefined } from 'vs/base/common/types';
1314
import { Constants } from 'vs/base/common/uint';
1415
import 'vs/css!./style';
@@ -80,6 +81,7 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
8081
private readonly _rootSizeObserver: ObservableElementSizeObserver;
8182
private readonly _options: ISettableObservable<ValidDiffEditorBaseOptions>;
8283
private readonly _sash: IObservable<DiffEditorSash | undefined>;
84+
private readonly _boundarySashes = observableValue<IBoundarySashes | undefined>('boundarySashes', undefined);
8385
private readonly _renderOverviewRuler: IObservable<boolean>;
8486

8587
constructor(
@@ -114,30 +116,30 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
114116
this._register(applyObservableDecorations(this._modifiedEditor, this._decorations.map(d => d?.modifiedDecorations || [])));
115117

116118
this._renderOverviewRuler = this._options.map(o => o.renderOverviewRuler);
117-
const sash = this._register(disposableObservableValue<DiffEditorSash | undefined>('sash', undefined));
118-
this._sash = sash;
119-
120-
this._register(autorun('update sash', reader => {
119+
this._sash = derivedWithStore('sash', (reader, store) => {
121120
const showSash = this._options.read(reader).renderSideBySide;
122-
123121
this.elements.root.classList.toggle('side-by-side', showSash);
124-
125-
transaction(tx => {
126-
sash.set(undefined, tx);
127-
if (showSash) {
128-
sash.set(new DiffEditorSash(
129-
this._options.map(o => o.enableSplitViewResizing),
130-
this._options.map(o => o.splitViewDefaultRatio),
131-
this.elements.root,
132-
{
133-
height: this._rootSizeObserver.height,
134-
width: this._rootSizeObserver.width.map((w, reader) => w - (this._renderOverviewRuler.read(reader) ? OverviewRulerPart.ENTIRE_DIFF_OVERVIEW_WIDTH : 0)),
135-
}
136-
), tx);
122+
if (!showSash) {
123+
return undefined;
124+
}
125+
const result = store.add(new DiffEditorSash(
126+
this._options.map(o => o.enableSplitViewResizing),
127+
this._options.map(o => o.splitViewDefaultRatio),
128+
this.elements.root,
129+
{
130+
height: this._rootSizeObserver.height,
131+
width: this._rootSizeObserver.width.map((w, reader) => w - (this._renderOverviewRuler.read(reader) ? OverviewRulerPart.ENTIRE_DIFF_OVERVIEW_WIDTH : 0)),
137132
}
138-
});
139-
}));
140-
133+
));
134+
store.add(autorun('setBoundarySashes', reader => {
135+
const boundarySashes = this._boundarySashes.read(reader);
136+
if (boundarySashes) {
137+
result.setBoundarySashes(boundarySashes);
138+
}
139+
}));
140+
return result;
141+
});
142+
this._register(keepAlive(this._sash, true));
141143

142144
this._register(new UnchangedRangesFeature(this._originalEditor, this._modifiedEditor, this._diffModel));
143145
this._register(this._instantiationService.createInstance(ViewZoneManager, this._originalEditor, this._modifiedEditor, this._diffModel, this._options.map(o => o.renderSideBySide)));
@@ -490,13 +492,11 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
490492
getModifiedEditor(): ICodeEditor { return this._modifiedEditor; }
491493

492494
setBoundarySashes(sashes: IBoundarySashes): void {
493-
// TODO
494-
this._sash.get()?.setBoundarySashes(sashes);
495+
this._boundarySashes.set(sashes, undefined);
495496
}
496497

497-
readonly onDidUpdateDiff: Event<void> = e => {
498-
return { dispose: () => { } };
499-
};
498+
private readonly _diffValue = this._diffModel.map((m, r) => m?.diff.read(r));
499+
readonly onDidUpdateDiff: Event<void> = Event.fromObservableLight(this._diffValue);
500500

501501
get ignoreTrimWhitespace(): boolean {
502502
return this._options.get().ignoreTrimWhitespace;
@@ -510,13 +510,73 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
510510
return this._options.get().renderSideBySide;
511511
}
512512

513+
/**
514+
* @deprecated Use `this.getDiffComputationResult().changes2` instead.
515+
*/
513516
getLineChanges(): ILineChange[] | null {
514-
return null;
515-
//throw new Error('Method not implemented.');
517+
const diffState = this._diffModel.get()?.diff.get();
518+
if (!diffState) {
519+
return null;
520+
}
521+
return diffState.mappings.map(x => {
522+
const m = x.lineRangeMapping;
523+
let originalStartLineNumber: number;
524+
let originalEndLineNumber: number;
525+
let modifiedStartLineNumber: number;
526+
let modifiedEndLineNumber: number;
527+
let innerChanges = m.innerChanges;
528+
529+
if (m.originalRange.isEmpty) {
530+
// Insertion
531+
originalStartLineNumber = m.originalRange.startLineNumber - 1;
532+
originalEndLineNumber = 0;
533+
innerChanges = undefined;
534+
} else {
535+
originalStartLineNumber = m.originalRange.startLineNumber;
536+
originalEndLineNumber = m.originalRange.endLineNumberExclusive - 1;
537+
}
538+
539+
if (m.modifiedRange.isEmpty) {
540+
// Deletion
541+
modifiedStartLineNumber = m.modifiedRange.startLineNumber - 1;
542+
modifiedEndLineNumber = 0;
543+
innerChanges = undefined;
544+
} else {
545+
modifiedStartLineNumber = m.modifiedRange.startLineNumber;
546+
modifiedEndLineNumber = m.modifiedRange.endLineNumberExclusive - 1;
547+
}
548+
549+
return {
550+
originalStartLineNumber,
551+
originalEndLineNumber,
552+
modifiedStartLineNumber,
553+
modifiedEndLineNumber,
554+
charChanges: innerChanges?.map(m => ({
555+
originalStartLineNumber: m.originalRange.startLineNumber,
556+
originalStartColumn: m.originalRange.startColumn,
557+
originalEndLineNumber: m.originalRange.endLineNumber,
558+
originalEndColumn: m.originalRange.endColumn,
559+
modifiedStartLineNumber: m.modifiedRange.startLineNumber,
560+
modifiedStartColumn: m.modifiedRange.startColumn,
561+
modifiedEndLineNumber: m.modifiedRange.endLineNumber,
562+
modifiedEndColumn: m.modifiedRange.endColumn,
563+
}))
564+
};
565+
});
516566
}
567+
517568
getDiffComputationResult(): IDiffComputationResult | null {
518-
return null;
519-
//throw new Error('Method not implemented.');
569+
const diffState = this._diffModel.get()?.diff.get();
570+
if (!diffState) {
571+
return null;
572+
}
573+
574+
return {
575+
changes: this.getLineChanges()!,
576+
changes2: diffState.mappings.map(m => m.lineRangeMapping),
577+
identical: diffState.identical,
578+
quitEarly: diffState.quitEarly,
579+
};
520580
}
521581

522582
private _goTo(diff: DiffMapping): void {

src/vs/editor/browser/widget/diffEditorWidget2/diffModel.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,17 @@ export class DiffState {
177177
public static fromDiffResult(result: IDocumentDiff): DiffState {
178178
return new DiffState(
179179
result.changes.map(c => new DiffMapping(c)),
180-
result.moves || []
180+
result.moves || [],
181+
result.identical,
182+
result.quitEarly,
181183
);
182184
}
183185

184186
constructor(
185187
public readonly mappings: readonly DiffMapping[],
186188
public readonly movedTexts: readonly MovedText[],
189+
public readonly identical: boolean,
190+
public readonly quitEarly: boolean,
187191
) { }
188192
}
189193

src/vs/editor/common/diff/smartLinesDiffComputer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export interface IDiffComputationResult {
8585

8686
/**
8787
* The changes as (legacy) line change array.
88+
* @deprecated Use `changes2` instead.
8889
*/
8990
changes: ILineChange[];
9091

0 commit comments

Comments
 (0)