Skip to content

Commit e568a31

Browse files
authored
Merge pull request microsoft#151826 from Mingpan/mingpan/side-by-side-diff-arrow-revert
2 parents bb012a1 + 778e622 commit e568a31

File tree

3 files changed

+100
-1
lines changed

3 files changed

+100
-1
lines changed

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

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,9 +592,75 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
592592
});
593593
}));
594594

595+
// Revert change when an arrow is clicked.
596+
this._register(editor.onMouseDown(event => {
597+
if (!event.event.rightButton && event.target.position && event.target.element?.className.includes('arrow-revert-change')) {
598+
const lineNumber = event.target.position.lineNumber;
599+
const change = this._diffComputationResult?.changes.find(c => c.modifiedStartLineNumber === lineNumber - 1 || c.modifiedStartLineNumber === lineNumber);
600+
if (change) {
601+
this.revertChange(change);
602+
}
603+
event.event.stopPropagation();
604+
this._updateDecorations();
605+
return;
606+
}
607+
}));
608+
595609
return editor;
596610
}
597611

612+
/**
613+
* Reverts a change in the modified editor.
614+
*/
615+
revertChange(change: IChange) {
616+
const editor = this._modifiedEditor;
617+
const original = this._originalEditor.getModel();
618+
const modified = this._modifiedEditor.getModel();
619+
if (!original || !modified || !editor) {
620+
return;
621+
}
622+
623+
const originalRange = change.originalEndLineNumber > 0 ? new Range(change.originalStartLineNumber, 1, change.originalEndLineNumber, original.getLineMaxColumn(change.originalEndLineNumber)) : null;
624+
const originalContent = originalRange ? original.getValueInRange(originalRange) : null;
625+
626+
const newRange = change.modifiedEndLineNumber > 0 ? new Range(change.modifiedStartLineNumber, 1, change.modifiedEndLineNumber, modified.getLineMaxColumn(change.modifiedEndLineNumber)) : null;
627+
628+
const eol = modified.getEOL();
629+
630+
if (change.originalEndLineNumber === 0 && newRange) {
631+
// Insert change.
632+
// To revert: delete the new content and a linebreak (if possible)
633+
634+
let range = newRange;
635+
if (change.modifiedStartLineNumber > 1) {
636+
// Try to include a linebreak from before.
637+
range = newRange.setStartPosition(change.modifiedStartLineNumber - 1, modified.getLineMaxColumn(change.modifiedStartLineNumber - 1));
638+
} else if (change.modifiedEndLineNumber < modified.getLineCount()) {
639+
// Try to include the linebreak from after.
640+
range = newRange.setEndPosition(change.modifiedEndLineNumber + 1, 1);
641+
}
642+
editor.executeEdits('diffEditor', [{
643+
range,
644+
text: '',
645+
}]);
646+
} else if (change.modifiedEndLineNumber === 0 && originalContent) {
647+
// Delete change.
648+
// To revert: insert the old content and a linebreak.
649+
650+
const insertAt = change.modifiedStartLineNumber < modified.getLineCount() ? new Position(change.modifiedStartLineNumber + 1, 1) : new Position(change.modifiedStartLineNumber, modified.getLineMaxColumn(change.modifiedStartLineNumber));
651+
editor.executeEdits('diffEditor', [{
652+
range: Range.fromPositions(insertAt, insertAt),
653+
text: change.modifiedStartLineNumber < modified.getLineCount() ? originalContent + eol : eol + originalContent,
654+
}]);
655+
} else if (newRange && originalContent !== null) {
656+
// Modified change.
657+
editor.executeEdits('diffEditor', [{
658+
range: newRange,
659+
text: originalContent,
660+
}]);
661+
}
662+
}
663+
598664
protected _createInnerEditor(instantiationService: IInstantiationService, container: HTMLElement, options: Readonly<IEditorConstructionOptions>, editorWidgetOptions: ICodeEditorWidgetOptions): CodeEditorWidget {
599665
return instantiationService.createInstance(CodeEditorWidget, container, options, editorWidgetOptions);
600666
}
@@ -1734,6 +1800,11 @@ function createDecoration(startLineNumber: number, startColumn: number, endLineN
17341800

17351801
const DECORATIONS = {
17361802

1803+
arrowRevertChange: ModelDecorationOptions.register({
1804+
description: 'diff-editor-arrow-revert-change',
1805+
glyphMarginClassName: 'arrow-revert-change ' + ThemeIcon.asClassName(Codicon.arrowRight),
1806+
}),
1807+
17371808
charDelete: ModelDecorationOptions.register({
17381809
description: 'diff-editor-char-delete',
17391810
className: 'char-delete'
@@ -1969,6 +2040,19 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IVerti
19692040

19702041
for (const lineChange of lineChanges) {
19712042

2043+
// Arrows for reverting changes.
2044+
if (lineChange.modifiedEndLineNumber > 0) {
2045+
result.decorations.push({
2046+
range: new Range(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedStartLineNumber, 1),
2047+
options: DECORATIONS.arrowRevertChange
2048+
});
2049+
} else {
2050+
const viewZone = zones.modified.find(z => z.afterLineNumber === lineChange.modifiedStartLineNumber);
2051+
if (viewZone) {
2052+
viewZone.marginDomNode = createViewZoneMarginArrow();
2053+
}
2054+
}
2055+
19722056
if (isChangeOrInsert(lineChange)) {
19732057

19742058
result.decorations.push({
@@ -2532,6 +2616,12 @@ function createFakeLinesDiv(): HTMLElement {
25322616
return r;
25332617
}
25342618

2619+
function createViewZoneMarginArrow(): HTMLElement {
2620+
const arrow = document.createElement('div');
2621+
arrow.className = 'arrow-revert-change ' + ThemeIcon.asClassName(Codicon.arrowRight);
2622+
return dom.$('div', {}, arrow);
2623+
}
2624+
25352625
function getViewRange(model: ITextModel, viewModel: IViewModel, startLineNumber: number, endLineNumber: number): Range {
25362626
const lineCount = model.getLineCount();
25372627
startLineNumber = Math.min(lineCount, Math.max(1, startLineNumber));

src/vs/editor/browser/widget/media/diffEditor.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@
5757
text-align: right;
5858
}
5959

60+
.monaco-editor .arrow-revert-change {
61+
z-index: 10;
62+
position: absolute;
63+
}
64+
65+
.monaco-editor .arrow-revert-change:hover {
66+
cursor: pointer;
67+
}
68+
6069
/* ---------- Inline Diff ---------- */
6170

6271
.monaco-editor .view-zones .view-lines .view-line span {

src/vs/workbench/contrib/debug/browser/breakpointEditorContribution.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
465465
if (decorations) {
466466
for (const { options } of decorations) {
467467
const clz = options.glyphMarginClassName;
468-
if (clz && (!clz.includes('codicon-') || clz.includes('codicon-testing-') || clz.includes('codicon-merge-'))) {
468+
if (clz && (!clz.includes('codicon-') || clz.includes('codicon-testing-') || clz.includes('codicon-merge-') || clz.includes('codicon-arrow-'))) {
469469
return false;
470470
}
471471
}

0 commit comments

Comments
 (0)