microsoft / vscode

Visual Studio Code
https://code.visualstudio.com
MIT License
162.67k stars 28.68k forks source link

Merge Editor: Diff Both Inputs Against Each Other #157496

Open hediet opened 2 years ago

hediet commented 2 years ago

Currently, we just look at the diffs between input1 and base and input2 and base. However, if input1 and input2 caused the same edit relative to base, we should be smarter.

By default, git uses the conflict style merge, which diffs the changes against each other and accepts the longest common substring.

Our implementation matches gits diff3 conflict style, which does not move common lines out of conflicts.

Related: #155965


create a new branch conflict new and commit a file merge_conflict_test.go, with Name: "n1"

// branch conflict
package main

import (
    "github.com/gin-gonic/gin"
)

func Foo1(c *gin.Context) {
    s1 := s{
        ID:        111,
        Condition: "c1",
        Check:     true,
        Name:      "n1" // diff from master
    }
}

func Foo2(c *gin.Context) {
    line1 := "line1"
    line2 := "line2"
    line3 := "line3"
    line4 := "line4"
    line5 := "line5"
    line6 := "line6"
}

func Foo3(c *gin.Context) {
    s3 := s{
        ID:        123,
        Condition: "c3",
        Check:     true,
        Name:      "n3" // diff from master
    }
}

back to master, also new file merge_conflict_test.go, without Name: "n1"

// branch master
package main

import (
    "github.com/gin-gonic/gin"
)

func Foo1(c *gin.Context) {
    s1 := s{
        ID:        111,
        Condition: "c1",
        Check:     true,
    }
}

func Foo2(c *gin.Context) {
    line1 := "line1"
    line2 := "line2"
    line3 := "line3"
    line4 := "line4"
    line5 := "line5"
    line6 := "line6"
}

func Foo3(c *gin.Context) {
    s3 := s{
        ID:        123,
        Condition: "c3",
        Check:     true,
    }
}

commit, then goto conflict, rebase master image

with "git.mergeEditor": false on image

3 way merge editor: image

Originally posted by @Void-King in https://github.com/microsoft/vscode/issues/157469#issuecomment-1207839032

hediet commented 2 years ago

Related: https://github.com/microsoft/vscode/issues/157997#issuecomment-1213066409 in #157997

hediet commented 2 years ago

This is a counter example, where diffing both sides makes the experience worse:

image

When not removing the common prefix/suffix, both changes can easily be combined:

recording

sanket-bhalerao commented 1 year ago

is there any way to have the checkbox experience back? i prefer checkbox over the current codesens prompts.

hediet commented 1 year ago

Another example of where gits behavior is confusing that I just ran into:

GitHub/git (what is the conflict?):

chrome_WEPaXOkR6A

VS Code Merge Editor (clearly on the left someone inserted two methods, on the right someone added one method):

Code_-_Insiders_YHZv48CAvC

hediet commented 1 year ago

This one is much worse:

GitHub (completely unusable diff):

chrome_JjUDN84Idw

VS Code:

Code_-_Insiders_9YJdClDt4y

Both are confusing, but VS Code got also lucky with a better diff, so it is much less confusing.

