Skip to content

Commit 45d2dd8

Browse files
authored
Improves merge marker presentation in merge editor. (microsoft#158738)
1 parent e009a3b commit 45d2dd8

File tree

5 files changed

+112
-31
lines changed

5 files changed

+112
-31
lines changed

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

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,101 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { h } from 'vs/base/browser/dom';
7-
import { Disposable } from 'vs/base/common/lifecycle';
7+
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
8+
import { autorun, IObservable } from 'vs/base/common/observable';
89
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
910
import { ITextModel } from 'vs/editor/common/model';
1011
import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';
12+
import { MergeEditorViewModel } from 'vs/workbench/contrib/mergeEditor/browser/view/viewModel';
13+
import * as nls from 'vs/nls';
1114

1215
export const conflictMarkers = {
1316
start: '<<<<<<<',
1417
end: '>>>>>>>',
1518
};
1619

1720
export class MergeMarkersController extends Disposable {
18-
public static ID = 'editor.contrib.mergeConflictsController';
19-
2021
private readonly viewZoneIds: string[] = [];
22+
private readonly disposableStore = new DisposableStore();
2123

2224
public constructor(
23-
public readonly editor: ICodeEditor
25+
public readonly editor: ICodeEditor,
26+
public readonly mergeEditorViewModel: IObservable<MergeEditorViewModel | undefined>,
2427
) {
2528
super();
2629

27-
editor.onDidChangeModelContent(e => {
28-
this.updateDecorations(editor);
29-
});
30+
this._register(editor.onDidChangeModelContent(e => {
31+
this.updateDecorations();
32+
}));
3033

31-
editor.onDidChangeModel(e => {
32-
this.updateDecorations(editor);
33-
});
34+
this._register(editor.onDidChangeModel(e => {
35+
this.updateDecorations();
36+
}));
3437

35-
this.updateDecorations(editor);
38+
this.updateDecorations();
3639
}
3740

38-
private updateDecorations(editor: ICodeEditor) {
41+
private updateDecorations() {
3942
const model = this.editor.getModel();
4043
const blocks = model ? getBlocks(model, { blockToRemoveStartLinePrefix: conflictMarkers.start, blockToRemoveEndLinePrefix: conflictMarkers.end }) : { blocks: [] };
4144

42-
editor.setHiddenAreas(blocks.blocks.map(b => b.lineRange.deltaEnd(-1).toRange()), this);
43-
editor.changeViewZones(c => {
45+
this.editor.setHiddenAreas(blocks.blocks.map(b => b.lineRange.deltaEnd(-1).toRange()), this);
46+
this.editor.changeViewZones(c => {
47+
this.disposableStore.clear();
4448
for (const id of this.viewZoneIds) {
4549
c.removeZone(id);
4650
}
4751
this.viewZoneIds.length = 0;
4852
for (const b of blocks.blocks) {
53+
54+
const startLine = model!.getLineContent(b.lineRange.startLineNumber).substring(0, 20);
55+
const endLine = model!.getLineContent(b.lineRange.endLineNumberExclusive - 1).substring(0, 20);
56+
57+
const domNode = h('div', [
58+
h('div.conflict-zone-root', [
59+
h('pre', [startLine]),
60+
h('span.dots', ['...']),
61+
h('pre', [endLine]),
62+
h('span.text', [nls.localize('conflictingLines', "Conflicting Lines")]),
63+
]),
64+
]).root;
4965
this.viewZoneIds.push(c.addZone({
5066
afterLineNumber: b.lineRange.endLineNumberExclusive - 1,
51-
domNode: h('div.conflict-zone', [
52-
h('div.conflict-zone-root', [h('div.conflict-zone-button', ['Conflict Marker'])]),
53-
]).root,
54-
heightInLines: 1,
67+
domNode,
68+
heightInLines: 1.5,
69+
}));
70+
71+
const updateWidth = () => {
72+
const layoutInfo = this.editor.getLayoutInfo();
73+
domNode.style.width = `${layoutInfo.contentWidth - layoutInfo.verticalScrollbarWidth}px`;
74+
};
75+
76+
this.disposableStore.add(
77+
this.editor.onDidLayoutChange(() => {
78+
updateWidth();
79+
})
80+
);
81+
updateWidth();
82+
83+
84+
this.disposableStore.add(autorun('update classname', reader => {
85+
const vm = this.mergeEditorViewModel.read(reader);
86+
if (!vm) {
87+
return;
88+
}
89+
const activeRange = vm.activeModifiedBaseRange.read(reader);
90+
91+
const classNames: string[] = [];
92+
classNames.push('conflict-zone');
93+
94+
if (activeRange) {
95+
const activeRangeInResult = vm.model.getRangeInResult(activeRange.baseRange, reader);
96+
if (activeRangeInResult.intersects(b.lineRange)) {
97+
classNames.push('focused');
98+
}
99+
}
100+
101+
domNode.className = classNames.join(' ');
55102
}));
56103
}
57104
});

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,9 @@ export class LineRange {
111111
}
112112
return new Range(this.startLineNumber, 1, this.endLineNumberExclusive - 1, Constants.MAX_SAFE_SMALL_INTEGER);
113113
}
114+
115+
intersects(lineRange: LineRange) {
116+
return this.startLineNumber <= lineRange.endLineNumberExclusive
117+
&& lineRange.startLineNumber <= this.endLineNumberExclusive;
118+
}
114119
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,9 @@ export const unhandledConflictMinimapOverViewRulerColor = registerColor(
5454
{ dark: '#fcba03FF', light: '#fcba03FF', hcDark: '#fcba03FF', hcLight: '#fcba03FF', },
5555
localize('mergeEditor.conflict.unhandled.minimapOverViewRuler', 'The foreground color for changes in input 1.')
5656
);
57+
58+
export const conflictingLinesBackground = registerColor(
59+
'mergeEditor.conflictingLines.background',
60+
{ dark: '#ffea0047', light: '#ffea0047', hcDark: '#ffea0047', hcLight: '#ffea0047', },
61+
localize('mergeEditor.conflictingLines.background', 'The background of the "Conflicting Lines" text.')
62+
);

src/vs/workbench/contrib/mergeEditor/browser/view/editors/resultCodeEditorView.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import { CompareResult } from 'vs/base/common/arrays';
77
import { BugIndicatingError } from 'vs/base/common/errors';
88
import { autorun, derived } from 'vs/base/common/observable';
9-
import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
109
import { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model';
1110
import { localize } from 'vs/nls';
1211
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -113,6 +112,8 @@ export class ResultCodeEditorView extends CodeEditorView {
113112

114113
this._register(applyObservableDecorations(this.editor, this.decorations));
115114

115+
this._register(new MergeMarkersController(this.editor, this.viewModel));
116+
116117
this.htmlElements.gutterDiv.style.width = '5px';
117118

118119
this._register(
@@ -147,11 +148,4 @@ export class ResultCodeEditorView extends CodeEditorView {
147148

148149
}));
149150
}
150-
151-
protected override getEditorContributions(): IEditorContributionDescription[] | undefined {
152-
return [
153-
...EditorExtensionsRegistry.getEditorContributions(),
154-
{ id: MergeMarkersController.ID, ctor: MergeMarkersController }
155-
] as IEditorContributionDescription[];
156-
}
157151
}

src/vs/workbench/contrib/mergeEditor/browser/view/media/mergeEditor.css

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,41 @@
159159
}
160160

161161
.conflict-zone-root {
162+
border: 2px solid var(--vscode-mergeEditor-conflict-unhandledUnfocused-border);
163+
background-color: var(--vscode-mergeEditor-change-background);
164+
165+
height: 90%;
166+
display: flex;
167+
align-items: center;
168+
align-content: center;
169+
}
170+
171+
.conflict-zone-root .dots {
172+
margin: 0 10px;
173+
}
174+
175+
.conflict-zone-root pre {
176+
display: 'inline';
177+
font-family: var(--monaco-monospace-font);
178+
}
179+
180+
.conflict-zone-root .text {
181+
margin-left: auto;
182+
padding: 0 12px;
162183
display: flex;
184+
align-items: center;
185+
background: var(--vscode-mergeEditor-conflictingLines-background);
186+
height: 100%;
187+
white-space: nowrap;
188+
overflow: hidden;
163189
}
164190

165-
.conflict-zone-button {
166-
border: 1px solid red;
167-
background: #ec010147;
168-
padding: 0px 10px;
169-
border-radius: 4px;
191+
192+
.focused.conflict-zone .conflict-zone-root {
193+
border: 2px solid var(--vscode-mergeEditor-conflict-unhandledFocused-border);
194+
}
195+
196+
197+
.view-zones {
198+
z-index: 10000000;
170199
}

0 commit comments

Comments
 (0)