Skip to content

Commit da7ab49

Browse files
authored
Fixes microsoft#188284 - Adds diffEditor.switchSide command (microsoft#188291)
1 parent acf5d15 commit da7ab49

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed

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

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55

66
import { Codicon } from 'vs/base/common/codicons';
77
import { ThemeIcon } from 'vs/base/common/themables';
8-
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
8+
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
9+
import { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
10+
import { findFocusedDiffEditor } from 'vs/editor/browser/widget/diffEditor.contribution';
11+
import { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';
912
import { localize } from 'vs/nls';
13+
import { ILocalizedString } from 'vs/platform/action/common/action';
1014
import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
1115
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1216
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
@@ -88,3 +92,29 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
8892
group: '1_diff',
8993
when: ContextKeyEqualsExpr.create('diffEditorVersion', 2)
9094
});
95+
96+
const diffEditorCategory: ILocalizedString = {
97+
value: localize('diffEditor', 'Diff Editor'),
98+
original: 'Diff Editor',
99+
};
100+
export class SwitchSide extends EditorAction2 {
101+
constructor() {
102+
super({
103+
id: 'diffEditor.switchSide',
104+
title: { value: localize('switchSide', "Switch Side"), original: 'Switch Side' },
105+
icon: Codicon.arrowSwap,
106+
precondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),
107+
f1: true,
108+
category: diffEditorCategory,
109+
});
110+
}
111+
112+
runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {
113+
const diffEditor = findFocusedDiffEditor(accessor);
114+
if (diffEditor instanceof DiffEditorWidget2) {
115+
diffEditor.switchSide();
116+
}
117+
}
118+
}
119+
120+
registerAction2(SwitchSide);

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

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import { DiffEditorViewModel, DiffMapping, DiffState } from './diffEditorViewMod
4444
import { AccessibleDiffViewer } from 'vs/editor/browser/widget/diffEditorWidget2/accessibleDiffViewer';
4545
import { CursorChangeReason } from 'vs/editor/common/cursorEvents';
4646
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
47+
import { LengthObj } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';
48+
import { Range } from 'vs/editor/common/core/range';
4749

4850
export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
4951
private readonly elements = h('div.monaco-diff-editor.side-by-side', { style: { position: 'relative', height: '100%' } }, [
@@ -479,6 +481,71 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
479481
if (!diffModel) { return; }
480482
await diffModel.waitForDiff();
481483
}
484+
485+
switchSide(): void {
486+
const isModifiedFocus = this._editors.modified.hasWidgetFocus();
487+
const source = isModifiedFocus ? this._editors.modified : this._editors.original;
488+
const destination = isModifiedFocus ? this._editors.original : this._editors.modified;
489+
490+
const sourceSelection = source.getSelection();
491+
if (sourceSelection) {
492+
const mappings = this._diffModel.get()?.diff.get()?.mappings.map(m => isModifiedFocus ? m.lineRangeMapping.flip() : m.lineRangeMapping);
493+
if (mappings) {
494+
const newRange1 = translatePosition(sourceSelection.getStartPosition(), mappings);
495+
const newRange2 = translatePosition(sourceSelection.getEndPosition(), mappings);
496+
const range = Range.plusRange(newRange1, newRange2);
497+
destination.setSelection(range);
498+
}
499+
}
500+
destination.focus();
501+
}
502+
}
503+
504+
function translatePosition(posInOriginal: Position, mappings: LineRangeMapping[]): Range {
505+
const mapping = findLast(mappings, m => m.originalRange.startLineNumber <= posInOriginal.lineNumber);
506+
if (!mapping) {
507+
// No changes before the position
508+
return Range.fromPositions(posInOriginal);
509+
}
510+
511+
if (mapping.originalRange.endLineNumberExclusive <= posInOriginal.lineNumber) {
512+
const newLineNumber = posInOriginal.lineNumber - mapping.originalRange.endLineNumberExclusive + mapping.modifiedRange.endLineNumberExclusive;
513+
return Range.fromPositions(new Position(newLineNumber, posInOriginal.column));
514+
}
515+
516+
if (!mapping.innerChanges) {
517+
// Only for legacy algorithm
518+
return Range.fromPositions(new Position(mapping.modifiedRange.startLineNumber, 1));
519+
}
520+
521+
const innerMapping = findLast(mapping.innerChanges, m => m.originalRange.getStartPosition().isBeforeOrEqual(posInOriginal));
522+
if (!innerMapping) {
523+
const newLineNumber = posInOriginal.lineNumber - mapping.originalRange.startLineNumber + mapping.modifiedRange.startLineNumber;
524+
return Range.fromPositions(new Position(newLineNumber, posInOriginal.column));
525+
}
526+
527+
if (innerMapping.originalRange.containsPosition(posInOriginal)) {
528+
return innerMapping.modifiedRange;
529+
} else {
530+
const l = lengthBetweenPositions(innerMapping.originalRange.getEndPosition(), posInOriginal);
531+
return Range.fromPositions(addLength(innerMapping.modifiedRange.getEndPosition(), l));
532+
}
533+
}
534+
535+
function lengthBetweenPositions(position1: Position, position2: Position): LengthObj {
536+
if (position1.lineNumber === position2.lineNumber) {
537+
return new LengthObj(0, position2.column - position1.column);
538+
} else {
539+
return new LengthObj(position2.lineNumber - position1.lineNumber, position2.column - 1);
540+
}
541+
}
542+
543+
function addLength(position: Position, length: LengthObj): Position {
544+
if (length.lineCount === 0) {
545+
return new Position(position.lineNumber, position.column + length.columnCount);
546+
} else {
547+
return new Position(position.lineNumber + length.lineCount, length.columnCount + 1);
548+
}
482549
}
483550

484551
function toLineChanges(state: DiffState): ILineChange[] {

0 commit comments

Comments
 (0)