{
    "languageId": "typescript",
    "base": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Microsoft Corporation. All rights reserved.\n *  Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { findFocusedDiffEditor } from 'vs/editor/browser/widget/diffEditor.contribution';\nimport { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { localize } from 'vs/nls';\nimport { ILocalizedString } from 'vs/platform/action/common/action';\nimport { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\n\nexport class ToggleCollapseUnchangedRegions extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleCollapseUnchangedRegions',\n\t\t\ttitle: { value: localize('toggleCollapseUnchangedRegions', \"Toggle Collapse Unchanged Regions\"), original: 'Toggle Collapse Unchanged Regions' },\n\t\t\ticon: Codicon.map,\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t\ttoggled: ContextKeyExpr.has('config.diffEditor.experimental.collapseUnchangedRegions'),\n\t\t\tmenu: {\n\t\t\t\tid: MenuId.EditorTitle,\n\t\t\t\torder: 22,\n\t\t\t\tgroup: 'navigation',\n\t\t\t\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t\t},\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.collapseUnchangedRegions');\n\t\tconfigurationService.updateValue('diffEditor.experimental.collapseUnchangedRegions', newValue);\n\t}\n}\n\nregisterAction2(ToggleCollapseUnchangedRegions);\n\nexport class ToggleShowMovedCodeBlocks extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleShowMovedCodeBlocks',\n\t\t\ttitle: { value: localize('toggleShowMovedCodeBlocks', \"Toggle Show Moved Code Blocks\"), original: 'Toggle Show Moved Code Blocks' },\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.showMoves');\n\t\tconfigurationService.updateValue('diffEditor.experimental.showMoves', newValue);\n\t}\n}\n\nregisterAction2(ToggleShowMovedCodeBlocks);\n\nexport class ToggleUseInlineViewWhenSpaceIsLimited extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleUseInlineViewWhenSpaceIsLimited',\n\t\t\ttitle: { value: localize('toggleUseInlineViewWhenSpaceIsLimited', \"Toggle Use Inline View When Space Is Limited\"), original: 'Toggle Use Inline View When Space Is Limited' },\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.useInlineViewWhenSpaceIsLimited');\n\t\tconfigurationService.updateValue('diffEditor.useInlineViewWhenSpaceIsLimited', newValue);\n\t}\n}\n\nregisterAction2(ToggleUseInlineViewWhenSpaceIsLimited);\n\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\n\tcommand: {\n\t\tid: new ToggleUseInlineViewWhenSpaceIsLimited().desc.id,\n\t\ttitle: localize('useInlineViewWhenSpaceIsLimited', \"Use Inline View When Space Is Limited\"),\n\t\ttoggled: ContextKeyExpr.has('config.diffEditor.useInlineViewWhenSpaceIsLimited'),\n\t},\n\torder: 11,\n\tgroup: '1_diff',\n\twhen: ContextKeyExpr.and(\n\t\tEditorContextKeys.diffEditorRenderSideBySideInlineBreakpointReached,\n\t\tContextKeyEqualsExpr.create('diffEditorVersion', 2)\n\t)\n});\n\n/*\nTODO@hediet add this back once move detection is more polished.\nUsers can still enable this via settings.json (config.diffEditor.experimental.showMoves).\n\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\n\tcommand: {\n\t\tid: new ToggleShowMovedCodeBlocks().desc.id,\n\t\ttitle: localize('showMoves', \"Show Moves\"),\n\t\ticon: Codicon.move,\n\t\ttoggled: ContextKeyEqualsExpr.create('config.diffEditor.experimental.showMoves', true),\n\t},\n\torder: 10,\n\tgroup: '1_diff',\n\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2)\n});\n*/\n\nconst diffEditorCategory: ILocalizedString = {\n\tvalue: localize('diffEditor', 'Diff Editor'),\n\toriginal: 'Diff Editor',\n};\nexport class SwitchSide extends EditorAction2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.switchSide',\n\t\t\ttitle: { value: localize('switchSide', \"Switch Side\"), original: 'Switch Side' },\n\t\t\ticon: Codicon.arrowSwap,\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\n\t\t\tf1: true,\n\t\t\tcategory: diffEditorCategory,\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\n\t\t\tdiffEditor.switchSide();\n\t\t}\n\t}\n}\n\nregisterAction2(SwitchSide);\n",
    "input1": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Microsoft Corporation. All rights reserved.\n *  Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Codicon } from 'vs/base/common/codicons';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { findFocusedDiffEditor } from 'vs/editor/browser/widget/diffEditor.contribution';\nimport { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { localize } from 'vs/nls';\nimport { ILocalizedString } from 'vs/platform/action/common/action';\nimport { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\n\nexport class ToggleCollapseUnchangedRegions extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleCollapseUnchangedRegions',\n\t\t\ttitle: { value: localize('toggleCollapseUnchangedRegions', \"Toggle Collapse Unchanged Regions\"), original: 'Toggle Collapse Unchanged Regions' },\n\t\t\ticon: Codicon.map,\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t\ttoggled: ContextKeyExpr.has('config.diffEditor.experimental.collapseUnchangedRegions'),\n\t\t\tmenu: {\n\t\t\t\tid: MenuId.EditorTitle,\n\t\t\t\torder: 22,\n\t\t\t\tgroup: 'navigation',\n\t\t\t\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t\t},\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.collapseUnchangedRegions');\n\t\tconfigurationService.updateValue('diffEditor.experimental.collapseUnchangedRegions', newValue);\n\t}\n}\n\nregisterAction2(ToggleCollapseUnchangedRegions);\n\nexport class ToggleShowMovedCodeBlocks extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleShowMovedCodeBlocks',\n\t\t\ttitle: { value: localize('toggleShowMovedCodeBlocks', \"Toggle Show Moved Code Blocks\"), original: 'Toggle Show Moved Code Blocks' },\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.showMoves');\n\t\tconfigurationService.updateValue('diffEditor.experimental.showMoves', newValue);\n\t}\n}\n\nregisterAction2(ToggleShowMovedCodeBlocks);\n\nexport class ToggleUseInlineViewWhenSpaceIsLimited extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleUseInlineViewWhenSpaceIsLimited',\n\t\t\ttitle: { value: localize('toggleUseInlineViewWhenSpaceIsLimited', \"Toggle Use Inline View When Space Is Limited\"), original: 'Toggle Use Inline View When Space Is Limited' },\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.useInlineViewWhenSpaceIsLimited');\n\t\tconfigurationService.updateValue('diffEditor.useInlineViewWhenSpaceIsLimited', newValue);\n\t}\n}\n\nregisterAction2(ToggleUseInlineViewWhenSpaceIsLimited);\n\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\n\tcommand: {\n\t\tid: new ToggleUseInlineViewWhenSpaceIsLimited().desc.id,\n\t\ttitle: localize('useInlineViewWhenSpaceIsLimited', \"Use Inline View When Space Is Limited\"),\n\t\ttoggled: ContextKeyExpr.has('config.diffEditor.useInlineViewWhenSpaceIsLimited'),\n\t},\n\torder: 11,\n\tgroup: '1_diff',\n\twhen: ContextKeyExpr.and(\n\t\tEditorContextKeys.diffEditorRenderSideBySideInlineBreakpointReached,\n\t\tContextKeyEqualsExpr.create('diffEditorVersion', 2)\n\t)\n});\n\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\n\tcommand: {\n\t\tid: new ToggleShowMovedCodeBlocks().desc.id,\n\t\ttitle: localize('showMoves', \"Show Moved Code Blocks\"),\n\t\ticon: Codicon.move,\n\t\ttoggled: ContextKeyEqualsExpr.create('config.diffEditor.experimental.showMoves', true),\n\t},\n\torder: 10,\n\tgroup: '1_diff',\n\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2)\n});\n\nconst diffEditorCategory: ILocalizedString = {\n\tvalue: localize('diffEditor', 'Diff Editor'),\n\toriginal: 'Diff Editor',\n};\nexport class SwitchSide extends EditorAction2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.switchSide',\n\t\t\ttitle: { value: localize('switchSide', \"Switch Side\"), original: 'Switch Side' },\n\t\t\ticon: Codicon.arrowSwap,\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\n\t\t\tf1: true,\n\t\t\tcategory: diffEditorCategory,\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, arg?: { dryRun: boolean }): unknown {\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\n\t\t\tif (arg && arg.dryRun) {\n\t\t\t\treturn { destinationSelection: diffEditor.mapToOtherSide().destinationSelection };\n\t\t\t} else {\n\t\t\t\tdiffEditor.switchSide();\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n}\n\nregisterAction2(SwitchSide);\n\nexport class ExitCompareMove extends EditorAction2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.exitCompareMove',\n\t\t\ttitle: { value: localize('exitCompareMove', \"Exit Compare Move\"), original: 'Exit Compare Move' },\n\t\t\ticon: Codicon.close,\n\t\t\tprecondition: EditorContextKeys.comparingMovedCode,\n\t\t\tf1: false,\n\t\t\tcategory: diffEditorCategory,\n\t\t\tkeybinding: {\n\t\t\t\tweight: 10000,\n\t\t\t\tprimary: KeyCode.Escape,\n\t\t\t}\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\n\t\t\tdiffEditor.exitCompareMove();\n\t\t}\n\t}\n}\n\nregisterAction2(ExitCompareMove);\n",
    "input2": "/*---------------------------------------------------------------------------------------------\n *  Copyright (c) Microsoft Corporation. All rights reserved.\n *  Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { findFocusedDiffEditor } from 'vs/editor/browser/widget/diffEditor.contribution';\nimport { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { localize } from 'vs/nls';\nimport { ILocalizedString } from 'vs/platform/action/common/action';\nimport { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\n\nexport class ToggleCollapseUnchangedRegions extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleCollapseUnchangedRegions',\n\t\t\ttitle: { value: localize('toggleCollapseUnchangedRegions', \"Toggle Collapse Unchanged Regions\"), original: 'Toggle Collapse Unchanged Regions' },\n\t\t\ticon: Codicon.map,\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t\ttoggled: ContextKeyExpr.has('config.diffEditor.experimental.collapseUnchangedRegions'),\n\t\t\tmenu: {\n\t\t\t\tid: MenuId.EditorTitle,\n\t\t\t\torder: 22,\n\t\t\t\tgroup: 'navigation',\n\t\t\t\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t\t},\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.collapseUnchangedRegions');\n\t\tconfigurationService.updateValue('diffEditor.experimental.collapseUnchangedRegions', newValue);\n\t}\n}\n\nregisterAction2(ToggleCollapseUnchangedRegions);\n\nexport class ToggleShowMovedCodeBlocks extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleShowMovedCodeBlocks',\n\t\t\ttitle: { value: localize('toggleShowMovedCodeBlocks', \"Toggle Show Moved Code Blocks\"), original: 'Toggle Show Moved Code Blocks' },\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.showMoves');\n\t\tconfigurationService.updateValue('diffEditor.experimental.showMoves', newValue);\n\t}\n}\n\nregisterAction2(ToggleShowMovedCodeBlocks);\n\nexport class ToggleUseInlineViewWhenSpaceIsLimited extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.toggleUseInlineViewWhenSpaceIsLimited',\n\t\t\ttitle: { value: localize('toggleUseInlineViewWhenSpaceIsLimited', \"Toggle Use Inline View When Space Is Limited\"), original: 'Toggle Use Inline View When Space Is Limited' },\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\n\t\tconst configurationService = accessor.get(IConfigurationService);\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.useInlineViewWhenSpaceIsLimited');\n\t\tconfigurationService.updateValue('diffEditor.useInlineViewWhenSpaceIsLimited', newValue);\n\t}\n}\n\nregisterAction2(ToggleUseInlineViewWhenSpaceIsLimited);\n\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\n\tcommand: {\n\t\tid: new ToggleUseInlineViewWhenSpaceIsLimited().desc.id,\n\t\ttitle: localize('useInlineViewWhenSpaceIsLimited', \"Use Inline View When Space Is Limited\"),\n\t\ttoggled: ContextKeyExpr.has('config.diffEditor.useInlineViewWhenSpaceIsLimited'),\n\t},\n\torder: 11,\n\tgroup: '1_diff',\n\twhen: ContextKeyExpr.and(\n\t\tEditorContextKeys.diffEditorRenderSideBySideInlineBreakpointReached,\n\t\tContextKeyEqualsExpr.create('diffEditorVersion', 2)\n\t)\n});\n\n/*\nTODO@hediet add this back once move detection is more polished.\nUsers can still enable this via settings.json (config.diffEditor.experimental.showMoves).\n\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\n\tcommand: {\n\t\tid: new ToggleShowMovedCodeBlocks().desc.id,\n\t\ttitle: localize('showMoves', \"Show Moves\"),\n\t\ticon: Codicon.move,\n\t\ttoggled: ContextKeyEqualsExpr.create('config.diffEditor.experimental.showMoves', true),\n\t},\n\torder: 10,\n\tgroup: '1_diff',\n\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2)\n});\n*/\n\nconst diffEditorCategory: ILocalizedString = {\n\tvalue: localize('diffEditor', 'Diff Editor'),\n\toriginal: 'Diff Editor',\n};\n\nexport class SwitchSide extends EditorAction2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.switchSide',\n\t\t\ttitle: { value: localize('switchSide', \"Switch Side\"), original: 'Switch Side' },\n\t\t\ticon: Codicon.arrowSwap,\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\n\t\t\tf1: true,\n\t\t\tcategory: diffEditorCategory,\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\n\t\t\tdiffEditor.switchSide();\n\t\t}\n\t}\n}\n\nregisterAction2(SwitchSide);\n\nexport class CollapseAllUnchangedRegions extends EditorAction2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.collapseAllUnchangedRegions',\n\t\t\ttitle: { value: localize('collapseAllUnchangedRegions', \"Collapse All Unchanged Regions\"), original: 'Collapse All Unchanged Regions' },\n\t\t\ticon: Codicon.fold,\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\n\t\t\tf1: true,\n\t\t\tcategory: diffEditorCategory,\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\n\t\t\tdiffEditor.collapseAllUnchangedRegions();\n\t\t}\n\t}\n}\n\nregisterAction2(CollapseAllUnchangedRegions);\n\nexport class ShowAllUnchangedRegions extends EditorAction2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'diffEditor.showAllUnchangedRegions',\n\t\t\ttitle: { value: localize('showAllUnchangedRegions', \"Show All Unchanged Regions\"), original: 'Show All Unchanged Regions' },\n\t\t\ticon: Codicon.unfold,\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\n\t\t\tf1: true,\n\t\t\tcategory: diffEditorCategory,\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\n\t\t\tdiffEditor.showAllUnchangedRegions();\n\t\t}\n\t}\n}\n\nregisterAction2(ShowAllUnchangedRegions);\n",
    "result": "/*---------------------------------------------------------------------------------------------\r\n *  Copyright (c) Microsoft Corporation. All rights reserved.\r\n *  Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\r\nimport { findFocusedDiffEditor } from 'vs/editor/browser/widget/diffEditor.contribution';\r\nimport { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { localize } from 'vs/nls';\r\nimport { ILocalizedString } from 'vs/platform/action/common/action';\r\nimport { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';\r\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\nimport { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport class ToggleCollapseUnchangedRegions extends Action2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.toggleCollapseUnchangedRegions',\r\n\t\t\ttitle: { value: localize('toggleCollapseUnchangedRegions', \"Toggle Collapse Unchanged Regions\"), original: 'Toggle Collapse Unchanged Regions' },\r\n\t\t\ticon: Codicon.map,\r\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t\ttoggled: ContextKeyExpr.has('config.diffEditor.experimental.collapseUnchangedRegions'),\r\n\t\t\tmenu: {\r\n\t\t\t\tid: MenuId.EditorTitle,\r\n\t\t\t\torder: 22,\r\n\t\t\t\tgroup: 'navigation',\r\n\t\t\t\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t\t},\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\r\n\t\tconst configurationService = accessor.get(IConfigurationService);\r\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.collapseUnchangedRegions');\r\n\t\tconfigurationService.updateValue('diffEditor.experimental.collapseUnchangedRegions', newValue);\r\n\t}\r\n}\r\n\r\nregisterAction2(ToggleCollapseUnchangedRegions);\r\n\r\nexport class ToggleShowMovedCodeBlocks extends Action2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.toggleShowMovedCodeBlocks',\r\n\t\t\ttitle: { value: localize('toggleShowMovedCodeBlocks', \"Toggle Show Moved Code Blocks\"), original: 'Toggle Show Moved Code Blocks' },\r\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\r\n\t\tconst configurationService = accessor.get(IConfigurationService);\r\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.showMoves');\r\n\t\tconfigurationService.updateValue('diffEditor.experimental.showMoves', newValue);\r\n\t}\r\n}\r\n\r\nregisterAction2(ToggleShowMovedCodeBlocks);\r\n\r\nexport class ToggleUseInlineViewWhenSpaceIsLimited extends Action2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.toggleUseInlineViewWhenSpaceIsLimited',\r\n\t\t\ttitle: { value: localize('toggleUseInlineViewWhenSpaceIsLimited', \"Toggle Use Inline View When Space Is Limited\"), original: 'Toggle Use Inline View When Space Is Limited' },\r\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\r\n\t\tconst configurationService = accessor.get(IConfigurationService);\r\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.useInlineViewWhenSpaceIsLimited');\r\n\t\tconfigurationService.updateValue('diffEditor.useInlineViewWhenSpaceIsLimited', newValue);\r\n\t}\r\n}\r\n\r\nregisterAction2(ToggleUseInlineViewWhenSpaceIsLimited);\r\n\r\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\r\n\tcommand: {\r\n\t\tid: new ToggleUseInlineViewWhenSpaceIsLimited().desc.id,\r\n\t\ttitle: localize('useInlineViewWhenSpaceIsLimited', \"Use Inline View When Space Is Limited\"),\r\n\t\ttoggled: ContextKeyExpr.has('config.diffEditor.useInlineViewWhenSpaceIsLimited'),\r\n\t},\r\n\torder: 11,\r\n\tgroup: '1_diff',\r\n\twhen: ContextKeyExpr.and(\r\n\t\tEditorContextKeys.diffEditorRenderSideBySideInlineBreakpointReached,\r\n\t\tContextKeyEqualsExpr.create('diffEditorVersion', 2)\r\n\t)\r\n});\r\n\r\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\r\n\tcommand: {\r\n\t\tid: new ToggleShowMovedCodeBlocks().desc.id,\r\n\t\ttitle: localize('showMoves', \"Show Moved Code Blocks\"),\r\n\t\ticon: Codicon.move,\r\n\t\ttoggled: ContextKeyEqualsExpr.create('config.diffEditor.experimental.showMoves', true),\r\n\t},\r\n\torder: 10,\r\n\tgroup: '1_diff',\r\n\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2)\r\n});\r\n\r\nconst diffEditorCategory: ILocalizedString = {\r\n\tvalue: localize('diffEditor', 'Diff Editor'),\r\n\toriginal: 'Diff Editor',\r\n};\r\n\r\nexport class SwitchSide extends EditorAction2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.switchSide',\r\n\t\t\ttitle: { value: localize('switchSide', \"Switch Side\"), original: 'Switch Side' },\r\n\t\t\ticon: Codicon.arrowSwap,\r\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\r\n\t\t\tf1: true,\r\n\t\t\tcategory: diffEditorCategory,\r\n\t\t});\r\n\t}\r\n\r\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, arg?: { dryRun: boolean }): unknown {\r\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\r\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\r\n\t\t\tif (arg && arg.dryRun) {\r\n\t\t\t\treturn { destinationSelection: diffEditor.mapToOtherSide().destinationSelection };\r\n\t\t\t} else {\r\n\t\t\t\tdiffEditor.switchSide();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n}\r\n\r\nregisterAction2(SwitchSide);\r\n\r\nexport class ExitCompareMove extends EditorAction2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.exitCompareMove',\r\n\t\t\ttitle: { value: localize('exitCompareMove', \"Exit Compare Move\"), original: 'Exit Compare Move' },\r\n\t\t\ticon: Codicon.close,\r\n\t\t\tprecondition: EditorContextKeys.comparingMovedCode,\r\n\t\t\tf1: false,\r\n\t\t\tcategory: diffEditorCategory,\r\n\t\t\tkeybinding: {\r\n\t\t\t\tweight: 10000,\r\n\t\t\t\tprimary: KeyCode.Escape,\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\r\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\r\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\r\n\t\t\tdiffEditor.exitCompareMove();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterAction2(SwitchSide);\r\n",
    "initialResult": "/*---------------------------------------------------------------------------------------------\r\n *  Copyright (c) Microsoft Corporation. All rights reserved.\r\n *  Licensed under the MIT License. See License.txt in the project root for license information.\r\n *--------------------------------------------------------------------------------------------*/\r\n\r\nimport { Codicon } from 'vs/base/common/codicons';\r\nimport { KeyCode } from 'vs/base/common/keyCodes';\r\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\r\nimport { EditorAction2, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\r\nimport { findFocusedDiffEditor } from 'vs/editor/browser/widget/diffEditor.contribution';\r\nimport { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';\r\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\r\nimport { localize } from 'vs/nls';\r\nimport { ILocalizedString } from 'vs/platform/action/common/action';\r\nimport { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';\r\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\r\nimport { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\r\n\r\nexport class ToggleCollapseUnchangedRegions extends Action2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.toggleCollapseUnchangedRegions',\r\n\t\t\ttitle: { value: localize('toggleCollapseUnchangedRegions', \"Toggle Collapse Unchanged Regions\"), original: 'Toggle Collapse Unchanged Regions' },\r\n\t\t\ticon: Codicon.map,\r\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t\ttoggled: ContextKeyExpr.has('config.diffEditor.experimental.collapseUnchangedRegions'),\r\n\t\t\tmenu: {\r\n\t\t\t\tid: MenuId.EditorTitle,\r\n\t\t\t\torder: 22,\r\n\t\t\t\tgroup: 'navigation',\r\n\t\t\t\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t\t},\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\r\n\t\tconst configurationService = accessor.get(IConfigurationService);\r\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.collapseUnchangedRegions');\r\n\t\tconfigurationService.updateValue('diffEditor.experimental.collapseUnchangedRegions', newValue);\r\n\t}\r\n}\r\n\r\nregisterAction2(ToggleCollapseUnchangedRegions);\r\n\r\nexport class ToggleShowMovedCodeBlocks extends Action2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.toggleShowMovedCodeBlocks',\r\n\t\t\ttitle: { value: localize('toggleShowMovedCodeBlocks', \"Toggle Show Moved Code Blocks\"), original: 'Toggle Show Moved Code Blocks' },\r\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\r\n\t\tconst configurationService = accessor.get(IConfigurationService);\r\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.experimental.showMoves');\r\n\t\tconfigurationService.updateValue('diffEditor.experimental.showMoves', newValue);\r\n\t}\r\n}\r\n\r\nregisterAction2(ToggleShowMovedCodeBlocks);\r\n\r\nexport class ToggleUseInlineViewWhenSpaceIsLimited extends Action2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.toggleUseInlineViewWhenSpaceIsLimited',\r\n\t\t\ttitle: { value: localize('toggleUseInlineViewWhenSpaceIsLimited', \"Toggle Use Inline View When Space Is Limited\"), original: 'Toggle Use Inline View When Space Is Limited' },\r\n\t\t\tprecondition: ContextKeyEqualsExpr.create('diffEditorVersion', 2),\r\n\t\t});\r\n\t}\r\n\r\n\trun(accessor: ServicesAccessor, ...args: unknown[]): void {\r\n\t\tconst configurationService = accessor.get(IConfigurationService);\r\n\t\tconst newValue = !configurationService.getValue<boolean>('diffEditor.useInlineViewWhenSpaceIsLimited');\r\n\t\tconfigurationService.updateValue('diffEditor.useInlineViewWhenSpaceIsLimited', newValue);\r\n\t}\r\n}\r\n\r\nregisterAction2(ToggleUseInlineViewWhenSpaceIsLimited);\r\n\r\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\r\n\tcommand: {\r\n\t\tid: new ToggleUseInlineViewWhenSpaceIsLimited().desc.id,\r\n\t\ttitle: localize('useInlineViewWhenSpaceIsLimited', \"Use Inline View When Space Is Limited\"),\r\n\t\ttoggled: ContextKeyExpr.has('config.diffEditor.useInlineViewWhenSpaceIsLimited'),\r\n\t},\r\n\torder: 11,\r\n\tgroup: '1_diff',\r\n\twhen: ContextKeyExpr.and(\r\n\t\tEditorContextKeys.diffEditorRenderSideBySideInlineBreakpointReached,\r\n\t\tContextKeyEqualsExpr.create('diffEditorVersion', 2)\r\n\t)\r\n});\r\n\r\nMenuRegistry.appendMenuItem(MenuId.EditorTitle, {\r\n\tcommand: {\r\n\t\tid: new ToggleShowMovedCodeBlocks().desc.id,\r\n\t\ttitle: localize('showMoves', \"Show Moved Code Blocks\"),\r\n\t\ticon: Codicon.move,\r\n\t\ttoggled: ContextKeyEqualsExpr.create('config.diffEditor.experimental.showMoves', true),\r\n\t},\r\n\torder: 10,\r\n\tgroup: '1_diff',\r\n\twhen: ContextKeyEqualsExpr.create('diffEditorVersion', 2)\r\n});\r\n\r\nconst diffEditorCategory: ILocalizedString = {\r\n\tvalue: localize('diffEditor', 'Diff Editor'),\r\n\toriginal: 'Diff Editor',\r\n};\r\n\r\nexport class SwitchSide extends EditorAction2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.switchSide',\r\n\t\t\ttitle: { value: localize('switchSide', \"Switch Side\"), original: 'Switch Side' },\r\n\t\t\ticon: Codicon.arrowSwap,\r\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\r\n\t\t\tf1: true,\r\n\t\t\tcategory: diffEditorCategory,\r\n\t\t});\r\n\t}\r\n\r\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, arg?: { dryRun: boolean }): unknown {\r\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\r\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\r\n\t\t\tif (arg && arg.dryRun) {\r\n\t\t\t\treturn { destinationSelection: diffEditor.mapToOtherSide().destinationSelection };\r\n\t\t\t} else {\r\n\t\t\t\tdiffEditor.switchSide();\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn undefined;\r\n\t}\r\n}\r\n\r\nregisterAction2(SwitchSide);\r\n\r\n<<<<<<< HEAD\r\nexport class CollapseAllUnchangedRegions extends EditorAction2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.collapseAllUnchangedRegions',\r\n\t\t\ttitle: { value: localize('collapseAllUnchangedRegions', \"Collapse All Unchanged Regions\"), original: 'Collapse All Unchanged Regions' },\r\n\t\t\ticon: Codicon.fold,\r\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\r\n\t\t\tf1: true,\r\n\t\t\tcategory: diffEditorCategory,\r\n=======\r\nexport class ExitCompareMove extends EditorAction2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.exitCompareMove',\r\n\t\t\ttitle: { value: localize('exitCompareMove', \"Exit Compare Move\"), original: 'Exit Compare Move' },\r\n\t\t\ticon: Codicon.close,\r\n\t\t\tprecondition: EditorContextKeys.comparingMovedCode,\r\n\t\t\tf1: false,\r\n\t\t\tcategory: diffEditorCategory,\r\n\t\t\tkeybinding: {\r\n\t\t\t\tweight: 10000,\r\n\t\t\t\tprimary: KeyCode.Escape,\r\n\t\t\t}\r\n>>>>>>> main\r\n\t\t});\r\n\t}\r\n\r\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\r\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\r\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\r\n<<<<<<< HEAD\r\n\t\t\tdiffEditor.collapseAllUnchangedRegions();\r\n=======\r\n\t\t\tdiffEditor.exitCompareMove();\r\n>>>>>>> main\r\n\t\t}\r\n\t}\r\n}\r\n\r\n<<<<<<< HEAD\r\nregisterAction2(CollapseAllUnchangedRegions);\r\n\r\nexport class ShowAllUnchangedRegions extends EditorAction2 {\r\n\tconstructor() {\r\n\t\tsuper({\r\n\t\t\tid: 'diffEditor.showAllUnchangedRegions',\r\n\t\t\ttitle: { value: localize('showAllUnchangedRegions', \"Show All Unchanged Regions\"), original: 'Show All Unchanged Regions' },\r\n\t\t\ticon: Codicon.unfold,\r\n\t\t\tprecondition: ContextKeyExpr.and(ContextKeyEqualsExpr.create('diffEditorVersion', 2), ContextKeyExpr.has('isInDiffEditor')),\r\n\t\t\tf1: true,\r\n\t\t\tcategory: diffEditorCategory,\r\n\t\t});\r\n\t}\r\n\r\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: unknown[]): void {\r\n\t\tconst diffEditor = findFocusedDiffEditor(accessor);\r\n\t\tif (diffEditor instanceof DiffEditorWidget2) {\r\n\t\t\tdiffEditor.showAllUnchangedRegions();\r\n\t\t}\r\n\t}\r\n}\r\n\r\nregisterAction2(ShowAllUnchangedRegions);\r\n=======\r\nregisterAction2(ExitCompareMove);\r\n>>>>>>> main\r\n"
}

The right diff is also tough though.