Skip to content

Commit 05a2f13

Browse files
committed
Refactors 3wm code.
1 parent bf787b0 commit 05a2f13

File tree

5 files changed

+385
-388
lines changed

5 files changed

+385
-388
lines changed

src/vs/workbench/contrib/mergeEditor/browser/diffComputer.ts

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

6+
import { BugIndicatingError } from 'vs/base/common/errors';
67
import { Range } from 'vs/editor/common/core/range';
78
import { ICharChange, IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/diffComputer';
89
import { ITextModel } from 'vs/editor/common/model';
910
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
10-
import { LineRange, LineRangeMapping, RangeMapping } from 'vs/workbench/contrib/mergeEditor/browser/model';
11+
import { LineRange, DetailedLineRangeMapping, RangeMapping } from 'vs/workbench/contrib/mergeEditor/browser/model';
1112

1213
export interface IDiffComputer {
1314
computeDiff(textModel1: ITextModel, textModel2: ITextModel): Promise<IDiffComputerResult>;
1415
}
1516

1617
export interface IDiffComputerResult {
17-
diffs: LineRangeMapping[] | null;
18+
diffs: DetailedLineRangeMapping[] | null;
1819
}
1920

2021
export class EditorWorkerServiceDiffComputer implements IDiffComputer {
@@ -28,12 +29,12 @@ export class EditorWorkerServiceDiffComputer implements IDiffComputer {
2829
return { diffs: EditorWorkerServiceDiffComputer.fromDiffComputationResult(diffs, textModel1, textModel2) };
2930
}
3031

31-
public static fromDiffComputationResult(result: IDiffComputationResult, textModel1: ITextModel, textModel2: ITextModel): LineRangeMapping[] {
32+
public static fromDiffComputationResult(result: IDiffComputationResult, textModel1: ITextModel, textModel2: ITextModel): DetailedLineRangeMapping[] {
3233
return result.changes.map((c) => fromLineChange(c, textModel1, textModel2));
3334
}
3435
}
3536

36-
function fromLineChange(lineChange: ILineChange, originalTextModel: ITextModel, modifiedTextModel: ITextModel): LineRangeMapping {
37+
function fromLineChange(lineChange: ILineChange, originalTextModel: ITextModel, modifiedTextModel: ITextModel): DetailedLineRangeMapping {
3738
let originalRange: LineRange;
3839
if (lineChange.originalEndLineNumber === 0) {
3940
// Insertion
@@ -50,16 +51,16 @@ function fromLineChange(lineChange: ILineChange, originalTextModel: ITextModel,
5051
modifiedRange = new LineRange(lineChange.modifiedStartLineNumber, lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1);
5152
}
5253

53-
let innerDiffs = lineChange.charChanges?.map(c => rangeMappingFromCharChange(c));
54+
let innerDiffs = lineChange.charChanges?.map(c => rangeMappingFromCharChange(c, originalTextModel, modifiedTextModel));
5455
if (!innerDiffs) {
5556
innerDiffs = [rangeMappingFromLineRanges(originalRange, modifiedRange)];
5657
}
5758

58-
return new LineRangeMapping(
59-
originalTextModel,
59+
return new DetailedLineRangeMapping(
6060
originalRange,
61-
modifiedTextModel,
61+
originalTextModel,
6262
modifiedRange,
63+
modifiedTextModel,
6364
innerDiffs
6465
);
6566
}
@@ -81,9 +82,80 @@ function rangeMappingFromLineRanges(originalRange: LineRange, modifiedRange: Lin
8182
);
8283
}
8384

84-
function rangeMappingFromCharChange(charChange: ICharChange): RangeMapping {
85-
return new RangeMapping(
85+
function rangeMappingFromCharChange(charChange: ICharChange, inputTextModel: ITextModel, modifiedTextModel: ITextModel): RangeMapping {
86+
return normalizeRangeMapping(new RangeMapping(
8687
new Range(charChange.originalStartLineNumber, charChange.originalStartColumn, charChange.originalEndLineNumber, charChange.originalEndColumn),
8788
new Range(charChange.modifiedStartLineNumber, charChange.modifiedStartColumn, charChange.modifiedEndLineNumber, charChange.modifiedEndColumn)
89+
), inputTextModel, modifiedTextModel);
90+
}
91+
92+
function normalizeRangeMapping(rangeMapping: RangeMapping, inputTextModel: ITextModel, outputTextModel: ITextModel): RangeMapping {
93+
const inputRangeEmpty = rangeMapping.inputRange.isEmpty();
94+
const outputRangeEmpty = rangeMapping.outputRange.isEmpty();
95+
96+
if (inputRangeEmpty && outputRangeEmpty) {
97+
throw new BugIndicatingError(); // This case makes no sense, but it is an edge case we need to rule out
98+
}
99+
100+
const originalStartsAtEndOfLine = isAtEndOfLine(rangeMapping.inputRange.startLineNumber, rangeMapping.inputRange.startColumn, inputTextModel);
101+
const modifiedStartsAtEndOfLine = isAtEndOfLine(rangeMapping.outputRange.startLineNumber, rangeMapping.outputRange.startColumn, outputTextModel);
102+
103+
if (!inputRangeEmpty && !outputRangeEmpty && originalStartsAtEndOfLine && modifiedStartsAtEndOfLine) {
104+
// a b c [\n] x y z \n
105+
// d e f [\n a] \n
106+
// ->
107+
// a b c \n [] x y z \n
108+
// d e f \n [a] \n
109+
110+
return new RangeMapping(
111+
rangeMapping.inputRange.setStartPosition(rangeMapping.inputRange.startLineNumber + 1, 1),
112+
113+
rangeMapping.outputRange.setStartPosition(rangeMapping.outputRange.startLineNumber + 1, 1),
114+
);
115+
}
116+
117+
if (
118+
modifiedStartsAtEndOfLine &&
119+
originalStartsAtEndOfLine &&
120+
((inputRangeEmpty && rangeEndsAtEndOfLine(rangeMapping.outputRange, outputTextModel)) ||
121+
(outputRangeEmpty && rangeEndsAtEndOfLine(rangeMapping.inputRange, inputTextModel)))
122+
) {
123+
// o: a b c [] \n x y z \n
124+
// m: d e f [\n a] \n
125+
// ->
126+
// o: a b c \n [] x y z \n
127+
// m: d e f \n [a \n]
128+
129+
// or
130+
131+
// a b c [\n x y z] \n
132+
// d e f [] \n a \n
133+
// ->
134+
// a b c \n [x y z \n]
135+
// d e f \n [] a \n
136+
137+
return new RangeMapping(
138+
moveRange(rangeMapping.inputRange),
139+
moveRange(rangeMapping.outputRange)
140+
);
141+
}
142+
143+
return rangeMapping;
144+
}
145+
146+
function isAtEndOfLine(lineNumber: number, column: number, model: ITextModel): boolean {
147+
return column >= model.getLineMaxColumn(lineNumber);
148+
}
149+
150+
function rangeEndsAtEndOfLine(range: Range, model: ITextModel,): boolean {
151+
return isAtEndOfLine(range.endLineNumber, range.endColumn, model);
152+
}
153+
154+
function moveRange(range: Range): Range {
155+
return new Range(
156+
range.startLineNumber + 1,
157+
1,
158+
range.endLineNumber + 1,
159+
1,
88160
);
89161
}

src/vs/workbench/contrib/mergeEditor/browser/mergeEditor.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ import { applyTextEditorOptions } from 'vs/workbench/common/editor/editorOptions
4747
import { autorun, autorunWithStore, derivedObservable, IObservable, ITransaction, keepAlive, ObservableValue, transaction } from 'vs/workbench/contrib/audioCues/browser/observable';
4848
import { MergeEditorInput } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorInput';
4949
import { MergeEditorModel } from 'vs/workbench/contrib/mergeEditor/browser/mergeEditorModel';
50-
import { DocumentMapping, LineRange, SimpleLineRangeMapping, ToggleState } from 'vs/workbench/contrib/mergeEditor/browser/model';
50+
import { DocumentMapping, LineRange, LineRangeMapping, InputState } from 'vs/workbench/contrib/mergeEditor/browser/model';
5151
import { applyObservableDecorations, join, n, ReentrancyBarrier, setStyle } from 'vs/workbench/contrib/mergeEditor/browser/utils';
5252
import { settingsSashBorder } from 'vs/workbench/contrib/preferences/common/settingsEditorColorRegistry';
5353
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
@@ -109,12 +109,12 @@ export class MergeEditor extends AbstractTextEditor<any> {
109109
return undefined;
110110
}
111111
const resultDiffs = model.resultDiffs.read(reader);
112-
const modifiedBaseRanges = DocumentMapping.fromDiffs(model.input1LinesDiffs.read(reader), resultDiffs, model.input1.getLineCount());
112+
const modifiedBaseRanges = DocumentMapping.betweenOutputs(model.input1LinesDiffs.read(reader), resultDiffs, model.input1.getLineCount());
113113

114114
return new DocumentMapping(
115115
modifiedBaseRanges.lineRangeMappings.map((m) =>
116116
m.inputRange.isEmpty || m.outputRange.isEmpty
117-
? new SimpleLineRangeMapping(
117+
? new LineRangeMapping(
118118
m.inputRange.deltaStart(-1),
119119
m.outputRange.deltaStart(-1)
120120
)
@@ -129,12 +129,12 @@ export class MergeEditor extends AbstractTextEditor<any> {
129129
return undefined;
130130
}
131131
const resultDiffs = model.resultDiffs.read(reader);
132-
const modifiedBaseRanges = DocumentMapping.fromDiffs(model.input2LinesDiffs.read(reader), resultDiffs, model.input2.getLineCount());
132+
const modifiedBaseRanges = DocumentMapping.betweenOutputs(model.input2LinesDiffs.read(reader), resultDiffs, model.input2.getLineCount());
133133

134134
return new DocumentMapping(
135135
modifiedBaseRanges.lineRangeMappings.map((m) =>
136136
m.inputRange.isEmpty || m.outputRange.isEmpty
137-
? new SimpleLineRangeMapping(
137+
? new LineRangeMapping(
138138
m.inputRange.deltaStart(-1),
139139
m.outputRange.deltaStart(-1)
140140
)
@@ -559,8 +559,8 @@ class InputCodeEditorView extends CodeEditorView {
559559

560560
const inputDiffs = m.getInputDiffs(this.inputNumber);
561561
for (const diff of inputDiffs) {
562-
if (diff.innerRangeMappings) {
563-
for (const d of diff.innerRangeMappings) {
562+
if (diff.rangeMappings) {
563+
for (const d of diff.rangeMappings) {
564564
result.push({
565565
range: d.outputRange,
566566
options: {
@@ -624,7 +624,7 @@ class InputCodeEditorView extends CodeEditorView {
624624

625625
interface ModifiedBaseRangeGutterItemInfo extends IGutterItemInfo {
626626
enabled: IObservable<boolean>;
627-
toggleState: IObservable<ToggleState>;
627+
toggleState: IObservable<InputState>;
628628
setState(value: boolean, tx: ITransaction): void;
629629
}
630630

@@ -645,11 +645,11 @@ class MergeConflictGutterItemView extends Disposable implements IGutterItemView<
645645
autorun((reader) => {
646646
const item = this.item.read(reader)!;
647647
const value = item.toggleState.read(reader);
648-
const iconMap: Record<ToggleState, { icon: Codicon | undefined; checked: boolean }> = {
649-
[ToggleState.unset]: { icon: undefined, checked: false },
650-
[ToggleState.conflicting]: { icon: Codicon.circleFilled, checked: false },
651-
[ToggleState.first]: { icon: Codicon.check, checked: true },
652-
[ToggleState.second]: { icon: Codicon.checkAll, checked: true },
648+
const iconMap: Record<InputState, { icon: Codicon | undefined; checked: boolean }> = {
649+
[InputState.excluded]: { icon: undefined, checked: false },
650+
[InputState.conflicting]: { icon: Codicon.circleFilled, checked: false },
651+
[InputState.first]: { icon: Codicon.check, checked: true },
652+
[InputState.second]: { icon: Codicon.checkAll, checked: true },
653653
};
654654
checkBox.setIcon(iconMap[value].icon);
655655
checkBox.checked = iconMap[value].checked;

src/vs/workbench/contrib/mergeEditor/browser/mergeEditorModel.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
1414
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
1515
import { autorunHandleChanges, derivedObservable, derivedObservableWithCache, IObservable, ITransaction, keepAlive, ObservableValue, transaction, waitForState } from 'vs/workbench/contrib/audioCues/browser/observable';
1616
import { EditorWorkerServiceDiffComputer } from 'vs/workbench/contrib/mergeEditor/browser/diffComputer';
17-
import { LineRangeMapping, LineRangeEdit, LineRange, ModifiedBaseRange, ModifiedBaseRangeState, RangeEdit } from 'vs/workbench/contrib/mergeEditor/browser/model';
17+
import { LineRangeEdit, LineRange, ModifiedBaseRange, ModifiedBaseRangeState, RangeEdit, DetailedLineRangeMapping } from 'vs/workbench/contrib/mergeEditor/browser/model';
1818
import { TextModelDiffChangeReason, TextModelDiffs, TextModelDiffState } from 'vs/workbench/contrib/mergeEditor/browser/textModelDiffs';
1919
import { concatArrays, leftJoin, elementAtOrUndefined } from 'vs/workbench/contrib/mergeEditor/browser/utils';
2020

@@ -58,7 +58,7 @@ export class MergeEditorModel extends EditorModel {
5858
const input1Diffs = this.input1TextModelDiffs.diffs.read(reader);
5959
const input2Diffs = this.input2TextModelDiffs.diffs.read(reader);
6060

61-
return ModifiedBaseRange.fromDiffs(this.base, this.input1, input1Diffs, this.input2, input2Diffs);
61+
return ModifiedBaseRange.fromDiffs(input1Diffs, input2Diffs, this.base, this.input1, this.input2);
6262
});
6363

6464
public readonly input1LinesDiffs = this.input1TextModelDiffs.diffs;
@@ -114,7 +114,7 @@ export class MergeEditorModel extends EditorModel {
114114
});
115115
}
116116

117-
private recomputeState(resultDiffs: LineRangeMapping[], stores: Map<ModifiedBaseRange, ObservableValue<ModifiedBaseRangeState>>): void {
117+
private recomputeState(resultDiffs: DetailedLineRangeMapping[], stores: Map<ModifiedBaseRange, ObservableValue<ModifiedBaseRangeState>>): void {
118118
transaction(tx => {
119119
const baseRangeWithStoreAndTouchingDiffs = leftJoin(
120120
stores,
@@ -199,13 +199,13 @@ export class MergeEditorModel extends EditorModel {
199199
}
200200
}
201201

202-
private computeState(baseRange: ModifiedBaseRange, conflictingDiffs: LineRangeMapping[]): ModifiedBaseRangeState {
202+
private computeState(baseRange: ModifiedBaseRange, conflictingDiffs: DetailedLineRangeMapping[]): ModifiedBaseRangeState {
203203
if (conflictingDiffs.length === 0) {
204204
return ModifiedBaseRangeState.default;
205205
}
206206
const conflictingEdits = conflictingDiffs.map((d) => d.getLineEdit());
207207

208-
function editsAgreeWithDiffs(diffs: readonly LineRangeMapping[]): boolean {
208+
function editsAgreeWithDiffs(diffs: readonly DetailedLineRangeMapping[]): boolean {
209209
return equals(
210210
conflictingEdits,
211211
diffs.map((d) => d.getLineEdit()),
@@ -279,10 +279,10 @@ function getEditForBase(baseRange: ModifiedBaseRange, state: ModifiedBaseRangeSt
279279
function combineInputs(baseRange: ModifiedBaseRange, firstInput: 1 | 2): LineRangeEdit | undefined {
280280
const combinedDiffs = concatArrays(
281281
baseRange.input1Diffs.flatMap((diffs) =>
282-
diffs.innerRangeMappings.map((diff) => ({ diff, input: 1 as const }))
282+
diffs.rangeMappings.map((diff) => ({ diff, input: 1 as const }))
283283
),
284284
baseRange.input2Diffs.flatMap((diffs) =>
285-
diffs.innerRangeMappings.map((diff) => ({ diff, input: 2 as const }))
285+
diffs.rangeMappings.map((diff) => ({ diff, input: 2 as const }))
286286
)
287287
).sort(
288288
tieBreakComparators(

0 commit comments

Comments
 (0)