Skip to content

Commit

Permalink
Fixes #188284 - Adds diffEditor.switchSide command
Browse files Browse the repository at this point in the history
  • Loading branch information
hediet committed Jul 20, 2023
1 parent 2cbf01b commit e06df6d
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@

import { Codicon } from 'vs/base/common/codicons';
import { ThemeIcon } from 'vs/base/common/themables';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { findFocusedDiffEditor } from 'vs/editor/browser/widget/diffEditor.contribution';
import { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';
import { localize } from 'vs/nls';
import { ILocalizedString } from 'vs/platform/action/common/action';
import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
Expand Down Expand Up @@ -88,3 +92,29 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, {
group: '1_diff',
when: ContextKeyEqualsExpr.create('diffEditorVersion', 2)
});

const diffEditorCategory: ILocalizedString = {
value: localize('diffEditor', 'Diff Editor'),
original: 'Diff Editor',
};
export class SwitchSide extends EditorAction2 {
constructor() {
super({
id: 'diffEditor.switchSide',
title: { value: localize('switchSide', "Switch Side"), original: 'Switch Side' },
icon: Codicon.arrowSwap,
precondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),
f1: true,
category: diffEditorCategory,
});
}

runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {
const diffEditor = findFocusedDiffEditor(accessor);
if (diffEditor instanceof DiffEditorWidget2) {
diffEditor.switchSide();
}
}
}

registerAction2(SwitchSide);
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import { DiffEditorViewModel, DiffMapping, DiffState } from './diffEditorViewMod
import { AccessibleDiffViewer } from 'vs/editor/browser/widget/diffEditorWidget2/accessibleDiffViewer';
import { CursorChangeReason } from 'vs/editor/common/cursorEvents';
import { AudioCue, IAudioCueService } from 'vs/platform/audioCues/browser/audioCueService';
import { LengthObj } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';
import { Range } from 'vs/editor/common/core/range';

export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
private readonly elements = h('div.monaco-diff-editor.side-by-side', { style: { position: 'relative', height: '100%' } }, [
Expand Down Expand Up @@ -479,6 +481,71 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
if (!diffModel) { return; }
await diffModel.waitForDiff();
}

switchSide(): void {
const isModifiedFocus = this._editors.modified.hasWidgetFocus();
const source = isModifiedFocus ? this._editors.modified : this._editors.original;
const destination = isModifiedFocus ? this._editors.original : this._editors.modified;

const sourceSelection = source.getSelection();
if (sourceSelection) {
const mappings = this._diffModel.get()?.diff.get()?.mappings.map(m => isModifiedFocus ? m.lineRangeMapping.flip() : m.lineRangeMapping);
if (mappings) {
const newRange1 = translatePosition(sourceSelection.getStartPosition(), mappings);
const newRange2 = translatePosition(sourceSelection.getEndPosition(), mappings);
const range = Range.plusRange(newRange1, newRange2);
destination.setSelection(range);
}
}
destination.focus();
}
}

function translatePosition(posInOriginal: Position, mappings: LineRangeMapping[]): Range {
const mapping = findLast(mappings, m => m.originalRange.startLineNumber <= posInOriginal.lineNumber);
if (!mapping) {
// No changes before the position
return Range.fromPositions(posInOriginal);
}

if (mapping.originalRange.endLineNumberExclusive <= posInOriginal.lineNumber) {
const newLineNumber = posInOriginal.lineNumber - mapping.originalRange.endLineNumberExclusive + mapping.modifiedRange.endLineNumberExclusive;
return Range.fromPositions(new Position(newLineNumber, posInOriginal.column));
}

if (!mapping.innerChanges) {
// Only for legacy algorithm
return Range.fromPositions(new Position(mapping.modifiedRange.startLineNumber, 1));
}

const innerMapping = findLast(mapping.innerChanges, m => m.originalRange.getStartPosition().isBeforeOrEqual(posInOriginal));
if (!innerMapping) {
const newLineNumber = posInOriginal.lineNumber - mapping.originalRange.startLineNumber + mapping.modifiedRange.startLineNumber;
return Range.fromPositions(new Position(newLineNumber, posInOriginal.column));
}

if (innerMapping.originalRange.containsPosition(posInOriginal)) {
return innerMapping.modifiedRange;
} else {
const l = lengthBetweenPositions(innerMapping.originalRange.getEndPosition(), posInOriginal);
return Range.fromPositions(addLength(innerMapping.modifiedRange.getEndPosition(), l));
}
}

function lengthBetweenPositions(position1: Position, position2: Position): LengthObj {
if (position1.lineNumber === position2.lineNumber) {
return new LengthObj(0, position2.column - position1.column);
} else {
return new LengthObj(position2.lineNumber - position1.lineNumber, position2.column - 1);
}
}

function addLength(position: Position, length: LengthObj): Position {
if (length.lineCount === 0) {
return new Position(position.lineNumber, position.column + length.columnCount);
} else {
return new Position(position.lineNumber + length.lineCount, length.columnCount + 1);
}
}

function toLineChanges(state: DiffState): ILineChange[] {
Expand Down

0 comments on commit e06df6d

Please sign in to comment.