From da33fe42cda07dbbe64fad2ebe5f0537bbffec8b Mon Sep 17 00:00:00 2001 From: Henning Dieterichs Date: Fri, 6 Oct 2023 11:11:19 +0200 Subject: [PATCH] Adds moved code tests --- .../editor/test/node/diffing/fixtures.test.ts | 4 +- .../advanced.expected.diff.json | 108 ++++ .../advanced.invalid.diff.json | 116 ++++ .../advanced.expected.diff.json | 26 + .../difficult-move/advanced.invalid.diff.json | 52 ++ .../indentation/advanced.expected.diff.json | 62 ++ .../indentation/advanced.invalid.diff.json | 84 +++ .../issue-185779/advanced.expected.diff.json | 42 ++ .../issue-185779/advanced.invalid.diff.json | 46 ++ .../move-1/advanced.expected.diff.json | 18 + .../move-1/advanced.invalid.diff.json | 32 + .../node/diffing/fixtures/noisy-move1/1.tst | 544 +++++++++++++++++ .../node/diffing/fixtures/noisy-move1/2.tst | 565 ++++++++++++++++++ .../noisy-move1/advanced.expected.diff.json | 316 ++++++++++ .../noisy-move1/advanced.invalid.diff.json | 0 .../noisy-move1/legacy.expected.diff.json | 178 ++++++ .../noisy-move1/legacy.invalid.diff.json | 0 17 files changed, 2191 insertions(+), 2 deletions(-) create mode 100644 src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.invalid.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.invalid.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/indentation/advanced.invalid.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.invalid.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/move-1/advanced.invalid.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/noisy-move1/1.tst create mode 100644 src/vs/editor/test/node/diffing/fixtures/noisy-move1/2.tst create mode 100644 src/vs/editor/test/node/diffing/fixtures/noisy-move1/advanced.expected.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/noisy-move1/advanced.invalid.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/noisy-move1/legacy.expected.diff.json create mode 100644 src/vs/editor/test/node/diffing/fixtures/noisy-move1/legacy.invalid.diff.json diff --git a/src/vs/editor/test/node/diffing/fixtures.test.ts b/src/vs/editor/test/node/diffing/fixtures.test.ts index 18a949c6538..958efb30027 100644 --- a/src/vs/editor/test/node/diffing/fixtures.test.ts +++ b/src/vs/editor/test/node/diffing/fixtures.test.ts @@ -42,7 +42,7 @@ suite('diffing fixtures', () => { const diffingAlgo = diffingAlgoName === 'legacy' ? new LegacyLinesDiffComputer() : new DefaultLinesDiffComputer(); const ignoreTrimWhitespace = folder.indexOf('trimws') >= 0; - const diff = diffingAlgo.computeDiff(firstContentLines, secondContentLines, { ignoreTrimWhitespace, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, computeMoves: false }); + const diff = diffingAlgo.computeDiff(firstContentLines, secondContentLines, { ignoreTrimWhitespace, maxComputationTimeMs: Number.MAX_SAFE_INTEGER, computeMoves: true }); function getDiffs(changes: readonly DetailedLineRangeMapping[]): IDetailedDiff[] { return changes.map(c => ({ @@ -155,5 +155,5 @@ interface IMoveInfo { originalRange: string; // [startLineNumber, endLineNumberExclusive) modifiedRange: string; // [startLineNumber, endLineNumberExclusive) - changes?: IDetailedDiff[]; + changes: IDetailedDiff[]; } diff --git a/src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.expected.diff.json index 85083dedd28..76e1b71ab6f 100644 --- a/src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.expected.diff.json @@ -112,5 +112,113 @@ } ] } + ], + "moves": [ + { + "originalRange": "[73,96)", + "modifiedRange": "[75,98)", + "changes": [ + { + "originalRange": "[73,85)", + "modifiedRange": "[75,87)", + "innerChanges": [ + { + "originalRange": "[73,1 -> 73,1]", + "modifiedRange": "[75,1 -> 75,2]" + }, + { + "originalRange": "[74,1 -> 74,1]", + "modifiedRange": "[76,1 -> 76,2]" + }, + { + "originalRange": "[75,1 -> 75,1]", + "modifiedRange": "[77,1 -> 77,2]" + }, + { + "originalRange": "[76,1 -> 76,1]", + "modifiedRange": "[78,1 -> 78,2]" + }, + { + "originalRange": "[77,1 -> 77,1]", + "modifiedRange": "[79,1 -> 79,2]" + }, + { + "originalRange": "[78,1 -> 78,1]", + "modifiedRange": "[80,1 -> 80,2]" + }, + { + "originalRange": "[79,1 -> 79,1]", + "modifiedRange": "[81,1 -> 81,2]" + }, + { + "originalRange": "[80,1 -> 80,1]", + "modifiedRange": "[82,1 -> 82,2]" + }, + { + "originalRange": "[81,1 -> 81,1]", + "modifiedRange": "[83,1 -> 83,2]" + }, + { + "originalRange": "[82,1 -> 82,1]", + "modifiedRange": "[84,1 -> 84,2]" + }, + { + "originalRange": "[83,1 -> 83,1]", + "modifiedRange": "[85,1 -> 85,2]" + }, + { + "originalRange": "[84,1 -> 84,1]", + "modifiedRange": "[86,1 -> 86,2]" + } + ] + }, + { + "originalRange": "[86,96)", + "modifiedRange": "[88,98)", + "innerChanges": [ + { + "originalRange": "[86,1 -> 86,1]", + "modifiedRange": "[88,1 -> 88,2]" + }, + { + "originalRange": "[87,1 -> 87,1]", + "modifiedRange": "[89,1 -> 89,2]" + }, + { + "originalRange": "[88,1 -> 88,1]", + "modifiedRange": "[90,1 -> 90,2]" + }, + { + "originalRange": "[89,1 -> 89,1]", + "modifiedRange": "[91,1 -> 91,2]" + }, + { + "originalRange": "[90,1 -> 90,1]", + "modifiedRange": "[92,1 -> 92,2]" + }, + { + "originalRange": "[91,1 -> 91,1]", + "modifiedRange": "[93,1 -> 93,2]" + }, + { + "originalRange": "[92,1 -> 92,1]", + "modifiedRange": "[94,1 -> 94,2]" + }, + { + "originalRange": "[93,1 -> 93,1]", + "modifiedRange": "[95,1 -> 95,2]" + }, + { + "originalRange": "[94,1 -> 94,1]", + "modifiedRange": "[96,1 -> 96,2]" + }, + { + "originalRange": "[95,1 -> 95,1]", + "modifiedRange": "[97,1 -> 97,2]" + } + ] + } + ] + } ] } \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.invalid.diff.json b/src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.invalid.diff.json new file mode 100644 index 00000000000..85083dedd28 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/bracket-aligning/advanced.invalid.diff.json @@ -0,0 +1,116 @@ +{ + "original": { + "content": "/*---------------------------------------------------------------------------------------------\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 { CompareResult } from 'vs/base/common/arrays';\nimport { autorun, derived } from 'vs/base/common/observable';\nimport { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model';\nimport { localize } from 'vs/nls';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';\nimport { applyObservableDecorations, join } from 'vs/workbench/contrib/mergeEditor/browser/utils';\nimport { handledConflictMinimapOverViewRulerColor, unhandledConflictMinimapOverViewRulerColor } from 'vs/workbench/contrib/mergeEditor/browser/view/colors';\nimport { CodeEditorView } from './codeEditorView';\n\nexport class ResultCodeEditorView extends CodeEditorView {\n\tprivate readonly decorations = derived('result.decorations', reader => {\n\t\tconst viewModel = this.viewModel.read(reader);\n\t\tif (!viewModel) {\n\t\t\treturn [];\n\t\t}\n\t\tconst model = viewModel.model;\n\t\tconst result = new Array();\n\n\t\tconst baseRangeWithStoreAndTouchingDiffs = join(\n\t\t\tmodel.modifiedBaseRanges.read(reader),\n\t\t\tmodel.resultDiffs.read(reader),\n\t\t\t(baseRange, diff) => baseRange.baseRange.touches(diff.inputRange)\n\t\t\t\t? CompareResult.neitherLessOrGreaterThan\n\t\t\t\t: LineRange.compareByStart(\n\t\t\t\t\tbaseRange.baseRange,\n\t\t\t\t\tdiff.inputRange\n\t\t\t\t)\n\t\t);\n\n\t\tconst activeModifiedBaseRange = viewModel.activeModifiedBaseRange.read(reader);\n\n\t\tfor (const m of baseRangeWithStoreAndTouchingDiffs) {\n\t\t\tconst modifiedBaseRange = m.left;\n\n\t\t\tif (modifiedBaseRange) {\n\t\t\t\tconst range = model.getRangeInResult(modifiedBaseRange.baseRange, reader).toInclusiveRange();\n\t\t\t\tif (range) {\n\t\t\t\t\tconst blockClassNames = ['merge-editor-block'];\n\t\t\t\t\tconst isHandled = model.isHandled(modifiedBaseRange).read(reader);\n\t\t\t\t\tif (isHandled) {\n\t\t\t\t\t\tblockClassNames.push('handled');\n\t\t\t\t\t}\n\t\t\t\t\tif (modifiedBaseRange === activeModifiedBaseRange) {\n\t\t\t\t\t\tblockClassNames.push('focused');\n\t\t\t\t\t}\n\t\t\t\t\tblockClassNames.push('result');\n\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\trange,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tisWholeLine: true,\n\t\t\t\t\t\t\tblockClassName: blockClassNames.join(' '),\n\t\t\t\t\t\t\tdescription: 'Result Diff',\n\t\t\t\t\t\t\tminimap: {\n\t\t\t\t\t\t\t\tposition: MinimapPosition.Gutter,\n\t\t\t\t\t\t\t\tcolor: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\toverviewRuler: {\n\t\t\t\t\t\t\t\tposition: OverviewRulerLane.Center,\n\t\t\t\t\t\t\t\tcolor: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const diff of m.rights) {\n\t\t\t\tconst range = diff.outputRange.toInclusiveRange();\n\t\t\t\tif (range) {\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\trange,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tclassName: `merge-editor-diff result`,\n\t\t\t\t\t\t\tdescription: 'Merge Editor',\n\t\t\t\t\t\t\tisWholeLine: true,\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (diff.rangeMappings) {\n\t\t\t\t\tfor (const d of diff.rangeMappings) {\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\trange: d.outputRange,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclassName: `merge-editor-diff-word result`,\n\t\t\t\t\t\t\t\tdescription: 'Merge Editor'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t});\n\n\tconstructor(\n\t\t@IInstantiationService instantiationService: IInstantiationService\n\t) {\n\t\tsuper(instantiationService);\n\n\t\tthis._register(applyObservableDecorations(this.editor, this.decorations));\n\n\n\t\tthis._register(autorun('update remainingConflicts label', reader => {\n\t\t\tconst model = this.model.read(reader);\n\t\t\tif (!model) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst count = model.unhandledConflictsCount.read(reader);\n\n\t\t\tthis.htmlElements.detail.innerText = count === 1\n\t\t\t\t? localize(\n\t\t\t\t\t'mergeEditor.remainingConflicts',\n\t\t\t\t\t'{0} Conflict Remaining',\n\t\t\t\t\tcount\n\t\t\t\t)\n\t\t\t\t: localize(\n\t\t\t\t\t'mergeEditor.remainingConflict',\n\t\t\t\t\t'{0} Conflicts Remaining ',\n\t\t\t\t\tcount\n\t\t\t\t);\n\n\t\t}));\n\t}\n}\n", + "fileName": "./1.tst" + }, + "modified": { + "content": "/*---------------------------------------------------------------------------------------------\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 { CompareResult } from 'vs/base/common/arrays';\nimport { autorun, derived } from 'vs/base/common/observable';\nimport { IModelDeltaDecoration, MinimapPosition, OverviewRulerLane } from 'vs/editor/common/model';\nimport { localize } from 'vs/nls';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';\nimport { applyObservableDecorations, join } from 'vs/workbench/contrib/mergeEditor/browser/utils';\nimport { handledConflictMinimapOverViewRulerColor, unhandledConflictMinimapOverViewRulerColor } from 'vs/workbench/contrib/mergeEditor/browser/view/colors';\nimport { CodeEditorView } from './codeEditorView';\n\nexport class ResultCodeEditorView extends CodeEditorView {\n\tprivate readonly decorations = derived('result.decorations', reader => {\n\t\tconst viewModel = this.viewModel.read(reader);\n\t\tif (!viewModel) {\n\t\t\treturn [];\n\t\t}\n\t\tconst model = viewModel.model;\n\t\tconst result = new Array();\n\n\t\tconst baseRangeWithStoreAndTouchingDiffs = join(\n\t\t\tmodel.modifiedBaseRanges.read(reader),\n\t\t\tmodel.resultDiffs.read(reader),\n\t\t\t(baseRange, diff) => baseRange.baseRange.touches(diff.inputRange)\n\t\t\t\t? CompareResult.neitherLessOrGreaterThan\n\t\t\t\t: LineRange.compareByStart(\n\t\t\t\t\tbaseRange.baseRange,\n\t\t\t\t\tdiff.inputRange\n\t\t\t\t)\n\t\t);\n\n\t\tconst activeModifiedBaseRange = viewModel.activeModifiedBaseRange.read(reader);\n\n\t\tfor (const m of baseRangeWithStoreAndTouchingDiffs) {\n\t\t\tconst modifiedBaseRange = m.left;\n\n\t\t\tif (modifiedBaseRange) {\n\t\t\t\tconst range = model.getRangeInResult(modifiedBaseRange.baseRange, reader).toInclusiveRange();\n\t\t\t\tif (range) {\n\t\t\t\t\tconst blockClassNames = ['merge-editor-block'];\n\t\t\t\t\tconst isHandled = model.isHandled(modifiedBaseRange).read(reader);\n\t\t\t\t\tif (isHandled) {\n\t\t\t\t\t\tblockClassNames.push('handled');\n\t\t\t\t\t}\n\t\t\t\t\tif (modifiedBaseRange === activeModifiedBaseRange) {\n\t\t\t\t\t\tblockClassNames.push('focused');\n\t\t\t\t\t}\n\t\t\t\t\tblockClassNames.push('result');\n\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\trange,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tisWholeLine: true,\n\t\t\t\t\t\t\tblockClassName: blockClassNames.join(' '),\n\t\t\t\t\t\t\tdescription: 'Result Diff',\n\t\t\t\t\t\t\tminimap: {\n\t\t\t\t\t\t\t\tposition: MinimapPosition.Gutter,\n\t\t\t\t\t\t\t\tcolor: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\toverviewRuler: {\n\t\t\t\t\t\t\t\tposition: OverviewRulerLane.Center,\n\t\t\t\t\t\t\t\tcolor: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor },\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tif (!modifiedBaseRange || modifiedBaseRange.isConflicting) {\n\t\t\t\tfor (const diff of m.rights) {\n\t\t\t\t\tconst range = diff.outputRange.toInclusiveRange();\n\t\t\t\t\tif (range) {\n\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\trange,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tclassName: `merge-editor-diff result`,\n\t\t\t\t\t\t\t\tdescription: 'Merge Editor',\n\t\t\t\t\t\t\t\tisWholeLine: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tif (diff.rangeMappings) {\n\t\t\t\t\t\tfor (const d of diff.rangeMappings) {\n\t\t\t\t\t\t\tresult.push({\n\t\t\t\t\t\t\t\trange: d.outputRange,\n\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\tclassName: `merge-editor-diff-word result`,\n\t\t\t\t\t\t\t\t\tdescription: 'Merge Editor'\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t});\n\n\tconstructor(\n\t\t@IInstantiationService instantiationService: IInstantiationService\n\t) {\n\t\tsuper(instantiationService);\n\n\t\tthis._register(applyObservableDecorations(this.editor, this.decorations));\n\n\n\t\tthis._register(autorun('update remainingConflicts label', reader => {\n\t\t\tconst model = this.model.read(reader);\n\t\t\tif (!model) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst count = model.unhandledConflictsCount.read(reader);\n\n\t\t\tthis.htmlElements.detail.innerText = count === 1\n\t\t\t\t? localize(\n\t\t\t\t\t'mergeEditor.remainingConflicts',\n\t\t\t\t\t'{0} Conflict Remaining',\n\t\t\t\t\tcount\n\t\t\t\t)\n\t\t\t\t: localize(\n\t\t\t\t\t'mergeEditor.remainingConflict',\n\t\t\t\t\t'{0} Conflicts Remaining ',\n\t\t\t\t\tcount\n\t\t\t\t);\n\n\t\t}));\n\t}\n}\n", + "fileName": "./2.tst" + }, + "diffs": [ + { + "originalRange": "[73,85)", + "modifiedRange": "[73,87)", + "innerChanges": [ + { + "originalRange": "[73,1 -> 73,1]", + "modifiedRange": "[73,1 -> 75,1]" + }, + { + "originalRange": "[73,1 -> 73,1]", + "modifiedRange": "[75,1 -> 75,2]" + }, + { + "originalRange": "[74,1 -> 74,1]", + "modifiedRange": "[76,1 -> 76,2]" + }, + { + "originalRange": "[75,1 -> 75,1]", + "modifiedRange": "[77,1 -> 77,2]" + }, + { + "originalRange": "[76,1 -> 76,1]", + "modifiedRange": "[78,1 -> 78,2]" + }, + { + "originalRange": "[77,1 -> 77,1]", + "modifiedRange": "[79,1 -> 79,2]" + }, + { + "originalRange": "[78,1 -> 78,1]", + "modifiedRange": "[80,1 -> 80,2]" + }, + { + "originalRange": "[79,1 -> 79,1]", + "modifiedRange": "[81,1 -> 81,2]" + }, + { + "originalRange": "[80,1 -> 80,1]", + "modifiedRange": "[82,1 -> 82,2]" + }, + { + "originalRange": "[81,1 -> 81,1]", + "modifiedRange": "[83,1 -> 83,2]" + }, + { + "originalRange": "[82,1 -> 82,1]", + "modifiedRange": "[84,1 -> 84,2]" + }, + { + "originalRange": "[83,1 -> 83,1]", + "modifiedRange": "[85,1 -> 85,2]" + }, + { + "originalRange": "[84,1 -> 84,1]", + "modifiedRange": "[86,1 -> 86,2]" + } + ] + }, + { + "originalRange": "[86,95)", + "modifiedRange": "[88,98)", + "innerChanges": [ + { + "originalRange": "[86,1 -> 86,1]", + "modifiedRange": "[88,1 -> 88,2]" + }, + { + "originalRange": "[87,1 -> 87,1]", + "modifiedRange": "[89,1 -> 89,2]" + }, + { + "originalRange": "[88,1 -> 88,1]", + "modifiedRange": "[90,1 -> 90,2]" + }, + { + "originalRange": "[89,1 -> 89,1]", + "modifiedRange": "[91,1 -> 91,2]" + }, + { + "originalRange": "[90,1 -> 90,1]", + "modifiedRange": "[92,1 -> 92,2]" + }, + { + "originalRange": "[91,1 -> 91,1]", + "modifiedRange": "[93,1 -> 93,2]" + }, + { + "originalRange": "[92,1 -> 92,1]", + "modifiedRange": "[94,1 -> 94,2]" + }, + { + "originalRange": "[93,1 -> 93,1]", + "modifiedRange": "[95,1 -> 95,2]" + }, + { + "originalRange": "[94,1 -> 94,1]", + "modifiedRange": "[96,1 -> 96,2]" + }, + { + "originalRange": "[95,1 -> 95,1]", + "modifiedRange": "[97,1 -> 98,1]" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.expected.diff.json index 7686d146b16..372deb16284 100644 --- a/src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.expected.diff.json @@ -48,5 +48,31 @@ } ] } + ], + "moves": [ + { + "originalRange": "[223,226)", + "modifiedRange": "[158,161)", + "changes": [ + { + "originalRange": "[223,226)", + "modifiedRange": "[158,161)", + "innerChanges": [ + { + "originalRange": "[223,1 -> 223,3]", + "modifiedRange": "[158,1 -> 158,1]" + }, + { + "originalRange": "[224,1 -> 224,3]", + "modifiedRange": "[159,1 -> 159,1]" + }, + { + "originalRange": "[225,1 -> 225,3]", + "modifiedRange": "[160,1 -> 160,1]" + } + ] + } + ] + } ] } \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.invalid.diff.json b/src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.invalid.diff.json new file mode 100644 index 00000000000..7686d146b16 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/difficult-move/advanced.invalid.diff.json @@ -0,0 +1,52 @@ +{ + "original": { + "content": "/*---------------------------------------------------------------------------------------------\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\n'use strict';\n\nconst gulp = require('gulp');\nconst path = require('path');\nconst es = require('event-stream');\nconst util = require('./lib/util');\nconst { getVersion } = require('./lib/getVersion');\nconst task = require('./lib/task');\nconst optimize = require('./lib/optimize');\nconst product = require('../product.json');\nconst rename = require('gulp-rename');\nconst replace = require('gulp-replace');\nconst filter = require('gulp-filter');\nconst { getProductionDependencies } = require('./lib/dependencies');\nconst vfs = require('vinyl-fs');\nconst packageJson = require('../package.json');\nconst flatmap = require('gulp-flatmap');\nconst gunzip = require('gulp-gunzip');\nconst File = require('vinyl');\nconst fs = require('fs');\nconst glob = require('glob');\nconst { compileBuildTask } = require('./gulpfile.compile');\nconst { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions');\nconst { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileContentMapper } = require('./gulpfile.vscode.web');\nconst cp = require('child_process');\nconst log = require('fancy-log');\n\nconst REPO_ROOT = path.dirname(__dirname);\nconst commit = getVersion(REPO_ROOT);\nconst BUILD_ROOT = path.dirname(REPO_ROOT);\nconst REMOTE_FOLDER = path.join(REPO_ROOT, 'remote');\n\n// Targets\n\nconst BUILD_TARGETS = [\n\t{ platform: 'win32', arch: 'ia32' },\n\t{ platform: 'win32', arch: 'x64' },\n\t{ platform: 'darwin', arch: 'x64' },\n\t{ platform: 'darwin', arch: 'arm64' },\n\t{ platform: 'linux', arch: 'x64' },\n\t{ platform: 'linux', arch: 'armhf' },\n\t{ platform: 'linux', arch: 'arm64' },\n\t{ platform: 'alpine', arch: 'arm64' },\n\t// legacy: we use to ship only one alpine so it was put in the arch, but now we ship\n\t// multiple alpine images and moved to a better model (alpine as the platform)\n\t{ platform: 'linux', arch: 'alpine' },\n];\n\nconst serverResources = [\n\n\t// Bootstrap\n\t'out-build/bootstrap.js',\n\t'out-build/bootstrap-fork.js',\n\t'out-build/bootstrap-amd.js',\n\t'out-build/bootstrap-node.js',\n\n\t// Performance\n\t'out-build/vs/base/common/performance.js',\n\n\t// Watcher\n\t'out-build/vs/platform/files/**/*.exe',\n\t'out-build/vs/platform/files/**/*.md',\n\n\t// Process monitor\n\t'out-build/vs/base/node/cpuUsage.sh',\n\t'out-build/vs/base/node/ps.sh',\n\n\t// Terminal shell integration\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-env.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-profile.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish',\n\n\t'!**/test/**'\n];\n\nconst serverWithWebResources = [\n\n\t// Include all of server...\n\t...serverResources,\n\n\t// ...and all of web\n\t...vscodeWebResourceIncludes\n];\n\nconst serverEntryPoints = [\n\t{\n\t\tname: 'vs/server/node/server.main',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/server/node/server.cli',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/workbench/api/node/extensionHostProcess',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/platform/files/node/watcher/watcherMain',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/platform/terminal/node/ptyHostMain',\n\t\texclude: ['vs/css', 'vs/nls']\n\t}\n];\n\nconst serverWithWebEntryPoints = [\n\n\t// Include all of server\n\t...serverEntryPoints,\n\n\t// Include workbench web\n\t...vscodeWebEntryPoints\n];\n\nfunction getNodeVersion() {\n\tconst yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8');\n\tconst nodeVersion = /^target \"(.*)\"$/m.exec(yarnrc)[1];\n\tconst internalNodeVersion = /^ms_build_id \"(.*)\"$/m.exec(yarnrc)[1];\n\treturn { nodeVersion, internalNodeVersion };\n}\n\nfunction getNodeChecksum(nodeVersion, platform, arch) {\n\tlet expectedName;\n\tswitch (platform) {\n\t\tcase 'win32':\n\t\t\texpectedName = `win-${arch}/node.exe`;\n\t\t\tbreak;\n\n\t\tcase 'darwin':\n\t\tcase 'linux':\n\t\t\texpectedName = `node-v${nodeVersion}-${platform}-${arch}.tar.gz`;\n\t\t\tbreak;\n\n\t\tcase 'alpine':\n\t\t\texpectedName = `${platform}-${arch}/node`;\n\t\t\tbreak;\n\t}\n\n\tconst nodeJsChecksums = fs.readFileSync(path.join(REPO_ROOT, 'build', 'checksums', 'nodejs.txt'), 'utf8');\n\tfor (const line of nodeJsChecksums.split('\\n')) {\n\t\tconst [checksum, name] = line.split(/\\s+/);\n\t\tif (name === expectedName) {\n\t\t\treturn checksum;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nconst { nodeVersion, internalNodeVersion } = getNodeVersion();\n\nBUILD_TARGETS.forEach(({ platform, arch }) => {\n\tgulp.task(task.define(`node-${platform}-${arch}`, () => {\n\t\tconst nodePath = path.join('.build', 'node', `v${nodeVersion}`, `${platform}-${arch}`);\n\n\t\tif (!fs.existsSync(nodePath)) {\n\t\t\tutil.rimraf(nodePath);\n\n\t\t\treturn nodejs(platform, arch)\n\t\t\t\t.pipe(vfs.dest(nodePath));\n\t\t}\n\n\t\treturn Promise.resolve(null);\n\t}));\n});\n\nconst defaultNodeTask = gulp.task(`node-${process.platform}-${process.arch}`);\n\nif (defaultNodeTask) {\n\tgulp.task(task.define('node', defaultNodeTask));\n}\n\nfunction nodejs(platform, arch) {\n\tconst { fetchUrls, fetchGithub } = require('./lib/fetch');\n\tconst untar = require('gulp-untar');\n\tconst crypto = require('crypto');\n\n\tif (arch === 'ia32') {\n\t\tarch = 'x86';\n\t} else if (arch === 'armhf') {\n\t\tarch = 'armv7l';\n\t} else if (arch === 'alpine') {\n\t\tplatform = 'alpine';\n\t\tarch = 'x64';\n\t}\n\n\tlog(`Downloading node.js ${nodeVersion} ${platform} ${arch} from ${product.nodejsRepository}...`);\n\n\tconst checksumSha256 = getNodeChecksum(nodeVersion, platform, arch);\n\n\tif (checksumSha256) {\n\t\tlog(`Using SHA256 checksum for checking integrity: ${checksumSha256}`);\n\t} else {\n\t\tlog.warn(`Unable to verify integrity of downloaded node.js binary because no SHA256 checksum was found!`);\n\t}\n\n\tswitch (platform) {\n\t\tcase 'win32':\n\t\t\treturn (product.nodejsRepository !== 'https://nodejs.org' ?\n\t\t\t\tfetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: `win-${arch}-node.exe`, checksumSha256 }) :\n\t\t\t\tfetchUrls(`/dist/v${nodeVersion}/win-${arch}/node.exe`, { base: 'https://nodejs.org', checksumSha256 }))\n\t\t\t\t.pipe(rename('node.exe'));\n\t\tcase 'darwin':\n\t\tcase 'linux':\n\t\t\treturn (product.nodejsRepository !== 'https://nodejs.org' ?\n\t\t\t\tfetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: `node-v${nodeVersion}-${platform}-${arch}.tar.gz`, checksumSha256 }) :\n\t\t\t\tfetchUrls(`/dist/v${nodeVersion}/node-v${nodeVersion}-${platform}-${arch}.tar.gz`, { base: 'https://nodejs.org', checksumSha256 })\n\t\t\t).pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar())))\n\t\t\t\t.pipe(filter('**/node'))\n\t\t\t\t.pipe(util.setExecutableBit('**'))\n\t\t\t\t.pipe(rename('node'));\n\t\tcase 'alpine': {\n\t\t\tconst imageName = arch === 'arm64' ? 'arm64v8/node' : 'node';\n\t\t\tlog(`Downloading node.js ${nodeVersion} ${platform} ${arch} from docker image ${imageName}`);\n\t\t\tconst contents = cp.execSync(`docker run --rm ${imageName}:${nodeVersion}-alpine /bin/sh -c 'cat \\`which node\\`'`, { maxBuffer: 100 * 1024 * 1024, encoding: 'buffer' });\n\t\t\tif (checksumSha256) {\n\t\t\t\tconst actualSHA256Checksum = crypto.createHash('sha256').update(contents).digest('hex');\n\t\t\t\tif (actualSHA256Checksum !== checksumSha256) {\n\t\t\t\t\tthrow new Error(`Checksum mismatch for node.js from docker image (expected ${options.checksumSha256}, actual ${actualSHA256Checksum}))`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn es.readArray([new File({ path: 'node', contents, stat: { mode: parseInt('755', 8) } })]);\n\t\t}\n\t}\n}\n\nfunction packageTask(type, platform, arch, sourceFolderName, destinationFolderName) {\n\tconst destination = path.join(BUILD_ROOT, destinationFolderName);\n\n\treturn () => {\n\t\tconst json = require('gulp-json-editor');\n\n\t\tconst src = gulp.src(sourceFolderName + '/**', { base: '.' })\n\t\t\t.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); }))\n\t\t\t.pipe(util.setExecutableBit(['**/*.sh']))\n\t\t\t.pipe(filter(['**', '!**/*.js.map']));\n\n\t\tconst workspaceExtensionPoints = ['debuggers', 'jsonValidation'];\n\t\tconst isUIExtension = (manifest) => {\n\t\t\tswitch (manifest.extensionKind) {\n\t\t\t\tcase 'ui': return true;\n\t\t\t\tcase 'workspace': return false;\n\t\t\t\tdefault: {\n\t\t\t\t\tif (manifest.main) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (manifest.contributes && Object.keys(manifest.contributes).some(key => workspaceExtensionPoints.indexOf(key) !== -1)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Default is UI Extension\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tconst localWorkspaceExtensions = glob.sync('extensions/*/package.json')\n\t\t\t.filter((extensionPath) => {\n\t\t\t\tif (type === 'reh-web') {\n\t\t\t\t\treturn true; // web: ship all extensions for now\n\t\t\t\t}\n\n\t\t\t\t// Skip shipping UI extensions because the client side will have them anyways\n\t\t\t\t// and they'd just increase the download without being used\n\t\t\t\tconst manifest = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, extensionPath)).toString());\n\t\t\t\treturn !isUIExtension(manifest);\n\t\t\t}).map((extensionPath) => path.basename(path.dirname(extensionPath)))\n\t\t\t.filter(name => name !== 'vscode-api-tests' && name !== 'vscode-test-resolver'); // Do not ship the test extensions\n\t\tconst marketplaceExtensions = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'product.json'), 'utf8')).builtInExtensions\n\t\t\t.filter(entry => !entry.platforms || new Set(entry.platforms).has(platform))\n\t\t\t.filter(entry => !entry.clientOnly)\n\t\t\t.map(entry => entry.name);\n\t\tconst extensionPaths = [...localWorkspaceExtensions, ...marketplaceExtensions]\n\t\t\t.map(name => `.build/extensions/${name}/**`);\n\n\t\tconst extensions = gulp.src(extensionPaths, { base: '.build', dot: true });\n\t\tconst extensionsCommonDependencies = gulp.src('.build/extensions/node_modules/**', { base: '.build', dot: true });\n\t\tconst sources = es.merge(src, extensions, extensionsCommonDependencies)\n\t\t\t.pipe(filter(['**', '!**/*.js.map'], { dot: true }));\n\n\t\tlet version = packageJson.version;\n\t\tconst quality = product.quality;\n\n\t\tif (quality && quality !== 'stable') {\n\t\t\tversion += '-' + quality;\n\t\t}\n\n\t\tconst name = product.nameShort;\n\t\tconst packageJsonStream = gulp.src(['remote/package.json'], { base: 'remote' })\n\t\t\t.pipe(json({ name, version, dependencies: undefined, optionalDependencies: undefined }));\n\n\t\tconst date = new Date().toISOString();\n\n\t\tconst productJsonStream = gulp.src(['product.json'], { base: '.' })\n\t\t\t.pipe(json({ commit, date, version }));\n\n\t\tconst license = gulp.src(['remote/LICENSE'], { base: 'remote', allowEmpty: true });\n\n\t\tconst jsFilter = util.filter(data => !data.isDirectory() && /\\.js$/.test(data.path));\n\n\t\tconst productionDependencies = getProductionDependencies(REMOTE_FOLDER);\n\t\tconst dependenciesSrc = productionDependencies.map(d => path.relative(REPO_ROOT, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`]).flat();\n\t\tconst deps = gulp.src(dependenciesSrc, { base: 'remote', dot: true })\n\t\t\t// filter out unnecessary files, no source maps in server build\n\t\t\t.pipe(filter(['**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.js.map']))\n\t\t\t.pipe(util.cleanNodeModules(path.join(__dirname, '.moduleignore')))\n\t\t\t.pipe(util.cleanNodeModules(path.join(__dirname, `.moduleignore.${process.platform}`)))\n\t\t\t.pipe(jsFilter)\n\t\t\t.pipe(util.stripSourceMappingURL())\n\t\t\t.pipe(jsFilter.restore);\n\n\t\tconst nodePath = `.build/node/v${nodeVersion}/${platform}-${arch}`;\n\t\tconst node = gulp.src(`${nodePath}/**`, { base: nodePath, dot: true });\n\n\t\tlet web = [];\n\t\tif (type === 'reh-web') {\n\t\t\tweb = [\n\t\t\t\t'resources/server/favicon.ico',\n\t\t\t\t'resources/server/code-192.png',\n\t\t\t\t'resources/server/code-512.png',\n\t\t\t\t'resources/server/manifest.json'\n\t\t\t].map(resource => gulp.src(resource, { base: '.' }).pipe(rename(resource)));\n\t\t}\n\n\t\tconst all = es.merge(\n\t\t\tpackageJsonStream,\n\t\t\tproductJsonStream,\n\t\t\tlicense,\n\t\t\tsources,\n\t\t\tdeps,\n\t\t\tnode,\n\t\t\t...web\n\t\t);\n\n\t\tlet result = all\n\t\t\t.pipe(util.skipDirectories())\n\t\t\t.pipe(util.fixWin32DirectoryPermissions());\n\n\t\tif (platform === 'win32') {\n\t\t\tresult = es.merge(result,\n\t\t\t\tgulp.src('resources/server/bin/remote-cli/code.cmd', { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/remote-cli/${product.applicationName}.cmd`)),\n\t\t\t\tgulp.src('resources/server/bin/helpers/browser.cmd', { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/helpers/browser.cmd`)),\n\t\t\t\tgulp.src('resources/server/bin/code-server.cmd', { base: '.' })\n\t\t\t\t\t.pipe(rename(`bin/${product.serverApplicationName}.cmd`)),\n\t\t\t);\n\t\t} else if (platform === 'linux' || platform === 'alpine' || platform === 'darwin') {\n\t\t\tresult = es.merge(result,\n\t\t\t\tgulp.src(`resources/server/bin/remote-cli/${platform === 'darwin' ? 'code-darwin.sh' : 'code-linux.sh'}`, { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/remote-cli/${product.applicationName}`))\n\t\t\t\t\t.pipe(util.setExecutableBit()),\n\t\t\t\tgulp.src(`resources/server/bin/helpers/${platform === 'darwin' ? 'browser-darwin.sh' : 'browser-linux.sh'}`, { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/helpers/browser.sh`))\n\t\t\t\t\t.pipe(util.setExecutableBit()),\n\t\t\t\tgulp.src(`resources/server/bin/${platform === 'darwin' ? 'code-server-darwin.sh' : 'code-server-linux.sh'}`, { base: '.' })\n\t\t\t\t\t.pipe(rename(`bin/${product.serverApplicationName}`))\n\t\t\t\t\t.pipe(util.setExecutableBit())\n\t\t\t);\n\t\t}\n\n\t\treturn result.pipe(vfs.dest(destination));\n\t};\n}\n\n/**\n * @param {object} product The parsed product.json file contents\n */\nfunction tweakProductForServerWeb(product) {\n\tconst result = { ...product };\n\tdelete result.webEndpointUrlTemplate;\n\treturn result;\n}\n\n['reh', 'reh-web'].forEach(type => {\n\tconst optimizeTask = task.define(`optimize-vscode-${type}`, task.series(\n\t\tutil.rimraf(`out-vscode-${type}`),\n\t\toptimize.optimizeTask(\n\t\t\t{\n\t\t\t\tout: `out-vscode-${type}`,\n\t\t\t\tamd: {\n\t\t\t\t\tsrc: 'out-build',\n\t\t\t\t\tentryPoints: (type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints).flat(),\n\t\t\t\t\totherSources: [],\n\t\t\t\t\tresources: type === 'reh' ? serverResources : serverWithWebResources,\n\t\t\t\t\tloaderConfig: optimize.loaderConfig(),\n\t\t\t\t\tinlineAmdImages: true,\n\t\t\t\t\tbundleInfo: undefined,\n\t\t\t\t\tfileContentMapper: createVSCodeWebFileContentMapper('.build/extensions', type === 'reh-web' ? tweakProductForServerWeb(product) : product)\n\t\t\t\t},\n\t\t\t\tcommonJS: {\n\t\t\t\t\tsrc: 'out-build',\n\t\t\t\t\tentryPoints: [\n\t\t\t\t\t\t'out-build/server-main.js',\n\t\t\t\t\t\t'out-build/server-cli.js'\n\t\t\t\t\t],\n\t\t\t\t\tplatform: 'node',\n\t\t\t\t\texternal: [\n\t\t\t\t\t\t'minimist',\n\t\t\t\t\t\t// TODO: we cannot inline `product.json` because\n\t\t\t\t\t\t// it is being changed during build time at a later\n\t\t\t\t\t\t// point in time (such as `checksums`)\n\t\t\t\t\t\t'../product.json',\n\t\t\t\t\t\t'../package.json'\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t));\n\n\tconst minifyTask = task.define(`minify-vscode-${type}`, task.series(\n\t\toptimizeTask,\n\t\tutil.rimraf(`out-vscode-${type}-min`),\n\t\toptimize.minifyTask(`out-vscode-${type}`, `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`)\n\t));\n\tgulp.task(minifyTask);\n\n\tBUILD_TARGETS.forEach(buildTarget => {\n\t\tconst dashed = (str) => (str ? `-${str}` : ``);\n\t\tconst platform = buildTarget.platform;\n\t\tconst arch = buildTarget.arch;\n\n\t\t['', 'min'].forEach(minified => {\n\t\t\tconst sourceFolderName = `out-vscode-${type}${dashed(minified)}`;\n\t\t\tconst destinationFolderName = `vscode-${type}${dashed(platform)}${dashed(arch)}`;\n\n\t\t\tconst serverTaskCI = task.define(`vscode-${type}${dashed(platform)}${dashed(arch)}${dashed(minified)}-ci`, task.series(\n\t\t\t\tgulp.task(`node-${platform}-${arch}`),\n\t\t\t\tutil.rimraf(path.join(BUILD_ROOT, destinationFolderName)),\n\t\t\t\tpackageTask(type, platform, arch, sourceFolderName, destinationFolderName)\n\t\t\t));\n\t\t\tgulp.task(serverTaskCI);\n\n\t\t\tconst serverTask = task.define(`vscode-${type}${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(\n\t\t\t\tcompileBuildTask,\n\t\t\t\tcompileExtensionsBuildTask,\n\t\t\t\tcompileExtensionMediaBuildTask,\n\t\t\t\tminified ? minifyTask : optimizeTask,\n\t\t\t\tserverTaskCI\n\t\t\t));\n\t\t\tgulp.task(serverTask);\n\t\t});\n\t});\n});\n", + "fileName": "./1.js" + }, + "modified": { + "content": "/*---------------------------------------------------------------------------------------------\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\n'use strict';\n\nconst gulp = require('gulp');\nconst path = require('path');\nconst es = require('event-stream');\nconst util = require('./lib/util');\nconst { getVersion } = require('./lib/getVersion');\nconst task = require('./lib/task');\nconst optimize = require('./lib/optimize');\nconst product = require('../product.json');\nconst rename = require('gulp-rename');\nconst replace = require('gulp-replace');\nconst filter = require('gulp-filter');\nconst { getProductionDependencies } = require('./lib/dependencies');\nconst vfs = require('vinyl-fs');\nconst packageJson = require('../package.json');\nconst flatmap = require('gulp-flatmap');\nconst gunzip = require('gulp-gunzip');\nconst File = require('vinyl');\nconst fs = require('fs');\nconst glob = require('glob');\nconst { compileBuildTask } = require('./gulpfile.compile');\nconst { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions');\nconst { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileContentMapper } = require('./gulpfile.vscode.web');\nconst cp = require('child_process');\nconst log = require('fancy-log');\n\nconst REPO_ROOT = path.dirname(__dirname);\nconst commit = getVersion(REPO_ROOT);\nconst BUILD_ROOT = path.dirname(REPO_ROOT);\nconst REMOTE_FOLDER = path.join(REPO_ROOT, 'remote');\n\n// Targets\n\nconst BUILD_TARGETS = [\n\t{ platform: 'win32', arch: 'ia32' },\n\t{ platform: 'win32', arch: 'x64' },\n\t{ platform: 'darwin', arch: 'x64' },\n\t{ platform: 'darwin', arch: 'arm64' },\n\t{ platform: 'linux', arch: 'x64' },\n\t{ platform: 'linux', arch: 'armhf' },\n\t{ platform: 'linux', arch: 'arm64' },\n\t{ platform: 'alpine', arch: 'arm64' },\n\t// legacy: we use to ship only one alpine so it was put in the arch, but now we ship\n\t// multiple alpine images and moved to a better model (alpine as the platform)\n\t{ platform: 'linux', arch: 'alpine' },\n];\n\nconst serverResources = [\n\n\t// Bootstrap\n\t'out-build/bootstrap.js',\n\t'out-build/bootstrap-fork.js',\n\t'out-build/bootstrap-amd.js',\n\t'out-build/bootstrap-node.js',\n\n\t// Performance\n\t'out-build/vs/base/common/performance.js',\n\n\t// Watcher\n\t'out-build/vs/platform/files/**/*.exe',\n\t'out-build/vs/platform/files/**/*.md',\n\n\t// Process monitor\n\t'out-build/vs/base/node/cpuUsage.sh',\n\t'out-build/vs/base/node/ps.sh',\n\n\t// Terminal shell integration\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration.ps1',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-env.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-profile.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh',\n\t'out-build/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish',\n\n\t'!**/test/**'\n];\n\nconst serverWithWebResources = [\n\n\t// Include all of server...\n\t...serverResources,\n\n\t// ...and all of web\n\t...vscodeWebResourceIncludes\n];\n\nconst serverEntryPoints = [\n\t{\n\t\tname: 'vs/server/node/server.main',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/server/node/server.cli',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/workbench/api/node/extensionHostProcess',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/platform/files/node/watcher/watcherMain',\n\t\texclude: ['vs/css', 'vs/nls']\n\t},\n\t{\n\t\tname: 'vs/platform/terminal/node/ptyHostMain',\n\t\texclude: ['vs/css', 'vs/nls']\n\t}\n];\n\nconst serverWithWebEntryPoints = [\n\n\t// Include all of server\n\t...serverEntryPoints,\n\n\t// Include workbench web\n\t...vscodeWebEntryPoints\n];\n\nfunction getNodeVersion() {\n\tconst yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8');\n\tconst nodeVersion = /^target \"(.*)\"$/m.exec(yarnrc)[1];\n\tconst internalNodeVersion = /^ms_build_id \"(.*)\"$/m.exec(yarnrc)[1];\n\treturn { nodeVersion, internalNodeVersion };\n}\n\nfunction getNodeChecksum(nodeVersion, platform, arch) {\n\tlet expectedName;\n\tswitch (platform) {\n\t\tcase 'win32':\n\t\t\texpectedName = `win-${arch}/node.exe`;\n\t\t\tbreak;\n\n\t\tcase 'darwin':\n\t\tcase 'alpine':\n\t\tcase 'linux':\n\t\t\texpectedName = `node-v${nodeVersion}-${platform}-${arch}.tar.gz`;\n\t\t\tbreak;\n\t}\n\n\tconst nodeJsChecksums = fs.readFileSync(path.join(REPO_ROOT, 'build', 'checksums', 'nodejs.txt'), 'utf8');\n\tfor (const line of nodeJsChecksums.split('\\n')) {\n\t\tconst [checksum, name] = line.split(/\\s+/);\n\t\tif (name === expectedName) {\n\t\t\treturn checksum;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction extractAlpinefromDocker(nodeVersion, platform, arch) {\n\tconst imageName = arch === 'arm64' ? 'arm64v8/node' : 'node';\n\tlog(`Downloading node.js ${nodeVersion} ${platform} ${arch} from docker image ${imageName}`);\n\tconst contents = cp.execSync(`docker run --rm ${imageName}:${nodeVersion}-alpine /bin/sh -c 'cat \\`which node\\`'`, { maxBuffer: 100 * 1024 * 1024, encoding: 'buffer' });\n\treturn es.readArray([new File({ path: 'node', contents, stat: { mode: parseInt('755', 8) } })]);\n}\n\nconst { nodeVersion, internalNodeVersion } = getNodeVersion();\n\nBUILD_TARGETS.forEach(({ platform, arch }) => {\n\tgulp.task(task.define(`node-${platform}-${arch}`, () => {\n\t\tconst nodePath = path.join('.build', 'node', `v${nodeVersion}`, `${platform}-${arch}`);\n\n\t\tif (!fs.existsSync(nodePath)) {\n\t\t\tutil.rimraf(nodePath);\n\n\t\t\treturn nodejs(platform, arch)\n\t\t\t\t.pipe(vfs.dest(nodePath));\n\t\t}\n\n\t\treturn Promise.resolve(null);\n\t}));\n});\n\nconst defaultNodeTask = gulp.task(`node-${process.platform}-${process.arch}`);\n\nif (defaultNodeTask) {\n\tgulp.task(task.define('node', defaultNodeTask));\n}\n\nfunction nodejs(platform, arch) {\n\tconst { fetchUrls, fetchGithub } = require('./lib/fetch');\n\tconst untar = require('gulp-untar');\n\tconst crypto = require('crypto');\n\n\tif (arch === 'ia32') {\n\t\tarch = 'x86';\n\t} else if (arch === 'armhf') {\n\t\tarch = 'armv7l';\n\t} else if (arch === 'alpine') {\n\t\tplatform = 'alpine';\n\t\tarch = 'x64';\n\t}\n\n\tlog(`Downloading node.js ${nodeVersion} ${platform} ${arch} from ${product.nodejsRepository}...`);\n\n\tconst checksumSha256 = getNodeChecksum(nodeVersion, platform, arch);\n\n\tif (checksumSha256) {\n\t\tlog(`Using SHA256 checksum for checking integrity: ${checksumSha256}`);\n\t} else {\n\t\tlog.warn(`Unable to verify integrity of downloaded node.js binary because no SHA256 checksum was found!`);\n\t}\n\n\tswitch (platform) {\n\t\tcase 'win32':\n\t\t\treturn (product.nodejsRepository !== 'https://nodejs.org' ?\n\t\t\t\tfetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: `win-${arch}-node.exe`, checksumSha256 }) :\n\t\t\t\tfetchUrls(`/dist/v${nodeVersion}/win-${arch}/node.exe`, { base: 'https://nodejs.org', checksumSha256 }))\n\t\t\t\t.pipe(rename('node.exe'));\n\t\tcase 'darwin':\n\t\tcase 'linux':\n\t\t\treturn (product.nodejsRepository !== 'https://nodejs.org' ?\n\t\t\t\tfetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: `node-v${nodeVersion}-${platform}-${arch}.tar.gz`, checksumSha256 }) :\n\t\t\t\tfetchUrls(`/dist/v${nodeVersion}/node-v${nodeVersion}-${platform}-${arch}.tar.gz`, { base: 'https://nodejs.org', checksumSha256 })\n\t\t\t).pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar())))\n\t\t\t\t.pipe(filter('**/node'))\n\t\t\t\t.pipe(util.setExecutableBit('**'))\n\t\t\t\t.pipe(rename('node'));\n\t\tcase 'alpine':\n\t\t\treturn product.nodejsRepository !== 'https://nodejs.org' ?\n\t\t\t\tfetchGithub(product.nodejsRepository, { version: `${nodeVersion}-${internalNodeVersion}`, name: `node-v${nodeVersion}-${platform}-${arch}.tar.gz`, checksumSha256 })\n\t\t\t\t\t.pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar())))\n\t\t\t\t\t.pipe(filter('**/node'))\n\t\t\t\t\t.pipe(util.setExecutableBit('**'))\n\t\t\t\t\t.pipe(rename('node'))\n\t\t\t\t: extractAlpinefromDocker(nodeVersion, platform, arch);\n\t}\n}\n\nfunction packageTask(type, platform, arch, sourceFolderName, destinationFolderName) {\n\tconst destination = path.join(BUILD_ROOT, destinationFolderName);\n\n\treturn () => {\n\t\tconst json = require('gulp-json-editor');\n\n\t\tconst src = gulp.src(sourceFolderName + '/**', { base: '.' })\n\t\t\t.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); }))\n\t\t\t.pipe(util.setExecutableBit(['**/*.sh']))\n\t\t\t.pipe(filter(['**', '!**/*.js.map']));\n\n\t\tconst workspaceExtensionPoints = ['debuggers', 'jsonValidation'];\n\t\tconst isUIExtension = (manifest) => {\n\t\t\tswitch (manifest.extensionKind) {\n\t\t\t\tcase 'ui': return true;\n\t\t\t\tcase 'workspace': return false;\n\t\t\t\tdefault: {\n\t\t\t\t\tif (manifest.main) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (manifest.contributes && Object.keys(manifest.contributes).some(key => workspaceExtensionPoints.indexOf(key) !== -1)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Default is UI Extension\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tconst localWorkspaceExtensions = glob.sync('extensions/*/package.json')\n\t\t\t.filter((extensionPath) => {\n\t\t\t\tif (type === 'reh-web') {\n\t\t\t\t\treturn true; // web: ship all extensions for now\n\t\t\t\t}\n\n\t\t\t\t// Skip shipping UI extensions because the client side will have them anyways\n\t\t\t\t// and they'd just increase the download without being used\n\t\t\t\tconst manifest = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, extensionPath)).toString());\n\t\t\t\treturn !isUIExtension(manifest);\n\t\t\t}).map((extensionPath) => path.basename(path.dirname(extensionPath)))\n\t\t\t.filter(name => name !== 'vscode-api-tests' && name !== 'vscode-test-resolver'); // Do not ship the test extensions\n\t\tconst marketplaceExtensions = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'product.json'), 'utf8')).builtInExtensions\n\t\t\t.filter(entry => !entry.platforms || new Set(entry.platforms).has(platform))\n\t\t\t.filter(entry => !entry.clientOnly)\n\t\t\t.map(entry => entry.name);\n\t\tconst extensionPaths = [...localWorkspaceExtensions, ...marketplaceExtensions]\n\t\t\t.map(name => `.build/extensions/${name}/**`);\n\n\t\tconst extensions = gulp.src(extensionPaths, { base: '.build', dot: true });\n\t\tconst extensionsCommonDependencies = gulp.src('.build/extensions/node_modules/**', { base: '.build', dot: true });\n\t\tconst sources = es.merge(src, extensions, extensionsCommonDependencies)\n\t\t\t.pipe(filter(['**', '!**/*.js.map'], { dot: true }));\n\n\t\tlet version = packageJson.version;\n\t\tconst quality = product.quality;\n\n\t\tif (quality && quality !== 'stable') {\n\t\t\tversion += '-' + quality;\n\t\t}\n\n\t\tconst name = product.nameShort;\n\t\tconst packageJsonStream = gulp.src(['remote/package.json'], { base: 'remote' })\n\t\t\t.pipe(json({ name, version, dependencies: undefined, optionalDependencies: undefined }));\n\n\t\tconst date = new Date().toISOString();\n\n\t\tconst productJsonStream = gulp.src(['product.json'], { base: '.' })\n\t\t\t.pipe(json({ commit, date, version }));\n\n\t\tconst license = gulp.src(['remote/LICENSE'], { base: 'remote', allowEmpty: true });\n\n\t\tconst jsFilter = util.filter(data => !data.isDirectory() && /\\.js$/.test(data.path));\n\n\t\tconst productionDependencies = getProductionDependencies(REMOTE_FOLDER);\n\t\tconst dependenciesSrc = productionDependencies.map(d => path.relative(REPO_ROOT, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`]).flat();\n\t\tconst deps = gulp.src(dependenciesSrc, { base: 'remote', dot: true })\n\t\t\t// filter out unnecessary files, no source maps in server build\n\t\t\t.pipe(filter(['**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.js.map']))\n\t\t\t.pipe(util.cleanNodeModules(path.join(__dirname, '.moduleignore')))\n\t\t\t.pipe(util.cleanNodeModules(path.join(__dirname, `.moduleignore.${process.platform}`)))\n\t\t\t.pipe(jsFilter)\n\t\t\t.pipe(util.stripSourceMappingURL())\n\t\t\t.pipe(jsFilter.restore);\n\n\t\tconst nodePath = `.build/node/v${nodeVersion}/${platform}-${arch}`;\n\t\tconst node = gulp.src(`${nodePath}/**`, { base: nodePath, dot: true });\n\n\t\tlet web = [];\n\t\tif (type === 'reh-web') {\n\t\t\tweb = [\n\t\t\t\t'resources/server/favicon.ico',\n\t\t\t\t'resources/server/code-192.png',\n\t\t\t\t'resources/server/code-512.png',\n\t\t\t\t'resources/server/manifest.json'\n\t\t\t].map(resource => gulp.src(resource, { base: '.' }).pipe(rename(resource)));\n\t\t}\n\n\t\tconst all = es.merge(\n\t\t\tpackageJsonStream,\n\t\t\tproductJsonStream,\n\t\t\tlicense,\n\t\t\tsources,\n\t\t\tdeps,\n\t\t\tnode,\n\t\t\t...web\n\t\t);\n\n\t\tlet result = all\n\t\t\t.pipe(util.skipDirectories())\n\t\t\t.pipe(util.fixWin32DirectoryPermissions());\n\n\t\tif (platform === 'win32') {\n\t\t\tresult = es.merge(result,\n\t\t\t\tgulp.src('resources/server/bin/remote-cli/code.cmd', { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/remote-cli/${product.applicationName}.cmd`)),\n\t\t\t\tgulp.src('resources/server/bin/helpers/browser.cmd', { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/helpers/browser.cmd`)),\n\t\t\t\tgulp.src('resources/server/bin/code-server.cmd', { base: '.' })\n\t\t\t\t\t.pipe(rename(`bin/${product.serverApplicationName}.cmd`)),\n\t\t\t);\n\t\t} else if (platform === 'linux' || platform === 'alpine' || platform === 'darwin') {\n\t\t\tresult = es.merge(result,\n\t\t\t\tgulp.src(`resources/server/bin/remote-cli/${platform === 'darwin' ? 'code-darwin.sh' : 'code-linux.sh'}`, { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/remote-cli/${product.applicationName}`))\n\t\t\t\t\t.pipe(util.setExecutableBit()),\n\t\t\t\tgulp.src(`resources/server/bin/helpers/${platform === 'darwin' ? 'browser-darwin.sh' : 'browser-linux.sh'}`, { base: '.' })\n\t\t\t\t\t.pipe(replace('@@VERSION@@', version))\n\t\t\t\t\t.pipe(replace('@@COMMIT@@', commit))\n\t\t\t\t\t.pipe(replace('@@APPNAME@@', product.applicationName))\n\t\t\t\t\t.pipe(rename(`bin/helpers/browser.sh`))\n\t\t\t\t\t.pipe(util.setExecutableBit()),\n\t\t\t\tgulp.src(`resources/server/bin/${platform === 'darwin' ? 'code-server-darwin.sh' : 'code-server-linux.sh'}`, { base: '.' })\n\t\t\t\t\t.pipe(rename(`bin/${product.serverApplicationName}`))\n\t\t\t\t\t.pipe(util.setExecutableBit())\n\t\t\t);\n\t\t}\n\n\t\treturn result.pipe(vfs.dest(destination));\n\t};\n}\n\n/**\n * @param {object} product The parsed product.json file contents\n */\nfunction tweakProductForServerWeb(product) {\n\tconst result = { ...product };\n\tdelete result.webEndpointUrlTemplate;\n\treturn result;\n}\n\n['reh', 'reh-web'].forEach(type => {\n\tconst optimizeTask = task.define(`optimize-vscode-${type}`, task.series(\n\t\tutil.rimraf(`out-vscode-${type}`),\n\t\toptimize.optimizeTask(\n\t\t\t{\n\t\t\t\tout: `out-vscode-${type}`,\n\t\t\t\tamd: {\n\t\t\t\t\tsrc: 'out-build',\n\t\t\t\t\tentryPoints: (type === 'reh' ? serverEntryPoints : serverWithWebEntryPoints).flat(),\n\t\t\t\t\totherSources: [],\n\t\t\t\t\tresources: type === 'reh' ? serverResources : serverWithWebResources,\n\t\t\t\t\tloaderConfig: optimize.loaderConfig(),\n\t\t\t\t\tinlineAmdImages: true,\n\t\t\t\t\tbundleInfo: undefined,\n\t\t\t\t\tfileContentMapper: createVSCodeWebFileContentMapper('.build/extensions', type === 'reh-web' ? tweakProductForServerWeb(product) : product)\n\t\t\t\t},\n\t\t\t\tcommonJS: {\n\t\t\t\t\tsrc: 'out-build',\n\t\t\t\t\tentryPoints: [\n\t\t\t\t\t\t'out-build/server-main.js',\n\t\t\t\t\t\t'out-build/server-cli.js'\n\t\t\t\t\t],\n\t\t\t\t\tplatform: 'node',\n\t\t\t\t\texternal: [\n\t\t\t\t\t\t'minimist',\n\t\t\t\t\t\t// TODO: we cannot inline `product.json` because\n\t\t\t\t\t\t// it is being changed during build time at a later\n\t\t\t\t\t\t// point in time (such as `checksums`)\n\t\t\t\t\t\t'../product.json',\n\t\t\t\t\t\t'../package.json'\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\t));\n\n\tconst minifyTask = task.define(`minify-vscode-${type}`, task.series(\n\t\toptimizeTask,\n\t\tutil.rimraf(`out-vscode-${type}-min`),\n\t\toptimize.minifyTask(`out-vscode-${type}`, `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`)\n\t));\n\tgulp.task(minifyTask);\n\n\tBUILD_TARGETS.forEach(buildTarget => {\n\t\tconst dashed = (str) => (str ? `-${str}` : ``);\n\t\tconst platform = buildTarget.platform;\n\t\tconst arch = buildTarget.arch;\n\n\t\t['', 'min'].forEach(minified => {\n\t\t\tconst sourceFolderName = `out-vscode-${type}${dashed(minified)}`;\n\t\t\tconst destinationFolderName = `vscode-${type}${dashed(platform)}${dashed(arch)}`;\n\n\t\t\tconst serverTaskCI = task.define(`vscode-${type}${dashed(platform)}${dashed(arch)}${dashed(minified)}-ci`, task.series(\n\t\t\t\tgulp.task(`node-${platform}-${arch}`),\n\t\t\t\tutil.rimraf(path.join(BUILD_ROOT, destinationFolderName)),\n\t\t\t\tpackageTask(type, platform, arch, sourceFolderName, destinationFolderName)\n\t\t\t));\n\t\t\tgulp.task(serverTaskCI);\n\n\t\t\tconst serverTask = task.define(`vscode-${type}${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(\n\t\t\t\tcompileBuildTask,\n\t\t\t\tcompileExtensionsBuildTask,\n\t\t\t\tcompileExtensionMediaBuildTask,\n\t\t\t\tminified ? minifyTask : optimizeTask,\n\t\t\t\tserverTaskCI\n\t\t\t));\n\t\t\tgulp.task(serverTask);\n\t\t});\n\t});\n});\n", + "fileName": "./2.js" + }, + "diffs": [ + { + "originalRange": "[141,141)", + "modifiedRange": "[141,142)", + "innerChanges": [ + { + "originalRange": "[141,1 -> 141,1]", + "modifiedRange": "[141,1 -> 142,1]" + } + ] + }, + { + "originalRange": "[144,148)", + "modifiedRange": "[145,145)", + "innerChanges": [ + { + "originalRange": "[144,1 -> 148,1]", + "modifiedRange": "[145,1 -> 145,1]" + } + ] + }, + { + "originalRange": "[159,159)", + "modifiedRange": "[156,163)", + "innerChanges": [ + { + "originalRange": "[159,1 -> 159,1 EOL]", + "modifiedRange": "[156,1 -> 163,1 EOL]" + } + ] + }, + { + "originalRange": "[222,234)", + "modifiedRange": "[226,234)", + "innerChanges": [ + { + "originalRange": "[222,17 -> 234,1]", + "modifiedRange": "[226,17 -> 234,1]" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/indentation/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/indentation/advanced.expected.diff.json index 43176254538..1cbdb02b648 100644 --- a/src/vs/editor/test/node/diffing/fixtures/indentation/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/indentation/advanced.expected.diff.json @@ -80,5 +80,67 @@ } ] } + ], + "moves": [ + { + "originalRange": "[12,24)", + "modifiedRange": "[13,25)", + "changes": [ + { + "originalRange": "[12,24)", + "modifiedRange": "[13,25)", + "innerChanges": [ + { + "originalRange": "[12,1 -> 12,1]", + "modifiedRange": "[13,1 -> 13,2]" + }, + { + "originalRange": "[13,1 -> 13,1]", + "modifiedRange": "[14,1 -> 14,2]" + }, + { + "originalRange": "[14,1 -> 14,1]", + "modifiedRange": "[15,1 -> 15,2]" + }, + { + "originalRange": "[15,1 -> 15,1]", + "modifiedRange": "[16,1 -> 16,2]" + }, + { + "originalRange": "[16,1 -> 16,1]", + "modifiedRange": "[17,1 -> 17,2]" + }, + { + "originalRange": "[17,1 -> 17,1]", + "modifiedRange": "[18,1 -> 18,2]" + }, + { + "originalRange": "[18,1 -> 18,1]", + "modifiedRange": "[19,1 -> 19,2]" + }, + { + "originalRange": "[19,1 -> 19,1]", + "modifiedRange": "[20,1 -> 20,2]" + }, + { + "originalRange": "[20,1 -> 20,1]", + "modifiedRange": "[21,1 -> 21,2]" + }, + { + "originalRange": "[21,1 -> 21,1]", + "modifiedRange": "[22,1 -> 22,2]" + }, + { + "originalRange": "[22,1 -> 22,1]", + "modifiedRange": "[23,1 -> 23,2]" + }, + { + "originalRange": "[23,1 -> 23,1]", + "modifiedRange": "[24,1 -> 24,2]" + } + ] + } + ] + } ] } \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/indentation/advanced.invalid.diff.json b/src/vs/editor/test/node/diffing/fixtures/indentation/advanced.invalid.diff.json new file mode 100644 index 00000000000..43176254538 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/indentation/advanced.invalid.diff.json @@ -0,0 +1,84 @@ +{ + "original": { + "content": "export function lineRangeMappingFromRangeMappings(alignments: RangeMapping[]): LineRangeMapping[] {\n\tconst changes: LineRangeMapping[] = [];\n\tfor (const g of group(\n\t\talignments,\n\t\t(a1, a2) =>\n\t\t\t(a2.originalRange.startLineNumber - (a1.originalRange.endLineNumber - (a1.originalRange.endColumn > 1 ? 0 : 1)) <= 1)\n\t\t\t|| (a2.modifiedRange.startLineNumber - (a1.modifiedRange.endLineNumber - (a1.modifiedRange.endColumn > 1 ? 0 : 1)) <= 1)\n\t)) {\n\t\tconst first = g[0];\n\t\tconst last = g[g.length - 1];\n\n\t\tchanges.push(new LineRangeMapping(\n\t\t\tnew LineRange(\n\t\t\t\tfirst.originalRange.startLineNumber,\n\t\t\t\tlast.originalRange.endLineNumber + (last.originalRange.endColumn > 1 || last.modifiedRange.endColumn > 1 ? 1 : 0)\n\t\t\t),\n\t\t\tnew LineRange(\n\t\t\t\tfirst.modifiedRange.startLineNumber,\n\t\t\t\tlast.modifiedRange.endLineNumber + (last.originalRange.endColumn > 1 || last.modifiedRange.endColumn > 1 ? 1 : 0)\n\t\t\t),\n\t\t\tg\n\t\t));\n\t}\n\n\tassertFn(() => {\n\t\treturn checkAdjacentItems(changes,\n\t\t\t(m1, m2) => m2.originalRange.startLineNumber - m1.originalRange.endLineNumberExclusive === m2.modifiedRange.startLineNumber - m1.modifiedRange.endLineNumberExclusive &&\n\t\t\t\t// There has to be an unchanged line in between (otherwise both diffs should have been joined)\n\t\t\t\tm1.originalRange.endLineNumberExclusive < m2.originalRange.startLineNumber &&\n\t\t\t\tm1.modifiedRange.endLineNumberExclusive < m2.modifiedRange.startLineNumber,\n\t\t);\n\t});\n\n\n\treturn changes;\n}", + "fileName": "./1.tst" + }, + "modified": { + "content": "export function lineRangeMappingFromRangeMappings(alignments: RangeMapping[]): LineRangeMapping[] {\n\tconst changes: LineRangeMapping[] = [];\n\tfor (const g of group(\n\t\talignments,\n\t\t(a1, a2) =>\n\t\t\t(a2.originalRange.startLineNumber - (a1.originalRange.endLineNumber - (a1.originalRange.endColumn > 1 ? 0 : 1)) <= 1)\n\t\t\t|| (a2.modifiedRange.startLineNumber - (a1.modifiedRange.endLineNumber - (a1.modifiedRange.endColumn > 1 ? 0 : 1)) <= 1)\n\t)) {\n\t\tif (true) {\n\t\t\tconst first = g[0];\n\t\t\tconst last = g[g.length - 1];\n\n\t\t\tchanges.push(new LineRangeMapping(\n\t\t\t\tnew LineRange(\n\t\t\t\t\tfirst.originalRange.startLineNumber,\n\t\t\t\t\tlast.originalRange.endLineNumber + (last.originalRange.endColumn > 1 || last.modifiedRange.endColumn > 1 ? 1 : 0)\n\t\t\t\t),\n\t\t\t\tnew LineRange(\n\t\t\t\t\tfirst.modifiedRange.startLineNumber,\n\t\t\t\t\tlast.modifiedRange.endLineNumber + (last.originalRange.endColumn > 1 || last.modifiedRange.endColumn > 1 ? 1 : 0)\n\t\t\t\t),\n\t\t\t\tg\n\t\t\t));\n\t\t}\n\t}\n\n\tassertFn(() => {\n\t\treturn checkAdjacentItems(changes,\n\t\t\t(m1, m2) => m2.originalRange.startLineNumber - m1.originalRange.endLineNumberExclusive === m2.modifiedRange.startLineNumber - m1.modifiedRange.endLineNumberExclusive &&\n\t\t\t\t// There has to be an unchanged line in between (otherwise both diffs should have been joined)\n\t\t\t\tm1.originalRange.endLineNumberExclusive < m2.originalRange.startLineNumber &&\n\t\t\t\tm1.modifiedRange.endLineNumberExclusive < m2.modifiedRange.startLineNumber,\n\t\t);\n\t});\n\n\n\treturn changes;\n}", + "fileName": "./2.tst" + }, + "diffs": [ + { + "originalRange": "[9,11)", + "modifiedRange": "[9,12)", + "innerChanges": [ + { + "originalRange": "[9,1 -> 9,1]", + "modifiedRange": "[9,1 -> 10,1]" + }, + { + "originalRange": "[9,1 -> 9,1]", + "modifiedRange": "[10,1 -> 10,2]" + }, + { + "originalRange": "[10,1 -> 10,1]", + "modifiedRange": "[11,1 -> 11,2]" + } + ] + }, + { + "originalRange": "[12,23)", + "modifiedRange": "[13,25)", + "innerChanges": [ + { + "originalRange": "[12,1 -> 12,1]", + "modifiedRange": "[13,1 -> 13,2]" + }, + { + "originalRange": "[13,1 -> 13,1]", + "modifiedRange": "[14,1 -> 14,2]" + }, + { + "originalRange": "[14,1 -> 14,1]", + "modifiedRange": "[15,1 -> 15,2]" + }, + { + "originalRange": "[15,1 -> 15,1]", + "modifiedRange": "[16,1 -> 16,2]" + }, + { + "originalRange": "[16,1 -> 16,1]", + "modifiedRange": "[17,1 -> 17,2]" + }, + { + "originalRange": "[17,1 -> 17,1]", + "modifiedRange": "[18,1 -> 18,2]" + }, + { + "originalRange": "[18,1 -> 18,1]", + "modifiedRange": "[19,1 -> 19,2]" + }, + { + "originalRange": "[19,1 -> 19,1]", + "modifiedRange": "[20,1 -> 20,2]" + }, + { + "originalRange": "[20,1 -> 20,1]", + "modifiedRange": "[21,1 -> 21,2]" + }, + { + "originalRange": "[21,1 -> 21,1]", + "modifiedRange": "[22,1 -> 22,2]" + }, + { + "originalRange": "[22,1 -> 22,1]", + "modifiedRange": "[23,1 -> 23,2]" + }, + { + "originalRange": "[23,1 -> 23,1]", + "modifiedRange": "[24,1 -> 25,1]" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.expected.diff.json index a7ea515c057..a83fa2ea6e4 100644 --- a/src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.expected.diff.json @@ -42,5 +42,47 @@ } ] } + ], + "moves": [ + { + "originalRange": "[26,33)", + "modifiedRange": "[35,42)", + "changes": [ + { + "originalRange": "[26,33)", + "modifiedRange": "[35,42)", + "innerChanges": [ + { + "originalRange": "[26,3 -> 26,10]", + "modifiedRange": "[35,3 -> 35,4]" + }, + { + "originalRange": "[27,1 -> 27,1]", + "modifiedRange": "[36,1 -> 36,2]" + }, + { + "originalRange": "[28,1 -> 28,1]", + "modifiedRange": "[37,1 -> 37,2]" + }, + { + "originalRange": "[29,1 -> 29,1]", + "modifiedRange": "[38,1 -> 38,2]" + }, + { + "originalRange": "[30,1 -> 30,1]", + "modifiedRange": "[39,1 -> 39,2]" + }, + { + "originalRange": "[31,1 -> 31,1]", + "modifiedRange": "[40,1 -> 40,2]" + }, + { + "originalRange": "[32,1 -> 32,1]", + "modifiedRange": "[41,1 -> 41,2]" + } + ] + } + ] + } ] } \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.invalid.diff.json b/src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.invalid.diff.json new file mode 100644 index 00000000000..a7ea515c057 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/issue-185779/advanced.invalid.diff.json @@ -0,0 +1,46 @@ +{ + "original": { + "content": "\n\tprivate doAddView(view: IView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {\n\t\tif (this.state !== State.Idle) {\n\t\t\tthrow new Error('Cant modify splitview');\n\t\t}\n\n\t\tthis.state = State.Busy;\n\n\t\t// Add view\n\t\tconst container = $('.split-view-view');\n\n\t\tif (index === this.viewItems.length) {\n\t\t\tthis.viewContainer.appendChild(container);\n\t\t} else {\n\t\t\tthis.viewContainer.insertBefore(container, this.viewContainer.children.item(index));\n\t\t}\n\n\t\tconst onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size));\n\t\tconst containerDisposable = toDisposable(() => this.viewContainer.removeChild(container));\n\t\tconst disposable = combinedDisposable(onChangeDisposable, containerDisposable);\n\n\t\tlet viewSize: ViewItemSize;\n\n\t\tif (typeof size === 'number') {\n\t\t\tviewSize = size;\n\t\t} else if (size.type === 'split') {\n\t\t\tviewSize = this.getViewSize(size.index) / 2;\n\t\t} else if (size.type === 'invisible') {\n\t\t\tviewSize = { cachedVisibleSize: size.cachedVisibleSize };\n\t\t} else {\n\t\t\tviewSize = view.minimumSize;\n\t\t}\n\n\t\tconst item = this.orientation === Orientation.VERTICAL\n\t\t\t? new VerticalViewItem(container, view, viewSize, disposable)\n\t\t\t: new HorizontalViewItem(container, view, viewSize, disposable);\n\n\t\tthis.viewItems.splice(index, 0, item);\n\n", + "fileName": "./1.txt" + }, + "modified": { + "content": "\n\tprivate doAddView(view: IView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {\n\t\tif (this.state !== State.Idle) {\n\t\t\tthrow new Error('Cant modify splitview');\n\t\t}\n\n\t\tthis.state = State.Busy;\n\n\t\t// Add view\n\t\tconst container = $('.split-view-view');\n\n\t\tif (index === this.viewItems.length) {\n\t\t\tthis.viewContainer.appendChild(container);\n\t\t} else {\n\t\t\tthis.viewContainer.insertBefore(container, this.viewContainer.children.item(index));\n\t\t}\n\n\t\tconst onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size));\n\t\tconst containerDisposable = toDisposable(() => this.viewContainer.removeChild(container));\n\t\tconst disposable = combinedDisposable(onChangeDisposable, containerDisposable);\n\n\t\tlet viewSize: ViewItemSize;\n\n\t\tif (typeof size === 'number') {\n\t\t\tviewSize = size;\n\t\t} else {\n\t\t\tif (size.type === 'auto') {\n\t\t\t\tif (this.areViewsDistributed()) {\n\t\t\t\t\tsize = { type: 'distribute' };\n\t\t\t\t} else {\n\t\t\t\t\tsize = { type: 'split', index: size.index };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (size.type === 'split') {\n\t\t\t\tviewSize = this.getViewSize(size.index) / 2;\n\t\t\t} else if (size.type === 'invisible') {\n\t\t\t\tviewSize = { cachedVisibleSize: size.cachedVisibleSize };\n\t\t\t} else {\n\t\t\t\tviewSize = view.minimumSize;\n\t\t\t}\n\t\t}\n\n\t\tconst item = this.orientation === Orientation.VERTICAL\n\t\t\t? new VerticalViewItem(container, view, viewSize, disposable)\n\t\t\t: new HorizontalViewItem(container, view, viewSize, disposable);\n\n\t\tthis.viewItems.splice(index, 0, item);\n\n", + "fileName": "./2.txt" + }, + "diffs": [ + { + "originalRange": "[26,32)", + "modifiedRange": "[26,42)", + "innerChanges": [ + { + "originalRange": "[26,10 -> 26,10]", + "modifiedRange": "[26,10 -> 35,4]" + }, + { + "originalRange": "[27,1 -> 27,1]", + "modifiedRange": "[36,1 -> 36,2]" + }, + { + "originalRange": "[28,1 -> 28,1]", + "modifiedRange": "[37,1 -> 37,2]" + }, + { + "originalRange": "[29,1 -> 29,1]", + "modifiedRange": "[38,1 -> 38,2]" + }, + { + "originalRange": "[30,1 -> 30,1]", + "modifiedRange": "[39,1 -> 39,2]" + }, + { + "originalRange": "[31,1 -> 31,1]", + "modifiedRange": "[40,1 -> 40,2]" + }, + { + "originalRange": "[32,1 -> 32,1]", + "modifiedRange": "[41,1 -> 42,1]" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/move-1/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/move-1/advanced.expected.diff.json index ad809ac7fe0..e2dac9ce019 100644 --- a/src/vs/editor/test/node/diffing/fixtures/move-1/advanced.expected.diff.json +++ b/src/vs/editor/test/node/diffing/fixtures/move-1/advanced.expected.diff.json @@ -28,5 +28,23 @@ } ] } + ], + "moves": [ + { + "originalRange": "[24,28)", + "modifiedRange": "[70,74)", + "changes": [ + { + "originalRange": "[26,27)", + "modifiedRange": "[72,73)", + "innerChanges": [ + { + "originalRange": "[26,36 -> 26,40 EOL]", + "modifiedRange": "[72,36 -> 72,40 EOL]" + } + ] + } + ] + } ] } \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/move-1/advanced.invalid.diff.json b/src/vs/editor/test/node/diffing/fixtures/move-1/advanced.invalid.diff.json new file mode 100644 index 00000000000..ad809ac7fe0 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/move-1/advanced.invalid.diff.json @@ -0,0 +1,32 @@ +{ + "original": { + "content": "/*---------------------------------------------------------------------------------------------\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 * as arrays from 'vs/base/common/arrays';\nimport { IdleDeadline, runWhenIdle } from 'vs/base/common/async';\nimport { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { setTimeout0 } from 'vs/base/common/platform';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { countEOL } from 'vs/editor/common/core/eolCounter';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\nimport { EncodedTokenizationResult, IBackgroundTokenizationStore, IBackgroundTokenizer, ILanguageIdCodec, IState, ITokenizationSupport, TokenizationRegistry } from 'vs/editor/common/languages';\nimport { nullTokenizeEncoded } from 'vs/editor/common/languages/nullTokenize';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { TextModel } from 'vs/editor/common/model/textModel';\nimport { TokenizationTextModelPart } from 'vs/editor/common/model/tokenizationTextModelPart';\nimport { IModelContentChangedEvent, IModelLanguageChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { ContiguousMultilineTokensBuilder } from 'vs/editor/common/tokens/contiguousMultilineTokensBuilder';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\n\nconst enum Constants {\n\tCHEAP_TOKENIZATION_LENGTH_LIMIT = 2048\n}\n\n/**\n * An array that avoids being sparse by always\n * filling up unused indices with a default value.\n */\nexport class ContiguousGrowingArray {\n\n\tprivate _store: T[] = [];\n\n\tconstructor(\n\t\tprivate readonly _default: T\n\t) { }\n\n\tpublic get(index: number): T {\n\t\tif (index < this._store.length) {\n\t\t\treturn this._store[index];\n\t\t}\n\t\treturn this._default;\n\t}\n\n\tpublic set(index: number, value: T): void {\n\t\twhile (index >= this._store.length) {\n\t\t\tthis._store[this._store.length] = this._default;\n\t\t}\n\t\tthis._store[index] = value;\n\t}\n\n\t// TODO have `replace` instead of `delete` and `insert`\n\tpublic delete(deleteIndex: number, deleteCount: number): void {\n\t\tif (deleteCount === 0 || deleteIndex >= this._store.length) {\n\t\t\treturn;\n\t\t}\n\t\tthis._store.splice(deleteIndex, deleteCount);\n\t}\n\n\tpublic insert(insertIndex: number, insertCount: number): void {\n\t\tif (insertCount === 0 || insertIndex >= this._store.length) {\n\t\t\treturn;\n\t\t}\n\t\tconst arr: T[] = [];\n\t\tfor (let i = 0; i < insertCount; i++) {\n\t\t\tarr[i] = this._default;\n\t\t}\n\t\tthis._store = arrays.arrayInsert(this._store, insertIndex, arr);\n\t}\n}\n\n/**\n * Stores the states at the start of each line and keeps track of which lines\n * must be re-tokenized. Also uses state equality to quickly validate lines\n * that don't need to be re-tokenized.\n *\n * For example, when typing on a line, the line gets marked as needing to be tokenized.\n * Once the line is tokenized, the end state is checked for equality against the begin\n * state of the next line. If the states are equal, tokenization doesn't need to run\n * again over the rest of the file. If the states are not equal, the next line gets marked\n * as needing to be tokenized.\n */\nexport class TokenizationStateStore {\n\trequestTokens(startLineNumber: number, endLineNumberExclusive: number): void {\n\t\tfor (let lineNumber = startLineNumber; lineNumber < endLineNumberExclusive; lineNumber++) {\n\t\t\tthis._stateStore.markMustBeTokenized(lineNumber - 1);\n\t\t}\n\t}\n}\n", + "fileName": "./1.tst" + }, + "modified": { + "content": "/*---------------------------------------------------------------------------------------------\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 * as arrays from 'vs/base/common/arrays';\nimport { IdleDeadline, runWhenIdle } from 'vs/base/common/async';\nimport { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { setTimeout0 } from 'vs/base/common/platform';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { countEOL } from 'vs/editor/common/core/eolCounter';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\nimport { EncodedTokenizationResult, IBackgroundTokenizationStore, IBackgroundTokenizer, ILanguageIdCodec, IState, ITokenizationSupport, TokenizationRegistry } from 'vs/editor/common/languages';\nimport { nullTokenizeEncoded } from 'vs/editor/common/languages/nullTokenize';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { TextModel } from 'vs/editor/common/model/textModel';\nimport { TokenizationTextModelPart } from 'vs/editor/common/model/tokenizationTextModelPart';\nimport { IModelContentChangedEvent, IModelLanguageChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { ContiguousMultilineTokensBuilder } from 'vs/editor/common/tokens/contiguousMultilineTokensBuilder';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\n\n/**\n * An array that avoids being sparse by always\n * filling up unused indices with a default value.\n */\nexport class ContiguousGrowingArray {\n\n\tprivate _store: T[] = [];\n\n\tconstructor(\n\t\tprivate readonly _default: T\n\t) { }\n\n\tpublic get(index: number): T {\n\t\tif (index < this._store.length) {\n\t\t\treturn this._store[index];\n\t\t}\n\t\treturn this._default;\n\t}\n\n\tpublic set(index: number, value: T): void {\n\t\twhile (index >= this._store.length) {\n\t\t\tthis._store[this._store.length] = this._default;\n\t\t}\n\t\tthis._store[index] = value;\n\t}\n\n\t// TODO have `replace` instead of `delete` and `insert`\n\tpublic delete(deleteIndex: number, deleteCount: number): void {\n\t\tif (deleteCount === 0 || deleteIndex >= this._store.length) {\n\t\t\treturn;\n\t\t}\n\t\tthis._store.splice(deleteIndex, deleteCount);\n\t}\n\n\tpublic insert(insertIndex: number, insertCount: number): void {\n\t\tif (insertCount === 0 || insertIndex >= this._store.length) {\n\t\t\treturn;\n\t\t}\n\t\tconst arr: T[] = [];\n\t\tfor (let i = 0; i < insertCount; i++) {\n\t\t\tarr[i] = this._default;\n\t\t}\n\t\tthis._store = arrays.arrayInsert(this._store, insertIndex, arr);\n\t}\n}\n\nconst enum Constants {\n\tCHEAP_TOKENIZATION_LENGTH_LIMIT = 1024\n}\n\n/**\n * Stores the states at the start of each line and keeps track of which lines\n * must be re-tokenized. Also uses state equality to quickly validate lines\n * that don't need to be re-tokenized.\n *\n * For example, when typing on a line, the line gets marked as needing to be tokenized.\n * Once the line is tokenized, the end state is checked for equality against the begin\n * state of the next line. If the states are equal, tokenization doesn't need to run\n * again over the rest of the file. If the states are not equal, the next line gets marked\n * as needing to be tokenized.\n */\nexport class TokenizationStateStore {\n\trequestTokens(startLineNumber: number, endLineNumberExclusive: number): void {\n\t\tfor (let lineNumber = startLineNumber; lineNumber < endLineNumberExclusive; lineNumber++) {\n\t\t\tthis._stateStore.markMustBeTokenized(lineNumber - 1);\n\t\t}\n\t}\n}\n", + "fileName": "./2.tst" + }, + "diffs": [ + { + "originalRange": "[24,28)", + "modifiedRange": "[24,24)", + "innerChanges": [ + { + "originalRange": "[24,1 -> 28,1 EOL]", + "modifiedRange": "[24,1 -> 24,1 EOL]" + } + ] + }, + { + "originalRange": "[74,74)", + "modifiedRange": "[70,74)", + "innerChanges": [ + { + "originalRange": "[74,1 -> 74,1 EOL]", + "modifiedRange": "[70,1 -> 74,1 EOL]" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/noisy-move1/1.tst b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/1.tst new file mode 100644 index 00000000000..28c9da392b1 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/1.tst @@ -0,0 +1,544 @@ + contextKeyService.onDidChangeContext(this.onDidChangeContext, this, this.disposables); + this.disposables.add(Event.filter(viewsRegistry.onDidChangeViewWelcomeContent, id => id === this.id)(this.onDidChangeViewWelcomeContent, this, this.disposables)); + this.onDidChangeViewWelcomeContent(); + } + + private onDidChangeViewWelcomeContent(): void { + const descriptors = viewsRegistry.getViewWelcomeContent(this.id); + + this.items = []; + + for (const descriptor of descriptors) { + if (descriptor.when === 'default') { + this.defaultItem = { descriptor, visible: true }; + } else { + const visible = descriptor.when ? this.contextKeyService.contextMatchesRules(descriptor.when) : true; + this.items.push({ descriptor, visible }); + } + } + + this._onDidChange.fire(); + } + + private onDidChangeContext(): void { + let didChange = false; + + for (const item of this.items) { + if (!item.descriptor.when || item.descriptor.when === 'default') { + continue; + } + + const visible = this.contextKeyService.contextMatchesRules(item.descriptor.when); + + if (item.visible === visible) { + continue; + } + + item.visible = visible; + didChange = true; + } + + if (didChange) { + this._onDidChange.fire(); + } + } + + dispose(): void { + this.disposables.dispose(); + } +} + +export abstract class ViewPane extends Pane implements IView { + + private static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions'; + + private _onDidFocus = this._register(new Emitter()); + readonly onDidFocus: Event = this._onDidFocus.event; + + private _onDidBlur = this._register(new Emitter()); + readonly onDidBlur: Event = this._onDidBlur.event; + + private _onDidChangeBodyVisibility = this._register(new Emitter()); + readonly onDidChangeBodyVisibility: Event = this._onDidChangeBodyVisibility.event; + + protected _onDidChangeTitleArea = this._register(new Emitter()); + readonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event; + + protected _onDidChangeViewWelcomeState = this._register(new Emitter()); + readonly onDidChangeViewWelcomeState: Event = this._onDidChangeViewWelcomeState.event; + + private _isVisible: boolean = false; + readonly id: string; + + private _title: string; + public get title(): string { + return this._title; + } + + private _titleDescription: string | undefined; + public get titleDescription(): string | undefined { + return this._titleDescription; + } + + readonly menuActions: CompositeMenuActions; + + private progressBar!: ProgressBar; + private progressIndicator!: IProgressIndicator; + + private toolbar?: WorkbenchToolBar; + private readonly showActions: ViewPaneShowActions; + private headerContainer?: HTMLElement; + private titleContainer?: HTMLElement; + private titleDescriptionContainer?: HTMLElement; + private iconContainer?: HTMLElement; + protected twistiesContainer?: HTMLElement; + + private bodyContainer!: HTMLElement; + private viewWelcomeContainer!: HTMLElement; + private viewWelcomeDisposable: IDisposable = Disposable.None; + private viewWelcomeController: ViewWelcomeController; + + protected readonly scopedContextKeyService: IContextKeyService; + + constructor( + options: IViewPaneOptions, + @IKeybindingService protected keybindingService: IKeybindingService, + @IContextMenuService protected contextMenuService: IContextMenuService, + @IConfigurationService protected readonly configurationService: IConfigurationService, + @IContextKeyService protected contextKeyService: IContextKeyService, + @IViewDescriptorService protected viewDescriptorService: IViewDescriptorService, + @IInstantiationService protected instantiationService: IInstantiationService, + @IOpenerService protected openerService: IOpenerService, + @IThemeService protected themeService: IThemeService, + @ITelemetryService protected telemetryService: ITelemetryService, + ) { + super({ ...options, ...{ orientation: viewDescriptorService.getViewLocationById(options.id) === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL } }); + + this.id = options.id; + this._title = options.title; + this._titleDescription = options.titleDescription; + this.showActions = options.showActions ?? ViewPaneShowActions.Default; + + this.scopedContextKeyService = this._register(contextKeyService.createScoped(this.element)); + this.scopedContextKeyService.createKey('view', this.id); + const viewLocationKey = this.scopedContextKeyService.createKey('viewLocation', ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!)); + this._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === this.id))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!)))); + + this.menuActions = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])).createInstance(CompositeMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs })); + this._register(this.menuActions.onDidChange(() => this.updateActions())); + + this.viewWelcomeController = this._register(new ViewWelcomeController(this.id, contextKeyService)); + } + + override get headerVisible(): boolean { + return super.headerVisible; + } + + override set headerVisible(visible: boolean) { + super.headerVisible = visible; + this.element.classList.toggle('merged-header', !visible); + } + + setVisible(visible: boolean): void { + if (this._isVisible !== visible) { + this._isVisible = visible; + + if (this.isExpanded()) { + this._onDidChangeBodyVisibility.fire(visible); + } + } + } + + isVisible(): boolean { + return this._isVisible; + } + + isBodyVisible(): boolean { + return this._isVisible && this.isExpanded(); + } + + override setExpanded(expanded: boolean): boolean { + const changed = super.setExpanded(expanded); + if (changed) { + this._onDidChangeBodyVisibility.fire(expanded); + } + if (this.twistiesContainer) { + this.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded))); + this.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded))); + } + return changed; + } + + override render(): void { + super.render(); + + const focusTracker = trackFocus(this.element); + this._register(focusTracker); + this._register(focusTracker.onDidFocus(() => this._onDidFocus.fire())); + this._register(focusTracker.onDidBlur(() => this._onDidBlur.fire())); + } + + protected renderHeader(container: HTMLElement): void { + this.headerContainer = container; + + this.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded())))); + + this.renderHeaderTitle(container, this.title); + + const actions = append(container, $('.actions')); + actions.classList.toggle('show-always', this.showActions === ViewPaneShowActions.Always); + actions.classList.toggle('show-expanded', this.showActions === ViewPaneShowActions.WhenExpanded); + this.toolbar = this.instantiationService.createInstance(WorkbenchToolBar, actions, { + orientation: ActionsOrientation.HORIZONTAL, + actionViewItemProvider: action => this.getActionViewItem(action), + ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.title), + getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), + renderDropdownAsChildElement: true, + actionRunner: this.getActionRunner(), + resetMenu: this.menuActions.menuId + }); + + this._register(this.toolbar); + this.setActions(); + + this._register(addDisposableListener(actions, EventType.CLICK, e => e.preventDefault())); + + const viewContainerModel = this.viewDescriptorService.getViewContainerByViewId(this.id); + if (viewContainerModel) { + this._register(this.viewDescriptorService.getViewContainerModel(viewContainerModel).onDidChangeContainerInfo(({ title }) => this.updateTitle(this.title))); + } else { + console.error(`View container model not found for view ${this.id}`); + } + + const onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig)); + this._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this)); + this.updateActionsVisibility(); + } + + protected getTwistyIcon(expanded: boolean): ThemeIcon { + return expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon; + } + + override style(styles: IPaneStyles): void { + super.style(styles); + + const icon = this.getIcon(); + if (this.iconContainer) { + const fgColor = asCssValueWithDefault(styles.headerForeground, asCssVariable(foreground)); + if (URI.isUri(icon)) { + // Apply background color to activity bar item provided with iconUrls + this.iconContainer.style.backgroundColor = fgColor; + this.iconContainer.style.color = ''; + } else { + // Apply foreground color to activity bar items provided with codicons + this.iconContainer.style.color = fgColor; + this.iconContainer.style.backgroundColor = ''; + } + } + } + + private getIcon(): ThemeIcon | URI { + return this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon; + } + + protected renderHeaderTitle(container: HTMLElement, title: string): void { + this.iconContainer = append(container, $('.icon', undefined)); + const icon = this.getIcon(); + + let cssClass: string | undefined = undefined; + if (URI.isUri(icon)) { + cssClass = `view-${this.id.replace(/[\.\:]/g, '-')}`; + const iconClass = `.pane-header .icon.${cssClass}`; + + createCSSRule(iconClass, ` + mask: ${asCSSUrl(icon)} no-repeat 50% 50%; + mask-size: 24px; + -webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%; + -webkit-mask-size: 16px; + `); + } else if (ThemeIcon.isThemeIcon(icon)) { + cssClass = ThemeIcon.asClassName(icon); + } + + if (cssClass) { + this.iconContainer.classList.add(...cssClass.split(' ')); + } + + const calculatedTitle = this.calculateTitle(title); + this.titleContainer = append(container, $('h3.title', { title: calculatedTitle }, calculatedTitle)); + + if (this._titleDescription) { + this.setTitleDescription(this._titleDescription); + } + + this.iconContainer.title = calculatedTitle; + this.iconContainer.setAttribute('aria-label', calculatedTitle); + } + + protected updateTitle(title: string): void { + const calculatedTitle = this.calculateTitle(title); + if (this.titleContainer) { + this.titleContainer.textContent = calculatedTitle; + this.titleContainer.setAttribute('title', calculatedTitle); + } + + if (this.iconContainer) { + this.iconContainer.title = calculatedTitle; + this.iconContainer.setAttribute('aria-label', calculatedTitle); + } + + this._title = title; + this._onDidChangeTitleArea.fire(); + } + + private setTitleDescription(description: string | undefined) { + if (this.titleDescriptionContainer) { + this.titleDescriptionContainer.textContent = description ?? ''; + this.titleDescriptionContainer.setAttribute('title', description ?? ''); + } + else if (description && this.titleContainer) { + this.titleDescriptionContainer = after(this.titleContainer, $('span.description', { title: description }, description)); + } + } + + protected updateTitleDescription(description?: string | undefined): void { + this.setTitleDescription(description); + + this._titleDescription = description; + this._onDidChangeTitleArea.fire(); + } + + private calculateTitle(title: string): string { + const viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!; + const model = this.viewDescriptorService.getViewContainerModel(viewContainer); + const viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id); + const isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer; + + if (!isDefault && viewDescriptor?.containerTitle && model.title !== viewDescriptor.containerTitle) { + return `${viewDescriptor.containerTitle}: ${title}`; + } + + return title; + } + + private scrollableElement!: DomScrollableElement; + + protected renderBody(container: HTMLElement): void { + this.bodyContainer = container; + + const viewWelcomeContainer = append(container, $('.welcome-view')); + this.viewWelcomeContainer = $('.welcome-view-content', { tabIndex: 0 }); + this.scrollableElement = this._register(new DomScrollableElement(this.viewWelcomeContainer, { + alwaysConsumeMouseWheel: true, + horizontal: ScrollbarVisibility.Hidden, + vertical: ScrollbarVisibility.Visible, + })); + + append(viewWelcomeContainer, this.scrollableElement.getDomNode()); + + const onViewWelcomeChange = Event.any(this.viewWelcomeController.onDidChange, this.onDidChangeViewWelcomeState); + this._register(onViewWelcomeChange(this.updateViewWelcome, this)); + this.updateViewWelcome(); + } + + protected layoutBody(height: number, width: number): void { + if (this.shouldShowWelcome()) { + this.viewWelcomeContainer.style.height = `${height}px`; + this.viewWelcomeContainer.style.width = `${width}px`; + this.viewWelcomeContainer.classList.toggle('wide', width > 640); + this.scrollableElement.scanDomNode(); + } + } + + onDidScrollRoot() { + // noop + } + + getProgressIndicator() { + if (this.progressBar === undefined) { + // Progress bar + this.progressBar = this._register(new ProgressBar(this.element, defaultProgressBarStyles)); + this.progressBar.hide(); + } + + if (this.progressIndicator === undefined) { + const that = this; + this.progressIndicator = new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope { + constructor() { + super(that.id, that.isBodyVisible()); + this._register(that.onDidChangeBodyVisibility(isVisible => isVisible ? this.onScopeOpened(that.id) : this.onScopeClosed(that.id))); + } + }()); + } + return this.progressIndicator; + } + + protected getProgressLocation(): string { + return this.viewDescriptorService.getViewContainerByViewId(this.id)!.id; + } + + protected getBackgroundColor(): string { + switch (this.viewDescriptorService.getViewLocationById(this.id)) { + case ViewContainerLocation.Panel: + return PANEL_BACKGROUND; + case ViewContainerLocation.Sidebar: + case ViewContainerLocation.AuxiliaryBar: + return SIDE_BAR_BACKGROUND; + } + + return SIDE_BAR_BACKGROUND; + } + + focus(): void { + if (this.shouldShowWelcome()) { + this.viewWelcomeContainer.focus(); + } else if (this.element) { + this.element.focus(); + this._onDidFocus.fire(); + } + } + + private setActions(): void { + if (this.toolbar) { + const primaryActions = [...this.menuActions.getPrimaryActions()]; + if (this.shouldShowFilterInHeader()) { + primaryActions.unshift(VIEWPANE_FILTER_ACTION); + } + this.toolbar.setActions(prepareActions(primaryActions), prepareActions(this.menuActions.getSecondaryActions())); + this.toolbar.context = this.getActionsContext(); + } + } + + private updateActionsVisibility(): void { + if (!this.headerContainer) { + return; + } + const shouldAlwaysShowActions = this.configurationService.getValue('workbench.view.alwaysShowHeaderActions'); + this.headerContainer.classList.toggle('actions-always-visible', shouldAlwaysShowActions); + } + + protected updateActions(): void { + this.setActions(); + this._onDidChangeTitleArea.fire(); + } + + getActionViewItem(action: IAction, options?: IDropdownMenuActionViewItemOptions): IActionViewItem | undefined { + if (action.id === VIEWPANE_FILTER_ACTION.id) { + const that = this; + return new class extends BaseActionViewItem { + constructor() { super(null, action); } + override setFocusable(): void { /* noop input elements are focusable by default */ } + override get trapsArrowNavigation(): boolean { return true; } + override render(container: HTMLElement): void { + container.classList.add('viewpane-filter-container'); + append(container, that.getFilterWidget()!.element); + } + }; + } + return createActionViewItem(this.instantiationService, action, { ...options, ...{ menuAsChild: action instanceof SubmenuItemAction } }); + } + + getActionsContext(): unknown { + return undefined; + } + + getActionRunner(): IActionRunner | undefined { + return undefined; + } + + getOptimalWidth(): number { + return 0; + } + + saveState(): void { + // Subclasses to implement for saving state + } + + private updateViewWelcome(): void { + this.viewWelcomeDisposable.dispose(); + + if (!this.shouldShowWelcome()) { + this.bodyContainer.classList.remove('welcome'); + this.viewWelcomeContainer.innerText = ''; + this.scrollableElement.scanDomNode(); + return; + } + + const contents = this.viewWelcomeController.contents; + + if (contents.length === 0) { + this.bodyContainer.classList.remove('welcome'); + this.viewWelcomeContainer.innerText = ''; + this.scrollableElement.scanDomNode(); + return; + } + + const disposables = new DisposableStore(); + this.bodyContainer.classList.add('welcome'); + this.viewWelcomeContainer.innerText = ''; + + for (const { content, precondition } of contents) { + const lines = content.split('\n'); + + for (let line of lines) { + line = line.trim(); + + if (!line) { + continue; + } + + const linkedText = parseLinkedText(line); + + if (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') { + const node = linkedText.nodes[0]; + const buttonContainer = append(this.viewWelcomeContainer, $('.button-container')); + const button = new Button(buttonContainer, { title: node.title, supportIcons: true, ...defaultButtonStyles }); + button.label = node.label; + button.onDidClick(_ => { + this.telemetryService.publicLog2<{ viewId: string; uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href }); + this.openerService.open(node.href, { allowCommands: true }); + }, null, disposables); + disposables.add(button); + + if (precondition) { + const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition); + updateEnablement(); + + const keys = new Set(); + precondition.keys().forEach(key => keys.add(key)); + const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys)); + onDidChangeContext(updateEnablement, null, disposables); + } + } else { + const p = append(this.viewWelcomeContainer, $('p')); + + for (const node of linkedText.nodes) { + if (typeof node === 'string') { + append(p, document.createTextNode(node)); + } else { + const link = disposables.add(this.instantiationService.createInstance(Link, p, node, {})); + + if (precondition && node.href.startsWith('command:')) { + const updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition); + updateEnablement(); + + const keys = new Set(); + precondition.keys().forEach(key => keys.add(key)); + const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys)); + onDidChangeContext(updateEnablement, null, disposables); + } + } + } + } + } + } + + this.scrollableElement.scanDomNode(); + this.viewWelcomeDisposable = disposables; + } + + shouldShowWelcome(): boolean { + return false; + } + + getFilterWidget() \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/noisy-move1/2.tst b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/2.tst new file mode 100644 index 00000000000..744eb775f10 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/2.tst @@ -0,0 +1,565 @@ + + layout(height: number, width: number) { + if (!this.enabled) { + return; + } + + this.element!.style.height = `${height}px`; + this.element!.style.width = `${width}px`; + this.element!.classList.toggle('wide', width > 640); + this.scrollableElement!.scanDomNode(); + } + + focus() { + if (!this.enabled) { + return; + } + + this.element!.focus(); + } + + private onDidChangeViewWelcomeState(): void { + const enabled = this.delegate.shouldShowWelcome(); + + if (this.enabled === enabled) { + return; + } + + this.enabled = enabled; + + if (!enabled) { + this.enabledDisposables.clear(); + return; + } + + this.container.classList.add('welcome'); + const viewWelcomeContainer = append(this.container, $('.welcome-view')); + this.element = $('.welcome-view-content', { tabIndex: 0 }); + this.scrollableElement = new DomScrollableElement(this.element, { alwaysConsumeMouseWheel: true, horizontal: ScrollbarVisibility.Hidden, vertical: ScrollbarVisibility.Visible, }); + append(viewWelcomeContainer, this.scrollableElement.getDomNode()); + + this.enabledDisposables.add(toDisposable(() => { + this.container.classList.remove('welcome'); + this.scrollableElement!.dispose(); + viewWelcomeContainer.remove(); + this.scrollableElement = undefined; + this.element = undefined; + })); + + this.contextKeyService.onDidChangeContext(this.onDidChangeContext, this, this.enabledDisposables); + Event.chain(viewsRegistry.onDidChangeViewWelcomeContent, $ => $.filter(id => id === this.delegate.id)) + (this.onDidChangeViewWelcomeContent, this, this.enabledDisposables); + this.onDidChangeViewWelcomeContent(); + } + + private onDidChangeViewWelcomeContent(): void { + const descriptors = viewsRegistry.getViewWelcomeContent(this.delegate.id); + + this.items = []; + + for (const descriptor of descriptors) { + if (descriptor.when === 'default') { + this.defaultItem = { descriptor, visible: true }; + } else { + const visible = descriptor.when ? this.contextKeyService.contextMatchesRules(descriptor.when) : true; + this.items.push({ descriptor, visible }); + } + } + + this.render(); + } + + private onDidChangeContext(): void { + let didChange = false; + + for (const item of this.items) { + if (!item.descriptor.when || item.descriptor.when === 'default') { + continue; + } + + const visible = this.contextKeyService.contextMatchesRules(item.descriptor.when); + + if (item.visible === visible) { + continue; + } + + item.visible = visible; + didChange = true; + } + + if (didChange) { + this.render(); + } + } + + private render(): void { + this.renderDisposables.clear(); + + const contents = this.getContentDescriptors(); + + if (contents.length === 0) { + this.container.classList.remove('welcome'); + this.element!.innerText = ''; + this.scrollableElement!.scanDomNode(); + return; + } + + this.container.classList.add('welcome'); + this.element!.innerText = ''; + + for (const { content, precondition } of contents) { + const lines = content.split('\n'); + + for (let line of lines) { + line = line.trim(); + + if (!line) { + continue; + } + + const linkedText = parseLinkedText(line); + + if (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') { + const node = linkedText.nodes[0]; + const buttonContainer = append(this.element!, $('.button-container')); + const button = new Button(buttonContainer, { title: node.title, supportIcons: true, ...defaultButtonStyles }); + button.label = node.label; + button.onDidClick(_ => { + this.telemetryService.publicLog2<{ viewId: string; uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.delegate.id, uri: node.href }); + this.openerService.open(node.href, { allowCommands: true }); + }, null, this.renderDisposables); + this.renderDisposables.add(button); + + if (precondition) { + const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition); + updateEnablement(); + + const keys = new Set(precondition.keys()); + const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys)); + onDidChangeContext(updateEnablement, null, this.renderDisposables); + } + } else { + const p = append(this.element!, $('p')); + + for (const node of linkedText.nodes) { + if (typeof node === 'string') { + append(p, document.createTextNode(node)); + } else { + const link = this.renderDisposables.add(this.instantiationService.createInstance(Link, p, node, {})); + + if (precondition && node.href.startsWith('command:')) { + const updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition); + updateEnablement(); + + const keys = new Set(precondition.keys()); + const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys)); + onDidChangeContext(updateEnablement, null, this.renderDisposables); + } + } + } + } + } + } + + this.scrollableElement!.scanDomNode(); + } + + private getContentDescriptors(): IViewContentDescriptor[] { + const visibleItems = this.items.filter(v => v.visible); + + if (visibleItems.length === 0 && this.defaultItem) { + return [this.defaultItem.descriptor]; + } + + return visibleItems.map(v => v.descriptor); + } + + dispose(): void { + this.disposables.dispose(); + } + } + + export abstract class ViewPane extends Pane implements IView { + + private static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions'; + + private _onDidFocus = this._register(new Emitter()); + readonly onDidFocus: Event = this._onDidFocus.event; + + private _onDidBlur = this._register(new Emitter()); + readonly onDidBlur: Event = this._onDidBlur.event; + + private _onDidChangeBodyVisibility = this._register(new Emitter()); + readonly onDidChangeBodyVisibility: Event = this._onDidChangeBodyVisibility.event; + + protected _onDidChangeTitleArea = this._register(new Emitter()); + readonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event; + + protected _onDidChangeViewWelcomeState = this._register(new Emitter()); + readonly onDidChangeViewWelcomeState: Event = this._onDidChangeViewWelcomeState.event; + + private _isVisible: boolean = false; + readonly id: string; + + private _title: string; + public get title(): string { + return this._title; + } + + private _titleDescription: string | undefined; + public get titleDescription(): string | undefined { + return this._titleDescription; + } + + readonly menuActions: CompositeMenuActions; + + private progressBar!: ProgressBar; + private progressIndicator!: IProgressIndicator; + + private toolbar?: WorkbenchToolBar; + private readonly showActions: ViewPaneShowActions; + private headerContainer?: HTMLElement; + private titleContainer?: HTMLElement; + private titleDescriptionContainer?: HTMLElement; + private iconContainer?: HTMLElement; + protected twistiesContainer?: HTMLElement; + private viewWelcomeController!: ViewWelcomeController; + + protected readonly scopedContextKeyService: IContextKeyService; + + constructor( + options: IViewPaneOptions, + @IKeybindingService protected keybindingService: IKeybindingService, + @IContextMenuService protected contextMenuService: IContextMenuService, + @IConfigurationService protected readonly configurationService: IConfigurationService, + @IContextKeyService protected contextKeyService: IContextKeyService, + @IViewDescriptorService protected viewDescriptorService: IViewDescriptorService, + @IInstantiationService protected instantiationService: IInstantiationService, + @IOpenerService protected openerService: IOpenerService, + @IThemeService protected themeService: IThemeService, + @ITelemetryService protected telemetryService: ITelemetryService, + ) { + super({ ...options, ...{ orientation: viewDescriptorService.getViewLocationById(options.id) === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL } }); + + this.id = options.id; + this._title = options.title; + this._titleDescription = options.titleDescription; + this.showActions = options.showActions ?? ViewPaneShowActions.Default; + + this.scopedContextKeyService = this._register(contextKeyService.createScoped(this.element)); + this.scopedContextKeyService.createKey('view', this.id); + const viewLocationKey = this.scopedContextKeyService.createKey('viewLocation', ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!)); + this._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === this.id))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!)))); + + this.menuActions = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])).createInstance(CompositeMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs })); + this._register(this.menuActions.onDidChange(() => this.updateActions())); + } + + override get headerVisible(): boolean { + return super.headerVisible; + } + + override set headerVisible(visible: boolean) { + super.headerVisible = visible; + this.element.classList.toggle('merged-header', !visible); + } + + setVisible(visible: boolean): void { + if (this._isVisible !== visible) { + this._isVisible = visible; + + if (this.isExpanded()) { + this._onDidChangeBodyVisibility.fire(visible); + } + } + } + + isVisible(): boolean { + return this._isVisible; + } + + isBodyVisible(): boolean { + return this._isVisible && this.isExpanded(); + } + + override setExpanded(expanded: boolean): boolean { + const changed = super.setExpanded(expanded); + if (changed) { + this._onDidChangeBodyVisibility.fire(expanded); + } + if (this.twistiesContainer) { + this.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded))); + this.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded))); + } + return changed; + } + + override render(): void { + super.render(); + + const focusTracker = trackFocus(this.element); + this._register(focusTracker); + this._register(focusTracker.onDidFocus(() => this._onDidFocus.fire())); + this._register(focusTracker.onDidBlur(() => this._onDidBlur.fire())); + } + + protected renderHeader(container: HTMLElement): void { + this.headerContainer = container; + + this.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded())))); + + this.renderHeaderTitle(container, this.title); + + const actions = append(container, $('.actions')); + actions.classList.toggle('show-always', this.showActions === ViewPaneShowActions.Always); + actions.classList.toggle('show-expanded', this.showActions === ViewPaneShowActions.WhenExpanded); + this.toolbar = this.instantiationService.createInstance(WorkbenchToolBar, actions, { + orientation: ActionsOrientation.HORIZONTAL, + actionViewItemProvider: action => this.getActionViewItem(action), + ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.title), + getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), + renderDropdownAsChildElement: true, + actionRunner: this.getActionRunner(), + resetMenu: this.menuActions.menuId + }); + + this._register(this.toolbar); + this.setActions(); + + this._register(addDisposableListener(actions, EventType.CLICK, e => e.preventDefault())); + + const viewContainerModel = this.viewDescriptorService.getViewContainerByViewId(this.id); + if (viewContainerModel) { + this._register(this.viewDescriptorService.getViewContainerModel(viewContainerModel).onDidChangeContainerInfo(({ title }) => this.updateTitle(this.title))); + } else { + console.error(`View container model not found for view ${this.id}`); + } + + const onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig)); + this._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this)); + this.updateActionsVisibility(); + } + + protected getTwistyIcon(expanded: boolean): ThemeIcon { + return expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon; + } + + override style(styles: IPaneStyles): void { + super.style(styles); + + const icon = this.getIcon(); + if (this.iconContainer) { + const fgColor = asCssValueWithDefault(styles.headerForeground, asCssVariable(foreground)); + if (URI.isUri(icon)) { + // Apply background color to activity bar item provided with iconUrls + this.iconContainer.style.backgroundColor = fgColor; + this.iconContainer.style.color = ''; + } else { + // Apply foreground color to activity bar items provided with codicons + this.iconContainer.style.color = fgColor; + this.iconContainer.style.backgroundColor = ''; + } + } + } + + private getIcon(): ThemeIcon | URI { + return this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon; + } + + protected renderHeaderTitle(container: HTMLElement, title: string): void { + this.iconContainer = append(container, $('.icon', undefined)); + const icon = this.getIcon(); + + let cssClass: string | undefined = undefined; + if (URI.isUri(icon)) { + cssClass = `view-${this.id.replace(/[\.\:]/g, '-')}`; + const iconClass = `.pane-header .icon.${cssClass}`; + + createCSSRule(iconClass, ` + mask: ${asCSSUrl(icon)} no-repeat 50% 50%; + mask-size: 24px; + -webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%; + -webkit-mask-size: 16px; + `); + } else if (ThemeIcon.isThemeIcon(icon)) { + cssClass = ThemeIcon.asClassName(icon); + } + + if (cssClass) { + this.iconContainer.classList.add(...cssClass.split(' ')); + } + + const calculatedTitle = this.calculateTitle(title); + this.titleContainer = append(container, $('h3.title', { title: calculatedTitle }, calculatedTitle)); + + if (this._titleDescription) { + this.setTitleDescription(this._titleDescription); + } + + this.iconContainer.title = calculatedTitle; + this.iconContainer.setAttribute('aria-label', calculatedTitle); + } + + protected updateTitle(title: string): void { + const calculatedTitle = this.calculateTitle(title); + if (this.titleContainer) { + this.titleContainer.textContent = calculatedTitle; + this.titleContainer.setAttribute('title', calculatedTitle); + } + + if (this.iconContainer) { + this.iconContainer.title = calculatedTitle; + this.iconContainer.setAttribute('aria-label', calculatedTitle); + } + + this._title = title; + this._onDidChangeTitleArea.fire(); + } + + private setTitleDescription(description: string | undefined) { + if (this.titleDescriptionContainer) { + this.titleDescriptionContainer.textContent = description ?? ''; + this.titleDescriptionContainer.setAttribute('title', description ?? ''); + } + else if (description && this.titleContainer) { + this.titleDescriptionContainer = after(this.titleContainer, $('span.description', { title: description }, description)); + } + } + + protected updateTitleDescription(description?: string | undefined): void { + this.setTitleDescription(description); + + this._titleDescription = description; + this._onDidChangeTitleArea.fire(); + } + + private calculateTitle(title: string): string { + const viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!; + const model = this.viewDescriptorService.getViewContainerModel(viewContainer); + const viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id); + const isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer; + + if (!isDefault && viewDescriptor?.containerTitle && model.title !== viewDescriptor.containerTitle) { + return `${viewDescriptor.containerTitle}: ${title}`; + } + + return title; + } + + protected renderBody(container: HTMLElement): void { + this.viewWelcomeController = this._register(new ViewWelcomeController(container, this, this.instantiationService, this.openerService, this.telemetryService, this.contextKeyService)); + } + + protected layoutBody(height: number, width: number): void { + this.viewWelcomeController.layout(height, width); + } + + onDidScrollRoot() { + // noop + } + + getProgressIndicator() { + if (this.progressBar === undefined) { + // Progress bar + this.progressBar = this._register(new ProgressBar(this.element, defaultProgressBarStyles)); + this.progressBar.hide(); + } + + if (this.progressIndicator === undefined) { + const that = this; + this.progressIndicator = new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope { + constructor() { + super(that.id, that.isBodyVisible()); + this._register(that.onDidChangeBodyVisibility(isVisible => isVisible ? this.onScopeOpened(that.id) : this.onScopeClosed(that.id))); + } + }()); + } + return this.progressIndicator; + } + + protected getProgressLocation(): string { + return this.viewDescriptorService.getViewContainerByViewId(this.id)!.id; + } + + protected getBackgroundColor(): string { + switch (this.viewDescriptorService.getViewLocationById(this.id)) { + case ViewContainerLocation.Panel: + return PANEL_BACKGROUND; + case ViewContainerLocation.Sidebar: + case ViewContainerLocation.AuxiliaryBar: + return SIDE_BAR_BACKGROUND; + } + + return SIDE_BAR_BACKGROUND; + } + + focus(): void { + if (this.shouldShowWelcome()) { + this.viewWelcomeController.focus(); + } else if (this.element) { + this.element.focus(); + this._onDidFocus.fire(); + } + } + + private setActions(): void { + if (this.toolbar) { + const primaryActions = [...this.menuActions.getPrimaryActions()]; + if (this.shouldShowFilterInHeader()) { + primaryActions.unshift(VIEWPANE_FILTER_ACTION); + } + this.toolbar.setActions(prepareActions(primaryActions), prepareActions(this.menuActions.getSecondaryActions())); + this.toolbar.context = this.getActionsContext(); + } + } + + private updateActionsVisibility(): void { + if (!this.headerContainer) { + return; + } + const shouldAlwaysShowActions = this.configurationService.getValue('workbench.view.alwaysShowHeaderActions'); + this.headerContainer.classList.toggle('actions-always-visible', shouldAlwaysShowActions); + } + + protected updateActions(): void { + this.setActions(); + this._onDidChangeTitleArea.fire(); + } + + getActionViewItem(action: IAction, options?: IDropdownMenuActionViewItemOptions): IActionViewItem | undefined { + if (action.id === VIEWPANE_FILTER_ACTION.id) { + const that = this; + return new class extends BaseActionViewItem { + constructor() { super(null, action); } + override setFocusable(): void { /* noop input elements are focusable by default */ } + override get trapsArrowNavigation(): boolean { return true; } + override render(container: HTMLElement): void { + container.classList.add('viewpane-filter-container'); + append(container, that.getFilterWidget()!.element); + } + }; + } + return createActionViewItem(this.instantiationService, action, { ...options, ...{ menuAsChild: action instanceof SubmenuItemAction } }); + } + + getActionsContext(): unknown { + return undefined; + } + + getActionRunner(): IActionRunner | undefined { + return undefined; + } + + getOptimalWidth(): number { + return 0; + } + + saveState(): void { + // Subclasses to implement for saving state + } + + shouldShowWelcome(): boolean { + return false; + } + + getFilterWidget() \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/noisy-move1/advanced.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/advanced.expected.diff.json new file mode 100644 index 00000000000..09e850b054c --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/advanced.expected.diff.json @@ -0,0 +1,316 @@ +{ + "original": { + "content": "\tcontextKeyService.onDidChangeContext(this.onDidChangeContext, this, this.disposables);\n\t\tthis.disposables.add(Event.filter(viewsRegistry.onDidChangeViewWelcomeContent, id => id === this.id)(this.onDidChangeViewWelcomeContent, this, this.disposables));\n\t\tthis.onDidChangeViewWelcomeContent();\n\t}\n\n\tprivate onDidChangeViewWelcomeContent(): void {\n\t\tconst descriptors = viewsRegistry.getViewWelcomeContent(this.id);\n\n\t\tthis.items = [];\n\n\t\tfor (const descriptor of descriptors) {\n\t\t\tif (descriptor.when === 'default') {\n\t\t\t\tthis.defaultItem = { descriptor, visible: true };\n\t\t\t} else {\n\t\t\t\tconst visible = descriptor.when ? this.contextKeyService.contextMatchesRules(descriptor.when) : true;\n\t\t\t\tthis.items.push({ descriptor, visible });\n\t\t\t}\n\t\t}\n\n\t\tthis._onDidChange.fire();\n\t}\n\n\tprivate onDidChangeContext(): void {\n\t\tlet didChange = false;\n\n\t\tfor (const item of this.items) {\n\t\t\tif (!item.descriptor.when || item.descriptor.when === 'default') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst visible = this.contextKeyService.contextMatchesRules(item.descriptor.when);\n\n\t\t\tif (item.visible === visible) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titem.visible = visible;\n\t\t\tdidChange = true;\n\t\t}\n\n\t\tif (didChange) {\n\t\t\tthis._onDidChange.fire();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nexport abstract class ViewPane extends Pane implements IView {\n\n\tprivate static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions';\n\n\tprivate _onDidFocus = this._register(new Emitter());\n\treadonly onDidFocus: Event = this._onDidFocus.event;\n\n\tprivate _onDidBlur = this._register(new Emitter());\n\treadonly onDidBlur: Event = this._onDidBlur.event;\n\n\tprivate _onDidChangeBodyVisibility = this._register(new Emitter());\n\treadonly onDidChangeBodyVisibility: Event = this._onDidChangeBodyVisibility.event;\n\n\tprotected _onDidChangeTitleArea = this._register(new Emitter());\n\treadonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event;\n\n\tprotected _onDidChangeViewWelcomeState = this._register(new Emitter());\n\treadonly onDidChangeViewWelcomeState: Event = this._onDidChangeViewWelcomeState.event;\n\n\tprivate _isVisible: boolean = false;\n\treadonly id: string;\n\n\tprivate _title: string;\n\tpublic get title(): string {\n\t\treturn this._title;\n\t}\n\n\tprivate _titleDescription: string | undefined;\n\tpublic get titleDescription(): string | undefined {\n\t\treturn this._titleDescription;\n\t}\n\n\treadonly menuActions: CompositeMenuActions;\n\n\tprivate progressBar!: ProgressBar;\n\tprivate progressIndicator!: IProgressIndicator;\n\n\tprivate toolbar?: WorkbenchToolBar;\n\tprivate readonly showActions: ViewPaneShowActions;\n\tprivate headerContainer?: HTMLElement;\n\tprivate titleContainer?: HTMLElement;\n\tprivate titleDescriptionContainer?: HTMLElement;\n\tprivate iconContainer?: HTMLElement;\n\tprotected twistiesContainer?: HTMLElement;\n\n\tprivate bodyContainer!: HTMLElement;\n\tprivate viewWelcomeContainer!: HTMLElement;\n\tprivate viewWelcomeDisposable: IDisposable = Disposable.None;\n\tprivate viewWelcomeController: ViewWelcomeController;\n\n\tprotected readonly scopedContextKeyService: IContextKeyService;\n\n\tconstructor(\n\t\toptions: IViewPaneOptions,\n\t\t@IKeybindingService protected keybindingService: IKeybindingService,\n\t\t@IContextMenuService protected contextMenuService: IContextMenuService,\n\t\t@IConfigurationService protected readonly configurationService: IConfigurationService,\n\t\t@IContextKeyService protected contextKeyService: IContextKeyService,\n\t\t@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,\n\t\t@IInstantiationService protected instantiationService: IInstantiationService,\n\t\t@IOpenerService protected openerService: IOpenerService,\n\t\t@IThemeService protected themeService: IThemeService,\n\t\t@ITelemetryService protected telemetryService: ITelemetryService,\n\t) {\n\t\tsuper({ ...options, ...{ orientation: viewDescriptorService.getViewLocationById(options.id) === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL } });\n\n\t\tthis.id = options.id;\n\t\tthis._title = options.title;\n\t\tthis._titleDescription = options.titleDescription;\n\t\tthis.showActions = options.showActions ?? ViewPaneShowActions.Default;\n\n\t\tthis.scopedContextKeyService = this._register(contextKeyService.createScoped(this.element));\n\t\tthis.scopedContextKeyService.createKey('view', this.id);\n\t\tconst viewLocationKey = this.scopedContextKeyService.createKey('viewLocation', ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!));\n\t\tthis._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === this.id))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!))));\n\n\t\tthis.menuActions = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])).createInstance(CompositeMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs }));\n\t\tthis._register(this.menuActions.onDidChange(() => this.updateActions()));\n\n\t\tthis.viewWelcomeController = this._register(new ViewWelcomeController(this.id, contextKeyService));\n\t}\n\n\toverride get headerVisible(): boolean {\n\t\treturn super.headerVisible;\n\t}\n\n\toverride set headerVisible(visible: boolean) {\n\t\tsuper.headerVisible = visible;\n\t\tthis.element.classList.toggle('merged-header', !visible);\n\t}\n\n\tsetVisible(visible: boolean): void {\n\t\tif (this._isVisible !== visible) {\n\t\t\tthis._isVisible = visible;\n\n\t\t\tif (this.isExpanded()) {\n\t\t\t\tthis._onDidChangeBodyVisibility.fire(visible);\n\t\t\t}\n\t\t}\n\t}\n\n\tisVisible(): boolean {\n\t\treturn this._isVisible;\n\t}\n\n\tisBodyVisible(): boolean {\n\t\treturn this._isVisible && this.isExpanded();\n\t}\n\n\toverride setExpanded(expanded: boolean): boolean {\n\t\tconst changed = super.setExpanded(expanded);\n\t\tif (changed) {\n\t\t\tthis._onDidChangeBodyVisibility.fire(expanded);\n\t\t}\n\t\tif (this.twistiesContainer) {\n\t\t\tthis.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded)));\n\t\t\tthis.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded)));\n\t\t}\n\t\treturn changed;\n\t}\n\n\toverride render(): void {\n\t\tsuper.render();\n\n\t\tconst focusTracker = trackFocus(this.element);\n\t\tthis._register(focusTracker);\n\t\tthis._register(focusTracker.onDidFocus(() => this._onDidFocus.fire()));\n\t\tthis._register(focusTracker.onDidBlur(() => this._onDidBlur.fire()));\n\t}\n\n\tprotected renderHeader(container: HTMLElement): void {\n\t\tthis.headerContainer = container;\n\n\t\tthis.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded()))));\n\n\t\tthis.renderHeaderTitle(container, this.title);\n\n\t\tconst actions = append(container, $('.actions'));\n\t\tactions.classList.toggle('show-always', this.showActions === ViewPaneShowActions.Always);\n\t\tactions.classList.toggle('show-expanded', this.showActions === ViewPaneShowActions.WhenExpanded);\n\t\tthis.toolbar = this.instantiationService.createInstance(WorkbenchToolBar, actions, {\n\t\t\torientation: ActionsOrientation.HORIZONTAL,\n\t\t\tactionViewItemProvider: action => this.getActionViewItem(action),\n\t\t\tariaLabel: nls.localize('viewToolbarAriaLabel', \"{0} actions\", this.title),\n\t\t\tgetKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),\n\t\t\trenderDropdownAsChildElement: true,\n\t\t\tactionRunner: this.getActionRunner(),\n\t\t\tresetMenu: this.menuActions.menuId\n\t\t});\n\n\t\tthis._register(this.toolbar);\n\t\tthis.setActions();\n\n\t\tthis._register(addDisposableListener(actions, EventType.CLICK, e => e.preventDefault()));\n\n\t\tconst viewContainerModel = this.viewDescriptorService.getViewContainerByViewId(this.id);\n\t\tif (viewContainerModel) {\n\t\t\tthis._register(this.viewDescriptorService.getViewContainerModel(viewContainerModel).onDidChangeContainerInfo(({ title }) => this.updateTitle(this.title)));\n\t\t} else {\n\t\t\tconsole.error(`View container model not found for view ${this.id}`);\n\t\t}\n\n\t\tconst onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig));\n\t\tthis._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this));\n\t\tthis.updateActionsVisibility();\n\t}\n\n\tprotected getTwistyIcon(expanded: boolean): ThemeIcon {\n\t\treturn expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon;\n\t}\n\n\toverride style(styles: IPaneStyles): void {\n\t\tsuper.style(styles);\n\n\t\tconst icon = this.getIcon();\n\t\tif (this.iconContainer) {\n\t\t\tconst fgColor = asCssValueWithDefault(styles.headerForeground, asCssVariable(foreground));\n\t\t\tif (URI.isUri(icon)) {\n\t\t\t\t// Apply background color to activity bar item provided with iconUrls\n\t\t\t\tthis.iconContainer.style.backgroundColor = fgColor;\n\t\t\t\tthis.iconContainer.style.color = '';\n\t\t\t} else {\n\t\t\t\t// Apply foreground color to activity bar items provided with codicons\n\t\t\t\tthis.iconContainer.style.color = fgColor;\n\t\t\t\tthis.iconContainer.style.backgroundColor = '';\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getIcon(): ThemeIcon | URI {\n\t\treturn this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon;\n\t}\n\n\tprotected renderHeaderTitle(container: HTMLElement, title: string): void {\n\t\tthis.iconContainer = append(container, $('.icon', undefined));\n\t\tconst icon = this.getIcon();\n\n\t\tlet cssClass: string | undefined = undefined;\n\t\tif (URI.isUri(icon)) {\n\t\t\tcssClass = `view-${this.id.replace(/[\\.\\:]/g, '-')}`;\n\t\t\tconst iconClass = `.pane-header .icon.${cssClass}`;\n\n\t\t\tcreateCSSRule(iconClass, `\n\t\t\t\tmask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\tmask-size: 24px;\n\t\t\t\t-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\t-webkit-mask-size: 16px;\n\t\t\t`);\n\t\t} else if (ThemeIcon.isThemeIcon(icon)) {\n\t\t\tcssClass = ThemeIcon.asClassName(icon);\n\t\t}\n\n\t\tif (cssClass) {\n\t\t\tthis.iconContainer.classList.add(...cssClass.split(' '));\n\t\t}\n\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tthis.titleContainer = append(container, $('h3.title', { title: calculatedTitle }, calculatedTitle));\n\n\t\tif (this._titleDescription) {\n\t\t\tthis.setTitleDescription(this._titleDescription);\n\t\t}\n\n\t\tthis.iconContainer.title = calculatedTitle;\n\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t}\n\n\tprotected updateTitle(title: string): void {\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tif (this.titleContainer) {\n\t\t\tthis.titleContainer.textContent = calculatedTitle;\n\t\t\tthis.titleContainer.setAttribute('title', calculatedTitle);\n\t\t}\n\n\t\tif (this.iconContainer) {\n\t\t\tthis.iconContainer.title = calculatedTitle;\n\t\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t\t}\n\n\t\tthis._title = title;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate setTitleDescription(description: string | undefined) {\n\t\tif (this.titleDescriptionContainer) {\n\t\t\tthis.titleDescriptionContainer.textContent = description ?? '';\n\t\t\tthis.titleDescriptionContainer.setAttribute('title', description ?? '');\n\t\t}\n\t\telse if (description && this.titleContainer) {\n\t\t\tthis.titleDescriptionContainer = after(this.titleContainer, $('span.description', { title: description }, description));\n\t\t}\n\t}\n\n\tprotected updateTitleDescription(description?: string | undefined): void {\n\t\tthis.setTitleDescription(description);\n\n\t\tthis._titleDescription = description;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate calculateTitle(title: string): string {\n\t\tconst viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!;\n\t\tconst model = this.viewDescriptorService.getViewContainerModel(viewContainer);\n\t\tconst viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id);\n\t\tconst isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer;\n\n\t\tif (!isDefault && viewDescriptor?.containerTitle && model.title !== viewDescriptor.containerTitle) {\n\t\t\treturn `${viewDescriptor.containerTitle}: ${title}`;\n\t\t}\n\n\t\treturn title;\n\t}\n\n\tprivate scrollableElement!: DomScrollableElement;\n\n\tprotected renderBody(container: HTMLElement): void {\n\t\tthis.bodyContainer = container;\n\n\t\tconst viewWelcomeContainer = append(container, $('.welcome-view'));\n\t\tthis.viewWelcomeContainer = $('.welcome-view-content', { tabIndex: 0 });\n\t\tthis.scrollableElement = this._register(new DomScrollableElement(this.viewWelcomeContainer, {\n\t\t\talwaysConsumeMouseWheel: true,\n\t\t\thorizontal: ScrollbarVisibility.Hidden,\n\t\t\tvertical: ScrollbarVisibility.Visible,\n\t\t}));\n\n\t\tappend(viewWelcomeContainer, this.scrollableElement.getDomNode());\n\n\t\tconst onViewWelcomeChange = Event.any(this.viewWelcomeController.onDidChange, this.onDidChangeViewWelcomeState);\n\t\tthis._register(onViewWelcomeChange(this.updateViewWelcome, this));\n\t\tthis.updateViewWelcome();\n\t}\n\n\tprotected layoutBody(height: number, width: number): void {\n\t\tif (this.shouldShowWelcome()) {\n\t\t\tthis.viewWelcomeContainer.style.height = `${height}px`;\n\t\t\tthis.viewWelcomeContainer.style.width = `${width}px`;\n\t\t\tthis.viewWelcomeContainer.classList.toggle('wide', width > 640);\n\t\t\tthis.scrollableElement.scanDomNode();\n\t\t}\n\t}\n\n\tonDidScrollRoot() {\n\t\t// noop\n\t}\n\n\tgetProgressIndicator() {\n\t\tif (this.progressBar === undefined) {\n\t\t\t// Progress bar\n\t\t\tthis.progressBar = this._register(new ProgressBar(this.element, defaultProgressBarStyles));\n\t\t\tthis.progressBar.hide();\n\t\t}\n\n\t\tif (this.progressIndicator === undefined) {\n\t\t\tconst that = this;\n\t\t\tthis.progressIndicator = new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope {\n\t\t\t\tconstructor() {\n\t\t\t\t\tsuper(that.id, that.isBodyVisible());\n\t\t\t\t\tthis._register(that.onDidChangeBodyVisibility(isVisible => isVisible ? this.onScopeOpened(that.id) : this.onScopeClosed(that.id)));\n\t\t\t\t}\n\t\t\t}());\n\t\t}\n\t\treturn this.progressIndicator;\n\t}\n\n\tprotected getProgressLocation(): string {\n\t\treturn this.viewDescriptorService.getViewContainerByViewId(this.id)!.id;\n\t}\n\n\tprotected getBackgroundColor(): string {\n\t\tswitch (this.viewDescriptorService.getViewLocationById(this.id)) {\n\t\t\tcase ViewContainerLocation.Panel:\n\t\t\t\treturn PANEL_BACKGROUND;\n\t\t\tcase ViewContainerLocation.Sidebar:\n\t\t\tcase ViewContainerLocation.AuxiliaryBar:\n\t\t\t\treturn SIDE_BAR_BACKGROUND;\n\t\t}\n\n\t\treturn SIDE_BAR_BACKGROUND;\n\t}\n\n\tfocus(): void {\n\t\tif (this.shouldShowWelcome()) {\n\t\t\tthis.viewWelcomeContainer.focus();\n\t\t} else if (this.element) {\n\t\t\tthis.element.focus();\n\t\t\tthis._onDidFocus.fire();\n\t\t}\n\t}\n\n\tprivate setActions(): void {\n\t\tif (this.toolbar) {\n\t\t\tconst primaryActions = [...this.menuActions.getPrimaryActions()];\n\t\t\tif (this.shouldShowFilterInHeader()) {\n\t\t\t\tprimaryActions.unshift(VIEWPANE_FILTER_ACTION);\n\t\t\t}\n\t\t\tthis.toolbar.setActions(prepareActions(primaryActions), prepareActions(this.menuActions.getSecondaryActions()));\n\t\t\tthis.toolbar.context = this.getActionsContext();\n\t\t}\n\t}\n\n\tprivate updateActionsVisibility(): void {\n\t\tif (!this.headerContainer) {\n\t\t\treturn;\n\t\t}\n\t\tconst shouldAlwaysShowActions = this.configurationService.getValue('workbench.view.alwaysShowHeaderActions');\n\t\tthis.headerContainer.classList.toggle('actions-always-visible', shouldAlwaysShowActions);\n\t}\n\n\tprotected updateActions(): void {\n\t\tthis.setActions();\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tgetActionViewItem(action: IAction, options?: IDropdownMenuActionViewItemOptions): IActionViewItem | undefined {\n\t\tif (action.id === VIEWPANE_FILTER_ACTION.id) {\n\t\t\tconst that = this;\n\t\t\treturn new class extends BaseActionViewItem {\n\t\t\t\tconstructor() { super(null, action); }\n\t\t\t\toverride setFocusable(): void { /* noop input elements are focusable by default */ }\n\t\t\t\toverride get trapsArrowNavigation(): boolean { return true; }\n\t\t\t\toverride render(container: HTMLElement): void {\n\t\t\t\t\tcontainer.classList.add('viewpane-filter-container');\n\t\t\t\t\tappend(container, that.getFilterWidget()!.element);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\treturn createActionViewItem(this.instantiationService, action, { ...options, ...{ menuAsChild: action instanceof SubmenuItemAction } });\n\t}\n\n\tgetActionsContext(): unknown {\n\t\treturn undefined;\n\t}\n\n\tgetActionRunner(): IActionRunner | undefined {\n\t\treturn undefined;\n\t}\n\n\tgetOptimalWidth(): number {\n\t\treturn 0;\n\t}\n\n\tsaveState(): void {\n\t\t// Subclasses to implement for saving state\n\t}\n\n\tprivate updateViewWelcome(): void {\n\t\tthis.viewWelcomeDisposable.dispose();\n\n\t\tif (!this.shouldShowWelcome()) {\n\t\t\tthis.bodyContainer.classList.remove('welcome');\n\t\t\tthis.viewWelcomeContainer.innerText = '';\n\t\t\tthis.scrollableElement.scanDomNode();\n\t\t\treturn;\n\t\t}\n\n\t\tconst contents = this.viewWelcomeController.contents;\n\n\t\tif (contents.length === 0) {\n\t\t\tthis.bodyContainer.classList.remove('welcome');\n\t\t\tthis.viewWelcomeContainer.innerText = '';\n\t\t\tthis.scrollableElement.scanDomNode();\n\t\t\treturn;\n\t\t}\n\n\t\tconst disposables = new DisposableStore();\n\t\tthis.bodyContainer.classList.add('welcome');\n\t\tthis.viewWelcomeContainer.innerText = '';\n\n\t\tfor (const { content, precondition } of contents) {\n\t\t\tconst lines = content.split('\\n');\n\n\t\t\tfor (let line of lines) {\n\t\t\t\tline = line.trim();\n\n\t\t\t\tif (!line) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst linkedText = parseLinkedText(line);\n\n\t\t\t\tif (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') {\n\t\t\t\t\tconst node = linkedText.nodes[0];\n\t\t\t\t\tconst buttonContainer = append(this.viewWelcomeContainer, $('.button-container'));\n\t\t\t\t\tconst button = new Button(buttonContainer, { title: node.title, supportIcons: true, ...defaultButtonStyles });\n\t\t\t\t\tbutton.label = node.label;\n\t\t\t\t\tbutton.onDidClick(_ => {\n\t\t\t\t\t\tthis.telemetryService.publicLog2<{ viewId: string; uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href });\n\t\t\t\t\t\tthis.openerService.open(node.href, { allowCommands: true });\n\t\t\t\t\t}, null, disposables);\n\t\t\t\t\tdisposables.add(button);\n\n\t\t\t\t\tif (precondition) {\n\t\t\t\t\t\tconst updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\tconst keys = new Set();\n\t\t\t\t\t\tprecondition.keys().forEach(key => keys.add(key));\n\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, disposables);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst p = append(this.viewWelcomeContainer, $('p'));\n\n\t\t\t\t\tfor (const node of linkedText.nodes) {\n\t\t\t\t\t\tif (typeof node === 'string') {\n\t\t\t\t\t\t\tappend(p, document.createTextNode(node));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst link = disposables.add(this.instantiationService.createInstance(Link, p, node, {}));\n\n\t\t\t\t\t\t\tif (precondition && node.href.startsWith('command:')) {\n\t\t\t\t\t\t\t\tconst updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\t\t\tconst keys = new Set();\n\t\t\t\t\t\t\t\tprecondition.keys().forEach(key => keys.add(key));\n\t\t\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, disposables);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.scrollableElement.scanDomNode();\n\t\tthis.viewWelcomeDisposable = disposables;\n\t}\n\n\tshouldShowWelcome(): boolean {\n\t\treturn false;\n\t}\n\n\tgetFilterWidget()", + "fileName": "./1.tst" + }, + "modified": { + "content": "\n\tlayout(height: number, width: number) {\n\t\tif (!this.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.element!.style.height = `${height}px`;\n\t\tthis.element!.style.width = `${width}px`;\n\t\tthis.element!.classList.toggle('wide', width > 640);\n\t\tthis.scrollableElement!.scanDomNode();\n\t}\n\n\tfocus() {\n\t\tif (!this.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.element!.focus();\n\t}\n\n\tprivate onDidChangeViewWelcomeState(): void {\n\t\tconst enabled = this.delegate.shouldShowWelcome();\n\n\t\tif (this.enabled === enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.enabled = enabled;\n\n\t\tif (!enabled) {\n\t\t\tthis.enabledDisposables.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.container.classList.add('welcome');\n\t\tconst viewWelcomeContainer = append(this.container, $('.welcome-view'));\n\t\tthis.element = $('.welcome-view-content', { tabIndex: 0 });\n\t\tthis.scrollableElement = new DomScrollableElement(this.element, { alwaysConsumeMouseWheel: true, horizontal: ScrollbarVisibility.Hidden, vertical: ScrollbarVisibility.Visible, });\n\t\tappend(viewWelcomeContainer, this.scrollableElement.getDomNode());\n\n\t\tthis.enabledDisposables.add(toDisposable(() => {\n\t\t\tthis.container.classList.remove('welcome');\n\t\t\tthis.scrollableElement!.dispose();\n\t\t\tviewWelcomeContainer.remove();\n\t\t\tthis.scrollableElement = undefined;\n\t\t\tthis.element = undefined;\n\t\t}));\n\n\t\tthis.contextKeyService.onDidChangeContext(this.onDidChangeContext, this, this.enabledDisposables);\n\t\tEvent.chain(viewsRegistry.onDidChangeViewWelcomeContent, $ => $.filter(id => id === this.delegate.id))\n\t\t\t(this.onDidChangeViewWelcomeContent, this, this.enabledDisposables);\n\t\tthis.onDidChangeViewWelcomeContent();\n\t}\n\n\tprivate onDidChangeViewWelcomeContent(): void {\n\t\tconst descriptors = viewsRegistry.getViewWelcomeContent(this.delegate.id);\n\n\t\tthis.items = [];\n\n\t\tfor (const descriptor of descriptors) {\n\t\t\tif (descriptor.when === 'default') {\n\t\t\t\tthis.defaultItem = { descriptor, visible: true };\n\t\t\t} else {\n\t\t\t\tconst visible = descriptor.when ? this.contextKeyService.contextMatchesRules(descriptor.when) : true;\n\t\t\t\tthis.items.push({ descriptor, visible });\n\t\t\t}\n\t\t}\n\n\t\tthis.render();\n\t}\n\n\tprivate onDidChangeContext(): void {\n\t\tlet didChange = false;\n\n\t\tfor (const item of this.items) {\n\t\t\tif (!item.descriptor.when || item.descriptor.when === 'default') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst visible = this.contextKeyService.contextMatchesRules(item.descriptor.when);\n\n\t\t\tif (item.visible === visible) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titem.visible = visible;\n\t\t\tdidChange = true;\n\t\t}\n\n\t\tif (didChange) {\n\t\t\tthis.render();\n\t\t}\n\t}\n\n\tprivate render(): void {\n\t\tthis.renderDisposables.clear();\n\n\t\tconst contents = this.getContentDescriptors();\n\n\t\tif (contents.length === 0) {\n\t\t\tthis.container.classList.remove('welcome');\n\t\t\tthis.element!.innerText = '';\n\t\t\tthis.scrollableElement!.scanDomNode();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.container.classList.add('welcome');\n\t\tthis.element!.innerText = '';\n\n\t\tfor (const { content, precondition } of contents) {\n\t\t\tconst lines = content.split('\\n');\n\n\t\t\tfor (let line of lines) {\n\t\t\t\tline = line.trim();\n\n\t\t\t\tif (!line) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst linkedText = parseLinkedText(line);\n\n\t\t\t\tif (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') {\n\t\t\t\t\tconst node = linkedText.nodes[0];\n\t\t\t\t\tconst buttonContainer = append(this.element!, $('.button-container'));\n\t\t\t\t\tconst button = new Button(buttonContainer, { title: node.title, supportIcons: true, ...defaultButtonStyles });\n\t\t\t\t\tbutton.label = node.label;\n\t\t\t\t\tbutton.onDidClick(_ => {\n\t\t\t\t\t\tthis.telemetryService.publicLog2<{ viewId: string; uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.delegate.id, uri: node.href });\n\t\t\t\t\t\tthis.openerService.open(node.href, { allowCommands: true });\n\t\t\t\t\t}, null, this.renderDisposables);\n\t\t\t\t\tthis.renderDisposables.add(button);\n\n\t\t\t\t\tif (precondition) {\n\t\t\t\t\t\tconst updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\tconst keys = new Set(precondition.keys());\n\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, this.renderDisposables);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst p = append(this.element!, $('p'));\n\n\t\t\t\t\tfor (const node of linkedText.nodes) {\n\t\t\t\t\t\tif (typeof node === 'string') {\n\t\t\t\t\t\t\tappend(p, document.createTextNode(node));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst link = this.renderDisposables.add(this.instantiationService.createInstance(Link, p, node, {}));\n\n\t\t\t\t\t\t\tif (precondition && node.href.startsWith('command:')) {\n\t\t\t\t\t\t\t\tconst updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\t\t\tconst keys = new Set(precondition.keys());\n\t\t\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, this.renderDisposables);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.scrollableElement!.scanDomNode();\n\t}\n\n\tprivate getContentDescriptors(): IViewContentDescriptor[] {\n\t\tconst visibleItems = this.items.filter(v => v.visible);\n\n\t\tif (visibleItems.length === 0 && this.defaultItem) {\n\t\t\treturn [this.defaultItem.descriptor];\n\t\t}\n\n\t\treturn visibleItems.map(v => v.descriptor);\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n\t}\n\n\texport abstract class ViewPane extends Pane implements IView {\n\n\tprivate static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions';\n\n\tprivate _onDidFocus = this._register(new Emitter());\n\treadonly onDidFocus: Event = this._onDidFocus.event;\n\n\tprivate _onDidBlur = this._register(new Emitter());\n\treadonly onDidBlur: Event = this._onDidBlur.event;\n\n\tprivate _onDidChangeBodyVisibility = this._register(new Emitter());\n\treadonly onDidChangeBodyVisibility: Event = this._onDidChangeBodyVisibility.event;\n\n\tprotected _onDidChangeTitleArea = this._register(new Emitter());\n\treadonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event;\n\n\tprotected _onDidChangeViewWelcomeState = this._register(new Emitter());\n\treadonly onDidChangeViewWelcomeState: Event = this._onDidChangeViewWelcomeState.event;\n\n\tprivate _isVisible: boolean = false;\n\treadonly id: string;\n\n\tprivate _title: string;\n\tpublic get title(): string {\n\t\treturn this._title;\n\t}\n\n\tprivate _titleDescription: string | undefined;\n\tpublic get titleDescription(): string | undefined {\n\t\treturn this._titleDescription;\n\t}\n\n\treadonly menuActions: CompositeMenuActions;\n\n\tprivate progressBar!: ProgressBar;\n\tprivate progressIndicator!: IProgressIndicator;\n\n\tprivate toolbar?: WorkbenchToolBar;\n\tprivate readonly showActions: ViewPaneShowActions;\n\tprivate headerContainer?: HTMLElement;\n\tprivate titleContainer?: HTMLElement;\n\tprivate titleDescriptionContainer?: HTMLElement;\n\tprivate iconContainer?: HTMLElement;\n\tprotected twistiesContainer?: HTMLElement;\n\tprivate viewWelcomeController!: ViewWelcomeController;\n\n\tprotected readonly scopedContextKeyService: IContextKeyService;\n\n\tconstructor(\n\t\toptions: IViewPaneOptions,\n\t\t@IKeybindingService protected keybindingService: IKeybindingService,\n\t\t@IContextMenuService protected contextMenuService: IContextMenuService,\n\t\t@IConfigurationService protected readonly configurationService: IConfigurationService,\n\t\t@IContextKeyService protected contextKeyService: IContextKeyService,\n\t\t@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,\n\t\t@IInstantiationService protected instantiationService: IInstantiationService,\n\t\t@IOpenerService protected openerService: IOpenerService,\n\t\t@IThemeService protected themeService: IThemeService,\n\t\t@ITelemetryService protected telemetryService: ITelemetryService,\n\t) {\n\t\tsuper({ ...options, ...{ orientation: viewDescriptorService.getViewLocationById(options.id) === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL } });\n\n\t\tthis.id = options.id;\n\t\tthis._title = options.title;\n\t\tthis._titleDescription = options.titleDescription;\n\t\tthis.showActions = options.showActions ?? ViewPaneShowActions.Default;\n\n\t\tthis.scopedContextKeyService = this._register(contextKeyService.createScoped(this.element));\n\t\tthis.scopedContextKeyService.createKey('view', this.id);\n\t\tconst viewLocationKey = this.scopedContextKeyService.createKey('viewLocation', ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!));\n\t\tthis._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === this.id))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!))));\n\n\t\tthis.menuActions = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])).createInstance(CompositeMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs }));\n\t\tthis._register(this.menuActions.onDidChange(() => this.updateActions()));\n\t}\n\n\toverride get headerVisible(): boolean {\n\t\treturn super.headerVisible;\n\t}\n\n\toverride set headerVisible(visible: boolean) {\n\t\tsuper.headerVisible = visible;\n\t\tthis.element.classList.toggle('merged-header', !visible);\n\t}\n\n\tsetVisible(visible: boolean): void {\n\t\tif (this._isVisible !== visible) {\n\t\t\tthis._isVisible = visible;\n\n\t\t\tif (this.isExpanded()) {\n\t\t\t\tthis._onDidChangeBodyVisibility.fire(visible);\n\t\t\t}\n\t\t}\n\t}\n\n\tisVisible(): boolean {\n\t\treturn this._isVisible;\n\t}\n\n\tisBodyVisible(): boolean {\n\t\treturn this._isVisible && this.isExpanded();\n\t}\n\n\toverride setExpanded(expanded: boolean): boolean {\n\t\tconst changed = super.setExpanded(expanded);\n\t\tif (changed) {\n\t\t\tthis._onDidChangeBodyVisibility.fire(expanded);\n\t\t}\n\t\tif (this.twistiesContainer) {\n\t\t\tthis.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded)));\n\t\t\tthis.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded)));\n\t\t}\n\t\treturn changed;\n\t}\n\n\toverride render(): void {\n\t\tsuper.render();\n\n\t\tconst focusTracker = trackFocus(this.element);\n\t\tthis._register(focusTracker);\n\t\tthis._register(focusTracker.onDidFocus(() => this._onDidFocus.fire()));\n\t\tthis._register(focusTracker.onDidBlur(() => this._onDidBlur.fire()));\n\t}\n\n\tprotected renderHeader(container: HTMLElement): void {\n\t\tthis.headerContainer = container;\n\n\t\tthis.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded()))));\n\n\t\tthis.renderHeaderTitle(container, this.title);\n\n\t\tconst actions = append(container, $('.actions'));\n\t\tactions.classList.toggle('show-always', this.showActions === ViewPaneShowActions.Always);\n\t\tactions.classList.toggle('show-expanded', this.showActions === ViewPaneShowActions.WhenExpanded);\n\t\tthis.toolbar = this.instantiationService.createInstance(WorkbenchToolBar, actions, {\n\t\t\torientation: ActionsOrientation.HORIZONTAL,\n\t\t\tactionViewItemProvider: action => this.getActionViewItem(action),\n\t\t\tariaLabel: nls.localize('viewToolbarAriaLabel', \"{0} actions\", this.title),\n\t\t\tgetKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),\n\t\t\trenderDropdownAsChildElement: true,\n\t\t\tactionRunner: this.getActionRunner(),\n\t\t\tresetMenu: this.menuActions.menuId\n\t\t});\n\n\t\tthis._register(this.toolbar);\n\t\tthis.setActions();\n\n\t\tthis._register(addDisposableListener(actions, EventType.CLICK, e => e.preventDefault()));\n\n\t\tconst viewContainerModel = this.viewDescriptorService.getViewContainerByViewId(this.id);\n\t\tif (viewContainerModel) {\n\t\t\tthis._register(this.viewDescriptorService.getViewContainerModel(viewContainerModel).onDidChangeContainerInfo(({ title }) => this.updateTitle(this.title)));\n\t\t} else {\n\t\t\tconsole.error(`View container model not found for view ${this.id}`);\n\t\t}\n\n\t\tconst onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig));\n\t\tthis._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this));\n\t\tthis.updateActionsVisibility();\n\t}\n\n\tprotected getTwistyIcon(expanded: boolean): ThemeIcon {\n\t\treturn expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon;\n\t}\n\n\toverride style(styles: IPaneStyles): void {\n\t\tsuper.style(styles);\n\n\t\tconst icon = this.getIcon();\n\t\tif (this.iconContainer) {\n\t\t\tconst fgColor = asCssValueWithDefault(styles.headerForeground, asCssVariable(foreground));\n\t\t\tif (URI.isUri(icon)) {\n\t\t\t\t// Apply background color to activity bar item provided with iconUrls\n\t\t\t\tthis.iconContainer.style.backgroundColor = fgColor;\n\t\t\t\tthis.iconContainer.style.color = '';\n\t\t\t} else {\n\t\t\t\t// Apply foreground color to activity bar items provided with codicons\n\t\t\t\tthis.iconContainer.style.color = fgColor;\n\t\t\t\tthis.iconContainer.style.backgroundColor = '';\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getIcon(): ThemeIcon | URI {\n\t\treturn this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon;\n\t}\n\n\tprotected renderHeaderTitle(container: HTMLElement, title: string): void {\n\t\tthis.iconContainer = append(container, $('.icon', undefined));\n\t\tconst icon = this.getIcon();\n\n\t\tlet cssClass: string | undefined = undefined;\n\t\tif (URI.isUri(icon)) {\n\t\t\tcssClass = `view-${this.id.replace(/[\\.\\:]/g, '-')}`;\n\t\t\tconst iconClass = `.pane-header .icon.${cssClass}`;\n\n\t\t\tcreateCSSRule(iconClass, `\n\t\t\t\tmask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\tmask-size: 24px;\n\t\t\t\t-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\t-webkit-mask-size: 16px;\n\t\t\t`);\n\t\t} else if (ThemeIcon.isThemeIcon(icon)) {\n\t\t\tcssClass = ThemeIcon.asClassName(icon);\n\t\t}\n\n\t\tif (cssClass) {\n\t\t\tthis.iconContainer.classList.add(...cssClass.split(' '));\n\t\t}\n\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tthis.titleContainer = append(container, $('h3.title', { title: calculatedTitle }, calculatedTitle));\n\n\t\tif (this._titleDescription) {\n\t\t\tthis.setTitleDescription(this._titleDescription);\n\t\t}\n\n\t\tthis.iconContainer.title = calculatedTitle;\n\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t}\n\n\tprotected updateTitle(title: string): void {\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tif (this.titleContainer) {\n\t\t\tthis.titleContainer.textContent = calculatedTitle;\n\t\t\tthis.titleContainer.setAttribute('title', calculatedTitle);\n\t\t}\n\n\t\tif (this.iconContainer) {\n\t\t\tthis.iconContainer.title = calculatedTitle;\n\t\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t\t}\n\n\t\tthis._title = title;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate setTitleDescription(description: string | undefined) {\n\t\tif (this.titleDescriptionContainer) {\n\t\t\tthis.titleDescriptionContainer.textContent = description ?? '';\n\t\t\tthis.titleDescriptionContainer.setAttribute('title', description ?? '');\n\t\t}\n\t\telse if (description && this.titleContainer) {\n\t\t\tthis.titleDescriptionContainer = after(this.titleContainer, $('span.description', { title: description }, description));\n\t\t}\n\t}\n\n\tprotected updateTitleDescription(description?: string | undefined): void {\n\t\tthis.setTitleDescription(description);\n\n\t\tthis._titleDescription = description;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate calculateTitle(title: string): string {\n\t\tconst viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!;\n\t\tconst model = this.viewDescriptorService.getViewContainerModel(viewContainer);\n\t\tconst viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id);\n\t\tconst isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer;\n\n\t\tif (!isDefault && viewDescriptor?.containerTitle && model.title !== viewDescriptor.containerTitle) {\n\t\t\treturn `${viewDescriptor.containerTitle}: ${title}`;\n\t\t}\n\n\t\treturn title;\n\t}\n\n\tprotected renderBody(container: HTMLElement): void {\n\t\tthis.viewWelcomeController = this._register(new ViewWelcomeController(container, this, this.instantiationService, this.openerService, this.telemetryService, this.contextKeyService));\n\t}\n\n\tprotected layoutBody(height: number, width: number): void {\n\t\tthis.viewWelcomeController.layout(height, width);\n\t}\n\n\tonDidScrollRoot() {\n\t\t// noop\n\t}\n\n\tgetProgressIndicator() {\n\t\tif (this.progressBar === undefined) {\n\t\t\t// Progress bar\n\t\t\tthis.progressBar = this._register(new ProgressBar(this.element, defaultProgressBarStyles));\n\t\t\tthis.progressBar.hide();\n\t\t}\n\n\t\tif (this.progressIndicator === undefined) {\n\t\t\tconst that = this;\n\t\t\tthis.progressIndicator = new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope {\n\t\t\t\tconstructor() {\n\t\t\t\t\tsuper(that.id, that.isBodyVisible());\n\t\t\t\t\tthis._register(that.onDidChangeBodyVisibility(isVisible => isVisible ? this.onScopeOpened(that.id) : this.onScopeClosed(that.id)));\n\t\t\t\t}\n\t\t\t}());\n\t\t}\n\t\treturn this.progressIndicator;\n\t}\n\n\tprotected getProgressLocation(): string {\n\t\treturn this.viewDescriptorService.getViewContainerByViewId(this.id)!.id;\n\t}\n\n\tprotected getBackgroundColor(): string {\n\t\tswitch (this.viewDescriptorService.getViewLocationById(this.id)) {\n\t\t\tcase ViewContainerLocation.Panel:\n\t\t\t\treturn PANEL_BACKGROUND;\n\t\t\tcase ViewContainerLocation.Sidebar:\n\t\t\tcase ViewContainerLocation.AuxiliaryBar:\n\t\t\t\treturn SIDE_BAR_BACKGROUND;\n\t\t}\n\n\t\treturn SIDE_BAR_BACKGROUND;\n\t}\n\n\tfocus(): void {\n\t\tif (this.shouldShowWelcome()) {\n\t\t\tthis.viewWelcomeController.focus();\n\t\t} else if (this.element) {\n\t\t\tthis.element.focus();\n\t\t\tthis._onDidFocus.fire();\n\t\t}\n\t}\n\n\tprivate setActions(): void {\n\t\tif (this.toolbar) {\n\t\t\tconst primaryActions = [...this.menuActions.getPrimaryActions()];\n\t\t\tif (this.shouldShowFilterInHeader()) {\n\t\t\t\tprimaryActions.unshift(VIEWPANE_FILTER_ACTION);\n\t\t\t}\n\t\t\tthis.toolbar.setActions(prepareActions(primaryActions), prepareActions(this.menuActions.getSecondaryActions()));\n\t\t\tthis.toolbar.context = this.getActionsContext();\n\t\t}\n\t}\n\n\tprivate updateActionsVisibility(): void {\n\t\tif (!this.headerContainer) {\n\t\t\treturn;\n\t\t}\n\t\tconst shouldAlwaysShowActions = this.configurationService.getValue('workbench.view.alwaysShowHeaderActions');\n\t\tthis.headerContainer.classList.toggle('actions-always-visible', shouldAlwaysShowActions);\n\t}\n\n\tprotected updateActions(): void {\n\t\tthis.setActions();\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tgetActionViewItem(action: IAction, options?: IDropdownMenuActionViewItemOptions): IActionViewItem | undefined {\n\t\tif (action.id === VIEWPANE_FILTER_ACTION.id) {\n\t\t\tconst that = this;\n\t\t\treturn new class extends BaseActionViewItem {\n\t\t\t\tconstructor() { super(null, action); }\n\t\t\t\toverride setFocusable(): void { /* noop input elements are focusable by default */ }\n\t\t\t\toverride get trapsArrowNavigation(): boolean { return true; }\n\t\t\t\toverride render(container: HTMLElement): void {\n\t\t\t\t\tcontainer.classList.add('viewpane-filter-container');\n\t\t\t\t\tappend(container, that.getFilterWidget()!.element);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\treturn createActionViewItem(this.instantiationService, action, { ...options, ...{ menuAsChild: action instanceof SubmenuItemAction } });\n\t}\n\n\tgetActionsContext(): unknown {\n\t\treturn undefined;\n\t}\n\n\tgetActionRunner(): IActionRunner | undefined {\n\t\treturn undefined;\n\t}\n\n\tgetOptimalWidth(): number {\n\t\treturn 0;\n\t}\n\n\tsaveState(): void {\n\t\t// Subclasses to implement for saving state\n\t}\n\n\tshouldShowWelcome(): boolean {\n\t\treturn false;\n\t}\n\n\tgetFilterWidget()", + "fileName": "./2.tst" + }, + "diffs": [ + { + "originalRange": "[1,3)", + "modifiedRange": "[1,52)", + "innerChanges": [ + { + "originalRange": "[1,1 -> 2,50]", + "modifiedRange": "[1,1 -> 50,28]" + }, + { + "originalRange": "[2,82 -> 2,82]", + "modifiedRange": "[50,60 -> 50,74]" + }, + { + "originalRange": "[2,99 -> 2,99]", + "modifiedRange": "[50,91 -> 50,100]" + }, + { + "originalRange": "[2,103 -> 2,103]", + "modifiedRange": "[50,104 -> 51,4]" + }, + { + "originalRange": "[2,151 -> 2,152]", + "modifiedRange": "[51,52 -> 51,60]" + }, + { + "originalRange": "[2,162 -> 2,163]", + "modifiedRange": "[51,70 -> 51,70]" + } + ] + }, + { + "originalRange": "[7,8)", + "modifiedRange": "[56,57)", + "innerChanges": [ + { + "originalRange": "[7,63 -> 7,63]", + "modifiedRange": "[56,63 -> 56,72]" + } + ] + }, + { + "originalRange": "[20,21)", + "modifiedRange": "[69,70)", + "innerChanges": [ + { + "originalRange": "[20,8 -> 20,25]", + "modifiedRange": "[69,8 -> 69,14]" + } + ] + }, + { + "originalRange": "[42,45)", + "modifiedRange": "[91,176)", + "innerChanges": [ + { + "originalRange": "[42,9 -> 45,1 EOL]", + "modifiedRange": "[91,9 -> 176,1 EOL]" + } + ] + }, + { + "originalRange": "[49,50)", + "modifiedRange": "[180,181)", + "innerChanges": [ + { + "originalRange": "[49,1 -> 49,1]", + "modifiedRange": "[180,1 -> 180,2]" + } + ] + }, + { + "originalRange": "[51,52)", + "modifiedRange": "[182,183)", + "innerChanges": [ + { + "originalRange": "[51,1 -> 51,1]", + "modifiedRange": "[182,1 -> 182,2]" + } + ] + }, + { + "originalRange": "[95,100)", + "modifiedRange": "[226,227)", + "innerChanges": [ + { + "originalRange": "[95,1 -> 99,1]", + "modifiedRange": "[226,1 -> 226,1]" + }, + { + "originalRange": "[99,31 -> 99,31]", + "modifiedRange": "[226,31 -> 226,32]" + } + ] + }, + { + "originalRange": "[129,131)", + "modifiedRange": "[256,256)", + "innerChanges": [ + { + "originalRange": "[129,1 -> 131,1]", + "modifiedRange": "[256,1 -> 256,1]" + } + ] + }, + { + "originalRange": "[323,325)", + "modifiedRange": "[448,448)", + "innerChanges": [ + { + "originalRange": "[323,1 -> 325,1 EOL]", + "modifiedRange": "[448,1 -> 448,1 EOL]" + } + ] + }, + { + "originalRange": "[327,342)", + "modifiedRange": "[450,451)", + "innerChanges": [ + { + "originalRange": "[327,8 -> 342,1]", + "modifiedRange": "[450,8 -> 451,1]" + } + ] + }, + { + "originalRange": "[345,351)", + "modifiedRange": "[454,455)", + "innerChanges": [ + { + "originalRange": "[345,1 -> 346,2]", + "modifiedRange": "[454,1 -> 454,1]" + }, + { + "originalRange": "[346,24 -> 346,27]", + "modifiedRange": "[454,23 -> 454,27]" + }, + { + "originalRange": "[346,30 -> 346,48]", + "modifiedRange": "[454,30 -> 454,37]" + }, + { + "originalRange": "[346,54 -> 350,1]", + "modifiedRange": "[454,43 -> 455,1]" + }, + { + "originalRange": "[350,1 -> 351,1]", + "modifiedRange": "[455,1 -> 455,1]" + } + ] + }, + { + "originalRange": "[394,395)", + "modifiedRange": "[498,499)", + "innerChanges": [ + { + "originalRange": "[394,24 -> 394,27]", + "modifiedRange": "[498,24 -> 498,28]" + } + ] + }, + { + "originalRange": "[456,539)", + "modifiedRange": "[560,560)", + "innerChanges": [ + { + "originalRange": "[456,1 -> 539,1 EOL]", + "modifiedRange": "[560,1 -> 560,1 EOL]" + } + ] + } + ], + "moves": [ + { + "originalRange": "[477,537)", + "modifiedRange": "[107,165)", + "changes": [ + { + "originalRange": "[477,479)", + "modifiedRange": "[107,109)", + "innerChanges": [ + { + "originalRange": "[477,8 -> 477,13]", + "modifiedRange": "[107,8 -> 107,9]" + }, + { + "originalRange": "[478,8 -> 478,28]", + "modifiedRange": "[108,8 -> 108,16]" + } + ] + }, + { + "originalRange": "[494,495)", + "modifiedRange": "[124,125)", + "innerChanges": [ + { + "originalRange": "[494,42 -> 494,62]", + "modifiedRange": "[124,42 -> 124,50]" + } + ] + }, + { + "originalRange": "[498,499)", + "modifiedRange": "[128,129)", + "innerChanges": [ + { + "originalRange": "[498,139 -> 498,139]", + "modifiedRange": "[128,139 -> 128,148]" + } + ] + }, + { + "originalRange": "[500,502)", + "modifiedRange": "[130,132)", + "innerChanges": [ + { + "originalRange": "[500,15 -> 500,16]", + "modifiedRange": "[130,15 -> 130,27]" + }, + { + "originalRange": "[501,6 -> 501,7]", + "modifiedRange": "[131,6 -> 131,18]" + } + ] + }, + { + "originalRange": "[507,509)", + "modifiedRange": "[137,138)", + "innerChanges": [ + { + "originalRange": "[507,28 -> 508,7]", + "modifiedRange": "[137,28 -> 137,28]" + }, + { + "originalRange": "[508,25 -> 508,54]", + "modifiedRange": "[137,46 -> 137,46]" + } + ] + }, + { + "originalRange": "[510,511)", + "modifiedRange": "[139,140)", + "innerChanges": [ + { + "originalRange": "[510,50 -> 510,51]", + "modifiedRange": "[139,50 -> 139,62]" + } + ] + }, + { + "originalRange": "[513,514)", + "modifiedRange": "[142,143)", + "innerChanges": [ + { + "originalRange": "[513,28 -> 513,48]", + "modifiedRange": "[142,28 -> 142,36]" + } + ] + }, + { + "originalRange": "[519,520)", + "modifiedRange": "[148,149)", + "innerChanges": [ + { + "originalRange": "[519,21 -> 519,22]", + "modifiedRange": "[148,21 -> 148,33]" + } + ] + }, + { + "originalRange": "[525,527)", + "modifiedRange": "[154,155)", + "innerChanges": [ + { + "originalRange": "[525,30 -> 526,9]", + "modifiedRange": "[154,30 -> 154,30]" + }, + { + "originalRange": "[526,27 -> 526,56]", + "modifiedRange": "[154,48 -> 154,48]" + } + ] + }, + { + "originalRange": "[528,529)", + "modifiedRange": "[156,157)", + "innerChanges": [ + { + "originalRange": "[528,52 -> 528,53]", + "modifiedRange": "[156,52 -> 156,64]" + } + ] + }, + { + "originalRange": "[536,537)", + "modifiedRange": "[164,165)", + "innerChanges": [ + { + "originalRange": "[536,25 -> 536,25]", + "modifiedRange": "[164,25 -> 164,26]" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/noisy-move1/advanced.invalid.diff.json b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/advanced.invalid.diff.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/vs/editor/test/node/diffing/fixtures/noisy-move1/legacy.expected.diff.json b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/legacy.expected.diff.json new file mode 100644 index 00000000000..c6bdd931d44 --- /dev/null +++ b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/legacy.expected.diff.json @@ -0,0 +1,178 @@ +{ + "original": { + "content": "\tcontextKeyService.onDidChangeContext(this.onDidChangeContext, this, this.disposables);\n\t\tthis.disposables.add(Event.filter(viewsRegistry.onDidChangeViewWelcomeContent, id => id === this.id)(this.onDidChangeViewWelcomeContent, this, this.disposables));\n\t\tthis.onDidChangeViewWelcomeContent();\n\t}\n\n\tprivate onDidChangeViewWelcomeContent(): void {\n\t\tconst descriptors = viewsRegistry.getViewWelcomeContent(this.id);\n\n\t\tthis.items = [];\n\n\t\tfor (const descriptor of descriptors) {\n\t\t\tif (descriptor.when === 'default') {\n\t\t\t\tthis.defaultItem = { descriptor, visible: true };\n\t\t\t} else {\n\t\t\t\tconst visible = descriptor.when ? this.contextKeyService.contextMatchesRules(descriptor.when) : true;\n\t\t\t\tthis.items.push({ descriptor, visible });\n\t\t\t}\n\t\t}\n\n\t\tthis._onDidChange.fire();\n\t}\n\n\tprivate onDidChangeContext(): void {\n\t\tlet didChange = false;\n\n\t\tfor (const item of this.items) {\n\t\t\tif (!item.descriptor.when || item.descriptor.when === 'default') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst visible = this.contextKeyService.contextMatchesRules(item.descriptor.when);\n\n\t\t\tif (item.visible === visible) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titem.visible = visible;\n\t\t\tdidChange = true;\n\t\t}\n\n\t\tif (didChange) {\n\t\t\tthis._onDidChange.fire();\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nexport abstract class ViewPane extends Pane implements IView {\n\n\tprivate static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions';\n\n\tprivate _onDidFocus = this._register(new Emitter());\n\treadonly onDidFocus: Event = this._onDidFocus.event;\n\n\tprivate _onDidBlur = this._register(new Emitter());\n\treadonly onDidBlur: Event = this._onDidBlur.event;\n\n\tprivate _onDidChangeBodyVisibility = this._register(new Emitter());\n\treadonly onDidChangeBodyVisibility: Event = this._onDidChangeBodyVisibility.event;\n\n\tprotected _onDidChangeTitleArea = this._register(new Emitter());\n\treadonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event;\n\n\tprotected _onDidChangeViewWelcomeState = this._register(new Emitter());\n\treadonly onDidChangeViewWelcomeState: Event = this._onDidChangeViewWelcomeState.event;\n\n\tprivate _isVisible: boolean = false;\n\treadonly id: string;\n\n\tprivate _title: string;\n\tpublic get title(): string {\n\t\treturn this._title;\n\t}\n\n\tprivate _titleDescription: string | undefined;\n\tpublic get titleDescription(): string | undefined {\n\t\treturn this._titleDescription;\n\t}\n\n\treadonly menuActions: CompositeMenuActions;\n\n\tprivate progressBar!: ProgressBar;\n\tprivate progressIndicator!: IProgressIndicator;\n\n\tprivate toolbar?: WorkbenchToolBar;\n\tprivate readonly showActions: ViewPaneShowActions;\n\tprivate headerContainer?: HTMLElement;\n\tprivate titleContainer?: HTMLElement;\n\tprivate titleDescriptionContainer?: HTMLElement;\n\tprivate iconContainer?: HTMLElement;\n\tprotected twistiesContainer?: HTMLElement;\n\n\tprivate bodyContainer!: HTMLElement;\n\tprivate viewWelcomeContainer!: HTMLElement;\n\tprivate viewWelcomeDisposable: IDisposable = Disposable.None;\n\tprivate viewWelcomeController: ViewWelcomeController;\n\n\tprotected readonly scopedContextKeyService: IContextKeyService;\n\n\tconstructor(\n\t\toptions: IViewPaneOptions,\n\t\t@IKeybindingService protected keybindingService: IKeybindingService,\n\t\t@IContextMenuService protected contextMenuService: IContextMenuService,\n\t\t@IConfigurationService protected readonly configurationService: IConfigurationService,\n\t\t@IContextKeyService protected contextKeyService: IContextKeyService,\n\t\t@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,\n\t\t@IInstantiationService protected instantiationService: IInstantiationService,\n\t\t@IOpenerService protected openerService: IOpenerService,\n\t\t@IThemeService protected themeService: IThemeService,\n\t\t@ITelemetryService protected telemetryService: ITelemetryService,\n\t) {\n\t\tsuper({ ...options, ...{ orientation: viewDescriptorService.getViewLocationById(options.id) === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL } });\n\n\t\tthis.id = options.id;\n\t\tthis._title = options.title;\n\t\tthis._titleDescription = options.titleDescription;\n\t\tthis.showActions = options.showActions ?? ViewPaneShowActions.Default;\n\n\t\tthis.scopedContextKeyService = this._register(contextKeyService.createScoped(this.element));\n\t\tthis.scopedContextKeyService.createKey('view', this.id);\n\t\tconst viewLocationKey = this.scopedContextKeyService.createKey('viewLocation', ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!));\n\t\tthis._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === this.id))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!))));\n\n\t\tthis.menuActions = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])).createInstance(CompositeMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs }));\n\t\tthis._register(this.menuActions.onDidChange(() => this.updateActions()));\n\n\t\tthis.viewWelcomeController = this._register(new ViewWelcomeController(this.id, contextKeyService));\n\t}\n\n\toverride get headerVisible(): boolean {\n\t\treturn super.headerVisible;\n\t}\n\n\toverride set headerVisible(visible: boolean) {\n\t\tsuper.headerVisible = visible;\n\t\tthis.element.classList.toggle('merged-header', !visible);\n\t}\n\n\tsetVisible(visible: boolean): void {\n\t\tif (this._isVisible !== visible) {\n\t\t\tthis._isVisible = visible;\n\n\t\t\tif (this.isExpanded()) {\n\t\t\t\tthis._onDidChangeBodyVisibility.fire(visible);\n\t\t\t}\n\t\t}\n\t}\n\n\tisVisible(): boolean {\n\t\treturn this._isVisible;\n\t}\n\n\tisBodyVisible(): boolean {\n\t\treturn this._isVisible && this.isExpanded();\n\t}\n\n\toverride setExpanded(expanded: boolean): boolean {\n\t\tconst changed = super.setExpanded(expanded);\n\t\tif (changed) {\n\t\t\tthis._onDidChangeBodyVisibility.fire(expanded);\n\t\t}\n\t\tif (this.twistiesContainer) {\n\t\t\tthis.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded)));\n\t\t\tthis.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded)));\n\t\t}\n\t\treturn changed;\n\t}\n\n\toverride render(): void {\n\t\tsuper.render();\n\n\t\tconst focusTracker = trackFocus(this.element);\n\t\tthis._register(focusTracker);\n\t\tthis._register(focusTracker.onDidFocus(() => this._onDidFocus.fire()));\n\t\tthis._register(focusTracker.onDidBlur(() => this._onDidBlur.fire()));\n\t}\n\n\tprotected renderHeader(container: HTMLElement): void {\n\t\tthis.headerContainer = container;\n\n\t\tthis.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded()))));\n\n\t\tthis.renderHeaderTitle(container, this.title);\n\n\t\tconst actions = append(container, $('.actions'));\n\t\tactions.classList.toggle('show-always', this.showActions === ViewPaneShowActions.Always);\n\t\tactions.classList.toggle('show-expanded', this.showActions === ViewPaneShowActions.WhenExpanded);\n\t\tthis.toolbar = this.instantiationService.createInstance(WorkbenchToolBar, actions, {\n\t\t\torientation: ActionsOrientation.HORIZONTAL,\n\t\t\tactionViewItemProvider: action => this.getActionViewItem(action),\n\t\t\tariaLabel: nls.localize('viewToolbarAriaLabel', \"{0} actions\", this.title),\n\t\t\tgetKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),\n\t\t\trenderDropdownAsChildElement: true,\n\t\t\tactionRunner: this.getActionRunner(),\n\t\t\tresetMenu: this.menuActions.menuId\n\t\t});\n\n\t\tthis._register(this.toolbar);\n\t\tthis.setActions();\n\n\t\tthis._register(addDisposableListener(actions, EventType.CLICK, e => e.preventDefault()));\n\n\t\tconst viewContainerModel = this.viewDescriptorService.getViewContainerByViewId(this.id);\n\t\tif (viewContainerModel) {\n\t\t\tthis._register(this.viewDescriptorService.getViewContainerModel(viewContainerModel).onDidChangeContainerInfo(({ title }) => this.updateTitle(this.title)));\n\t\t} else {\n\t\t\tconsole.error(`View container model not found for view ${this.id}`);\n\t\t}\n\n\t\tconst onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig));\n\t\tthis._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this));\n\t\tthis.updateActionsVisibility();\n\t}\n\n\tprotected getTwistyIcon(expanded: boolean): ThemeIcon {\n\t\treturn expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon;\n\t}\n\n\toverride style(styles: IPaneStyles): void {\n\t\tsuper.style(styles);\n\n\t\tconst icon = this.getIcon();\n\t\tif (this.iconContainer) {\n\t\t\tconst fgColor = asCssValueWithDefault(styles.headerForeground, asCssVariable(foreground));\n\t\t\tif (URI.isUri(icon)) {\n\t\t\t\t// Apply background color to activity bar item provided with iconUrls\n\t\t\t\tthis.iconContainer.style.backgroundColor = fgColor;\n\t\t\t\tthis.iconContainer.style.color = '';\n\t\t\t} else {\n\t\t\t\t// Apply foreground color to activity bar items provided with codicons\n\t\t\t\tthis.iconContainer.style.color = fgColor;\n\t\t\t\tthis.iconContainer.style.backgroundColor = '';\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getIcon(): ThemeIcon | URI {\n\t\treturn this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon;\n\t}\n\n\tprotected renderHeaderTitle(container: HTMLElement, title: string): void {\n\t\tthis.iconContainer = append(container, $('.icon', undefined));\n\t\tconst icon = this.getIcon();\n\n\t\tlet cssClass: string | undefined = undefined;\n\t\tif (URI.isUri(icon)) {\n\t\t\tcssClass = `view-${this.id.replace(/[\\.\\:]/g, '-')}`;\n\t\t\tconst iconClass = `.pane-header .icon.${cssClass}`;\n\n\t\t\tcreateCSSRule(iconClass, `\n\t\t\t\tmask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\tmask-size: 24px;\n\t\t\t\t-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\t-webkit-mask-size: 16px;\n\t\t\t`);\n\t\t} else if (ThemeIcon.isThemeIcon(icon)) {\n\t\t\tcssClass = ThemeIcon.asClassName(icon);\n\t\t}\n\n\t\tif (cssClass) {\n\t\t\tthis.iconContainer.classList.add(...cssClass.split(' '));\n\t\t}\n\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tthis.titleContainer = append(container, $('h3.title', { title: calculatedTitle }, calculatedTitle));\n\n\t\tif (this._titleDescription) {\n\t\t\tthis.setTitleDescription(this._titleDescription);\n\t\t}\n\n\t\tthis.iconContainer.title = calculatedTitle;\n\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t}\n\n\tprotected updateTitle(title: string): void {\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tif (this.titleContainer) {\n\t\t\tthis.titleContainer.textContent = calculatedTitle;\n\t\t\tthis.titleContainer.setAttribute('title', calculatedTitle);\n\t\t}\n\n\t\tif (this.iconContainer) {\n\t\t\tthis.iconContainer.title = calculatedTitle;\n\t\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t\t}\n\n\t\tthis._title = title;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate setTitleDescription(description: string | undefined) {\n\t\tif (this.titleDescriptionContainer) {\n\t\t\tthis.titleDescriptionContainer.textContent = description ?? '';\n\t\t\tthis.titleDescriptionContainer.setAttribute('title', description ?? '');\n\t\t}\n\t\telse if (description && this.titleContainer) {\n\t\t\tthis.titleDescriptionContainer = after(this.titleContainer, $('span.description', { title: description }, description));\n\t\t}\n\t}\n\n\tprotected updateTitleDescription(description?: string | undefined): void {\n\t\tthis.setTitleDescription(description);\n\n\t\tthis._titleDescription = description;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate calculateTitle(title: string): string {\n\t\tconst viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!;\n\t\tconst model = this.viewDescriptorService.getViewContainerModel(viewContainer);\n\t\tconst viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id);\n\t\tconst isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer;\n\n\t\tif (!isDefault && viewDescriptor?.containerTitle && model.title !== viewDescriptor.containerTitle) {\n\t\t\treturn `${viewDescriptor.containerTitle}: ${title}`;\n\t\t}\n\n\t\treturn title;\n\t}\n\n\tprivate scrollableElement!: DomScrollableElement;\n\n\tprotected renderBody(container: HTMLElement): void {\n\t\tthis.bodyContainer = container;\n\n\t\tconst viewWelcomeContainer = append(container, $('.welcome-view'));\n\t\tthis.viewWelcomeContainer = $('.welcome-view-content', { tabIndex: 0 });\n\t\tthis.scrollableElement = this._register(new DomScrollableElement(this.viewWelcomeContainer, {\n\t\t\talwaysConsumeMouseWheel: true,\n\t\t\thorizontal: ScrollbarVisibility.Hidden,\n\t\t\tvertical: ScrollbarVisibility.Visible,\n\t\t}));\n\n\t\tappend(viewWelcomeContainer, this.scrollableElement.getDomNode());\n\n\t\tconst onViewWelcomeChange = Event.any(this.viewWelcomeController.onDidChange, this.onDidChangeViewWelcomeState);\n\t\tthis._register(onViewWelcomeChange(this.updateViewWelcome, this));\n\t\tthis.updateViewWelcome();\n\t}\n\n\tprotected layoutBody(height: number, width: number): void {\n\t\tif (this.shouldShowWelcome()) {\n\t\t\tthis.viewWelcomeContainer.style.height = `${height}px`;\n\t\t\tthis.viewWelcomeContainer.style.width = `${width}px`;\n\t\t\tthis.viewWelcomeContainer.classList.toggle('wide', width > 640);\n\t\t\tthis.scrollableElement.scanDomNode();\n\t\t}\n\t}\n\n\tonDidScrollRoot() {\n\t\t// noop\n\t}\n\n\tgetProgressIndicator() {\n\t\tif (this.progressBar === undefined) {\n\t\t\t// Progress bar\n\t\t\tthis.progressBar = this._register(new ProgressBar(this.element, defaultProgressBarStyles));\n\t\t\tthis.progressBar.hide();\n\t\t}\n\n\t\tif (this.progressIndicator === undefined) {\n\t\t\tconst that = this;\n\t\t\tthis.progressIndicator = new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope {\n\t\t\t\tconstructor() {\n\t\t\t\t\tsuper(that.id, that.isBodyVisible());\n\t\t\t\t\tthis._register(that.onDidChangeBodyVisibility(isVisible => isVisible ? this.onScopeOpened(that.id) : this.onScopeClosed(that.id)));\n\t\t\t\t}\n\t\t\t}());\n\t\t}\n\t\treturn this.progressIndicator;\n\t}\n\n\tprotected getProgressLocation(): string {\n\t\treturn this.viewDescriptorService.getViewContainerByViewId(this.id)!.id;\n\t}\n\n\tprotected getBackgroundColor(): string {\n\t\tswitch (this.viewDescriptorService.getViewLocationById(this.id)) {\n\t\t\tcase ViewContainerLocation.Panel:\n\t\t\t\treturn PANEL_BACKGROUND;\n\t\t\tcase ViewContainerLocation.Sidebar:\n\t\t\tcase ViewContainerLocation.AuxiliaryBar:\n\t\t\t\treturn SIDE_BAR_BACKGROUND;\n\t\t}\n\n\t\treturn SIDE_BAR_BACKGROUND;\n\t}\n\n\tfocus(): void {\n\t\tif (this.shouldShowWelcome()) {\n\t\t\tthis.viewWelcomeContainer.focus();\n\t\t} else if (this.element) {\n\t\t\tthis.element.focus();\n\t\t\tthis._onDidFocus.fire();\n\t\t}\n\t}\n\n\tprivate setActions(): void {\n\t\tif (this.toolbar) {\n\t\t\tconst primaryActions = [...this.menuActions.getPrimaryActions()];\n\t\t\tif (this.shouldShowFilterInHeader()) {\n\t\t\t\tprimaryActions.unshift(VIEWPANE_FILTER_ACTION);\n\t\t\t}\n\t\t\tthis.toolbar.setActions(prepareActions(primaryActions), prepareActions(this.menuActions.getSecondaryActions()));\n\t\t\tthis.toolbar.context = this.getActionsContext();\n\t\t}\n\t}\n\n\tprivate updateActionsVisibility(): void {\n\t\tif (!this.headerContainer) {\n\t\t\treturn;\n\t\t}\n\t\tconst shouldAlwaysShowActions = this.configurationService.getValue('workbench.view.alwaysShowHeaderActions');\n\t\tthis.headerContainer.classList.toggle('actions-always-visible', shouldAlwaysShowActions);\n\t}\n\n\tprotected updateActions(): void {\n\t\tthis.setActions();\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tgetActionViewItem(action: IAction, options?: IDropdownMenuActionViewItemOptions): IActionViewItem | undefined {\n\t\tif (action.id === VIEWPANE_FILTER_ACTION.id) {\n\t\t\tconst that = this;\n\t\t\treturn new class extends BaseActionViewItem {\n\t\t\t\tconstructor() { super(null, action); }\n\t\t\t\toverride setFocusable(): void { /* noop input elements are focusable by default */ }\n\t\t\t\toverride get trapsArrowNavigation(): boolean { return true; }\n\t\t\t\toverride render(container: HTMLElement): void {\n\t\t\t\t\tcontainer.classList.add('viewpane-filter-container');\n\t\t\t\t\tappend(container, that.getFilterWidget()!.element);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\treturn createActionViewItem(this.instantiationService, action, { ...options, ...{ menuAsChild: action instanceof SubmenuItemAction } });\n\t}\n\n\tgetActionsContext(): unknown {\n\t\treturn undefined;\n\t}\n\n\tgetActionRunner(): IActionRunner | undefined {\n\t\treturn undefined;\n\t}\n\n\tgetOptimalWidth(): number {\n\t\treturn 0;\n\t}\n\n\tsaveState(): void {\n\t\t// Subclasses to implement for saving state\n\t}\n\n\tprivate updateViewWelcome(): void {\n\t\tthis.viewWelcomeDisposable.dispose();\n\n\t\tif (!this.shouldShowWelcome()) {\n\t\t\tthis.bodyContainer.classList.remove('welcome');\n\t\t\tthis.viewWelcomeContainer.innerText = '';\n\t\t\tthis.scrollableElement.scanDomNode();\n\t\t\treturn;\n\t\t}\n\n\t\tconst contents = this.viewWelcomeController.contents;\n\n\t\tif (contents.length === 0) {\n\t\t\tthis.bodyContainer.classList.remove('welcome');\n\t\t\tthis.viewWelcomeContainer.innerText = '';\n\t\t\tthis.scrollableElement.scanDomNode();\n\t\t\treturn;\n\t\t}\n\n\t\tconst disposables = new DisposableStore();\n\t\tthis.bodyContainer.classList.add('welcome');\n\t\tthis.viewWelcomeContainer.innerText = '';\n\n\t\tfor (const { content, precondition } of contents) {\n\t\t\tconst lines = content.split('\\n');\n\n\t\t\tfor (let line of lines) {\n\t\t\t\tline = line.trim();\n\n\t\t\t\tif (!line) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst linkedText = parseLinkedText(line);\n\n\t\t\t\tif (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') {\n\t\t\t\t\tconst node = linkedText.nodes[0];\n\t\t\t\t\tconst buttonContainer = append(this.viewWelcomeContainer, $('.button-container'));\n\t\t\t\t\tconst button = new Button(buttonContainer, { title: node.title, supportIcons: true, ...defaultButtonStyles });\n\t\t\t\t\tbutton.label = node.label;\n\t\t\t\t\tbutton.onDidClick(_ => {\n\t\t\t\t\t\tthis.telemetryService.publicLog2<{ viewId: string; uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href });\n\t\t\t\t\t\tthis.openerService.open(node.href, { allowCommands: true });\n\t\t\t\t\t}, null, disposables);\n\t\t\t\t\tdisposables.add(button);\n\n\t\t\t\t\tif (precondition) {\n\t\t\t\t\t\tconst updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\tconst keys = new Set();\n\t\t\t\t\t\tprecondition.keys().forEach(key => keys.add(key));\n\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, disposables);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst p = append(this.viewWelcomeContainer, $('p'));\n\n\t\t\t\t\tfor (const node of linkedText.nodes) {\n\t\t\t\t\t\tif (typeof node === 'string') {\n\t\t\t\t\t\t\tappend(p, document.createTextNode(node));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst link = disposables.add(this.instantiationService.createInstance(Link, p, node, {}));\n\n\t\t\t\t\t\t\tif (precondition && node.href.startsWith('command:')) {\n\t\t\t\t\t\t\t\tconst updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\t\t\tconst keys = new Set();\n\t\t\t\t\t\t\t\tprecondition.keys().forEach(key => keys.add(key));\n\t\t\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, disposables);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.scrollableElement.scanDomNode();\n\t\tthis.viewWelcomeDisposable = disposables;\n\t}\n\n\tshouldShowWelcome(): boolean {\n\t\treturn false;\n\t}\n\n\tgetFilterWidget()", + "fileName": "./1.tst" + }, + "modified": { + "content": "\n\tlayout(height: number, width: number) {\n\t\tif (!this.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.element!.style.height = `${height}px`;\n\t\tthis.element!.style.width = `${width}px`;\n\t\tthis.element!.classList.toggle('wide', width > 640);\n\t\tthis.scrollableElement!.scanDomNode();\n\t}\n\n\tfocus() {\n\t\tif (!this.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.element!.focus();\n\t}\n\n\tprivate onDidChangeViewWelcomeState(): void {\n\t\tconst enabled = this.delegate.shouldShowWelcome();\n\n\t\tif (this.enabled === enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.enabled = enabled;\n\n\t\tif (!enabled) {\n\t\t\tthis.enabledDisposables.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.container.classList.add('welcome');\n\t\tconst viewWelcomeContainer = append(this.container, $('.welcome-view'));\n\t\tthis.element = $('.welcome-view-content', { tabIndex: 0 });\n\t\tthis.scrollableElement = new DomScrollableElement(this.element, { alwaysConsumeMouseWheel: true, horizontal: ScrollbarVisibility.Hidden, vertical: ScrollbarVisibility.Visible, });\n\t\tappend(viewWelcomeContainer, this.scrollableElement.getDomNode());\n\n\t\tthis.enabledDisposables.add(toDisposable(() => {\n\t\t\tthis.container.classList.remove('welcome');\n\t\t\tthis.scrollableElement!.dispose();\n\t\t\tviewWelcomeContainer.remove();\n\t\t\tthis.scrollableElement = undefined;\n\t\t\tthis.element = undefined;\n\t\t}));\n\n\t\tthis.contextKeyService.onDidChangeContext(this.onDidChangeContext, this, this.enabledDisposables);\n\t\tEvent.chain(viewsRegistry.onDidChangeViewWelcomeContent, $ => $.filter(id => id === this.delegate.id))\n\t\t\t(this.onDidChangeViewWelcomeContent, this, this.enabledDisposables);\n\t\tthis.onDidChangeViewWelcomeContent();\n\t}\n\n\tprivate onDidChangeViewWelcomeContent(): void {\n\t\tconst descriptors = viewsRegistry.getViewWelcomeContent(this.delegate.id);\n\n\t\tthis.items = [];\n\n\t\tfor (const descriptor of descriptors) {\n\t\t\tif (descriptor.when === 'default') {\n\t\t\t\tthis.defaultItem = { descriptor, visible: true };\n\t\t\t} else {\n\t\t\t\tconst visible = descriptor.when ? this.contextKeyService.contextMatchesRules(descriptor.when) : true;\n\t\t\t\tthis.items.push({ descriptor, visible });\n\t\t\t}\n\t\t}\n\n\t\tthis.render();\n\t}\n\n\tprivate onDidChangeContext(): void {\n\t\tlet didChange = false;\n\n\t\tfor (const item of this.items) {\n\t\t\tif (!item.descriptor.when || item.descriptor.when === 'default') {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst visible = this.contextKeyService.contextMatchesRules(item.descriptor.when);\n\n\t\t\tif (item.visible === visible) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titem.visible = visible;\n\t\t\tdidChange = true;\n\t\t}\n\n\t\tif (didChange) {\n\t\t\tthis.render();\n\t\t}\n\t}\n\n\tprivate render(): void {\n\t\tthis.renderDisposables.clear();\n\n\t\tconst contents = this.getContentDescriptors();\n\n\t\tif (contents.length === 0) {\n\t\t\tthis.container.classList.remove('welcome');\n\t\t\tthis.element!.innerText = '';\n\t\t\tthis.scrollableElement!.scanDomNode();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.container.classList.add('welcome');\n\t\tthis.element!.innerText = '';\n\n\t\tfor (const { content, precondition } of contents) {\n\t\t\tconst lines = content.split('\\n');\n\n\t\t\tfor (let line of lines) {\n\t\t\t\tline = line.trim();\n\n\t\t\t\tif (!line) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst linkedText = parseLinkedText(line);\n\n\t\t\t\tif (linkedText.nodes.length === 1 && typeof linkedText.nodes[0] !== 'string') {\n\t\t\t\t\tconst node = linkedText.nodes[0];\n\t\t\t\t\tconst buttonContainer = append(this.element!, $('.button-container'));\n\t\t\t\t\tconst button = new Button(buttonContainer, { title: node.title, supportIcons: true, ...defaultButtonStyles });\n\t\t\t\t\tbutton.label = node.label;\n\t\t\t\t\tbutton.onDidClick(_ => {\n\t\t\t\t\t\tthis.telemetryService.publicLog2<{ viewId: string; uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.delegate.id, uri: node.href });\n\t\t\t\t\t\tthis.openerService.open(node.href, { allowCommands: true });\n\t\t\t\t\t}, null, this.renderDisposables);\n\t\t\t\t\tthis.renderDisposables.add(button);\n\n\t\t\t\t\tif (precondition) {\n\t\t\t\t\t\tconst updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\tconst keys = new Set(precondition.keys());\n\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, this.renderDisposables);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst p = append(this.element!, $('p'));\n\n\t\t\t\t\tfor (const node of linkedText.nodes) {\n\t\t\t\t\t\tif (typeof node === 'string') {\n\t\t\t\t\t\t\tappend(p, document.createTextNode(node));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst link = this.renderDisposables.add(this.instantiationService.createInstance(Link, p, node, {}));\n\n\t\t\t\t\t\t\tif (precondition && node.href.startsWith('command:')) {\n\t\t\t\t\t\t\t\tconst updateEnablement = () => link.enabled = this.contextKeyService.contextMatchesRules(precondition);\n\t\t\t\t\t\t\t\tupdateEnablement();\n\n\t\t\t\t\t\t\t\tconst keys = new Set(precondition.keys());\n\t\t\t\t\t\t\t\tconst onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));\n\t\t\t\t\t\t\t\tonDidChangeContext(updateEnablement, null, this.renderDisposables);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.scrollableElement!.scanDomNode();\n\t}\n\n\tprivate getContentDescriptors(): IViewContentDescriptor[] {\n\t\tconst visibleItems = this.items.filter(v => v.visible);\n\n\t\tif (visibleItems.length === 0 && this.defaultItem) {\n\t\t\treturn [this.defaultItem.descriptor];\n\t\t}\n\n\t\treturn visibleItems.map(v => v.descriptor);\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n\t}\n\n\texport abstract class ViewPane extends Pane implements IView {\n\n\tprivate static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions';\n\n\tprivate _onDidFocus = this._register(new Emitter());\n\treadonly onDidFocus: Event = this._onDidFocus.event;\n\n\tprivate _onDidBlur = this._register(new Emitter());\n\treadonly onDidBlur: Event = this._onDidBlur.event;\n\n\tprivate _onDidChangeBodyVisibility = this._register(new Emitter());\n\treadonly onDidChangeBodyVisibility: Event = this._onDidChangeBodyVisibility.event;\n\n\tprotected _onDidChangeTitleArea = this._register(new Emitter());\n\treadonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event;\n\n\tprotected _onDidChangeViewWelcomeState = this._register(new Emitter());\n\treadonly onDidChangeViewWelcomeState: Event = this._onDidChangeViewWelcomeState.event;\n\n\tprivate _isVisible: boolean = false;\n\treadonly id: string;\n\n\tprivate _title: string;\n\tpublic get title(): string {\n\t\treturn this._title;\n\t}\n\n\tprivate _titleDescription: string | undefined;\n\tpublic get titleDescription(): string | undefined {\n\t\treturn this._titleDescription;\n\t}\n\n\treadonly menuActions: CompositeMenuActions;\n\n\tprivate progressBar!: ProgressBar;\n\tprivate progressIndicator!: IProgressIndicator;\n\n\tprivate toolbar?: WorkbenchToolBar;\n\tprivate readonly showActions: ViewPaneShowActions;\n\tprivate headerContainer?: HTMLElement;\n\tprivate titleContainer?: HTMLElement;\n\tprivate titleDescriptionContainer?: HTMLElement;\n\tprivate iconContainer?: HTMLElement;\n\tprotected twistiesContainer?: HTMLElement;\n\tprivate viewWelcomeController!: ViewWelcomeController;\n\n\tprotected readonly scopedContextKeyService: IContextKeyService;\n\n\tconstructor(\n\t\toptions: IViewPaneOptions,\n\t\t@IKeybindingService protected keybindingService: IKeybindingService,\n\t\t@IContextMenuService protected contextMenuService: IContextMenuService,\n\t\t@IConfigurationService protected readonly configurationService: IConfigurationService,\n\t\t@IContextKeyService protected contextKeyService: IContextKeyService,\n\t\t@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,\n\t\t@IInstantiationService protected instantiationService: IInstantiationService,\n\t\t@IOpenerService protected openerService: IOpenerService,\n\t\t@IThemeService protected themeService: IThemeService,\n\t\t@ITelemetryService protected telemetryService: ITelemetryService,\n\t) {\n\t\tsuper({ ...options, ...{ orientation: viewDescriptorService.getViewLocationById(options.id) === ViewContainerLocation.Panel ? Orientation.HORIZONTAL : Orientation.VERTICAL } });\n\n\t\tthis.id = options.id;\n\t\tthis._title = options.title;\n\t\tthis._titleDescription = options.titleDescription;\n\t\tthis.showActions = options.showActions ?? ViewPaneShowActions.Default;\n\n\t\tthis.scopedContextKeyService = this._register(contextKeyService.createScoped(this.element));\n\t\tthis.scopedContextKeyService.createKey('view', this.id);\n\t\tconst viewLocationKey = this.scopedContextKeyService.createKey('viewLocation', ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!));\n\t\tthis._register(Event.filter(viewDescriptorService.onDidChangeLocation, e => e.views.some(view => view.id === this.id))(() => viewLocationKey.set(ViewContainerLocationToString(viewDescriptorService.getViewLocationById(this.id)!))));\n\n\t\tthis.menuActions = this._register(this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.scopedContextKeyService])).createInstance(CompositeMenuActions, options.titleMenuId ?? MenuId.ViewTitle, MenuId.ViewTitleContext, { shouldForwardArgs: !options.donotForwardArgs }));\n\t\tthis._register(this.menuActions.onDidChange(() => this.updateActions()));\n\t}\n\n\toverride get headerVisible(): boolean {\n\t\treturn super.headerVisible;\n\t}\n\n\toverride set headerVisible(visible: boolean) {\n\t\tsuper.headerVisible = visible;\n\t\tthis.element.classList.toggle('merged-header', !visible);\n\t}\n\n\tsetVisible(visible: boolean): void {\n\t\tif (this._isVisible !== visible) {\n\t\t\tthis._isVisible = visible;\n\n\t\t\tif (this.isExpanded()) {\n\t\t\t\tthis._onDidChangeBodyVisibility.fire(visible);\n\t\t\t}\n\t\t}\n\t}\n\n\tisVisible(): boolean {\n\t\treturn this._isVisible;\n\t}\n\n\tisBodyVisible(): boolean {\n\t\treturn this._isVisible && this.isExpanded();\n\t}\n\n\toverride setExpanded(expanded: boolean): boolean {\n\t\tconst changed = super.setExpanded(expanded);\n\t\tif (changed) {\n\t\t\tthis._onDidChangeBodyVisibility.fire(expanded);\n\t\t}\n\t\tif (this.twistiesContainer) {\n\t\t\tthis.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded)));\n\t\t\tthis.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded)));\n\t\t}\n\t\treturn changed;\n\t}\n\n\toverride render(): void {\n\t\tsuper.render();\n\n\t\tconst focusTracker = trackFocus(this.element);\n\t\tthis._register(focusTracker);\n\t\tthis._register(focusTracker.onDidFocus(() => this._onDidFocus.fire()));\n\t\tthis._register(focusTracker.onDidBlur(() => this._onDidBlur.fire()));\n\t}\n\n\tprotected renderHeader(container: HTMLElement): void {\n\t\tthis.headerContainer = container;\n\n\t\tthis.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded()))));\n\n\t\tthis.renderHeaderTitle(container, this.title);\n\n\t\tconst actions = append(container, $('.actions'));\n\t\tactions.classList.toggle('show-always', this.showActions === ViewPaneShowActions.Always);\n\t\tactions.classList.toggle('show-expanded', this.showActions === ViewPaneShowActions.WhenExpanded);\n\t\tthis.toolbar = this.instantiationService.createInstance(WorkbenchToolBar, actions, {\n\t\t\torientation: ActionsOrientation.HORIZONTAL,\n\t\t\tactionViewItemProvider: action => this.getActionViewItem(action),\n\t\t\tariaLabel: nls.localize('viewToolbarAriaLabel', \"{0} actions\", this.title),\n\t\t\tgetKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),\n\t\t\trenderDropdownAsChildElement: true,\n\t\t\tactionRunner: this.getActionRunner(),\n\t\t\tresetMenu: this.menuActions.menuId\n\t\t});\n\n\t\tthis._register(this.toolbar);\n\t\tthis.setActions();\n\n\t\tthis._register(addDisposableListener(actions, EventType.CLICK, e => e.preventDefault()));\n\n\t\tconst viewContainerModel = this.viewDescriptorService.getViewContainerByViewId(this.id);\n\t\tif (viewContainerModel) {\n\t\t\tthis._register(this.viewDescriptorService.getViewContainerModel(viewContainerModel).onDidChangeContainerInfo(({ title }) => this.updateTitle(this.title)));\n\t\t} else {\n\t\t\tconsole.error(`View container model not found for view ${this.id}`);\n\t\t}\n\n\t\tconst onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig));\n\t\tthis._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this));\n\t\tthis.updateActionsVisibility();\n\t}\n\n\tprotected getTwistyIcon(expanded: boolean): ThemeIcon {\n\t\treturn expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon;\n\t}\n\n\toverride style(styles: IPaneStyles): void {\n\t\tsuper.style(styles);\n\n\t\tconst icon = this.getIcon();\n\t\tif (this.iconContainer) {\n\t\t\tconst fgColor = asCssValueWithDefault(styles.headerForeground, asCssVariable(foreground));\n\t\t\tif (URI.isUri(icon)) {\n\t\t\t\t// Apply background color to activity bar item provided with iconUrls\n\t\t\t\tthis.iconContainer.style.backgroundColor = fgColor;\n\t\t\t\tthis.iconContainer.style.color = '';\n\t\t\t} else {\n\t\t\t\t// Apply foreground color to activity bar items provided with codicons\n\t\t\t\tthis.iconContainer.style.color = fgColor;\n\t\t\t\tthis.iconContainer.style.backgroundColor = '';\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getIcon(): ThemeIcon | URI {\n\t\treturn this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon;\n\t}\n\n\tprotected renderHeaderTitle(container: HTMLElement, title: string): void {\n\t\tthis.iconContainer = append(container, $('.icon', undefined));\n\t\tconst icon = this.getIcon();\n\n\t\tlet cssClass: string | undefined = undefined;\n\t\tif (URI.isUri(icon)) {\n\t\t\tcssClass = `view-${this.id.replace(/[\\.\\:]/g, '-')}`;\n\t\t\tconst iconClass = `.pane-header .icon.${cssClass}`;\n\n\t\t\tcreateCSSRule(iconClass, `\n\t\t\t\tmask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\tmask-size: 24px;\n\t\t\t\t-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;\n\t\t\t\t-webkit-mask-size: 16px;\n\t\t\t`);\n\t\t} else if (ThemeIcon.isThemeIcon(icon)) {\n\t\t\tcssClass = ThemeIcon.asClassName(icon);\n\t\t}\n\n\t\tif (cssClass) {\n\t\t\tthis.iconContainer.classList.add(...cssClass.split(' '));\n\t\t}\n\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tthis.titleContainer = append(container, $('h3.title', { title: calculatedTitle }, calculatedTitle));\n\n\t\tif (this._titleDescription) {\n\t\t\tthis.setTitleDescription(this._titleDescription);\n\t\t}\n\n\t\tthis.iconContainer.title = calculatedTitle;\n\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t}\n\n\tprotected updateTitle(title: string): void {\n\t\tconst calculatedTitle = this.calculateTitle(title);\n\t\tif (this.titleContainer) {\n\t\t\tthis.titleContainer.textContent = calculatedTitle;\n\t\t\tthis.titleContainer.setAttribute('title', calculatedTitle);\n\t\t}\n\n\t\tif (this.iconContainer) {\n\t\t\tthis.iconContainer.title = calculatedTitle;\n\t\t\tthis.iconContainer.setAttribute('aria-label', calculatedTitle);\n\t\t}\n\n\t\tthis._title = title;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate setTitleDescription(description: string | undefined) {\n\t\tif (this.titleDescriptionContainer) {\n\t\t\tthis.titleDescriptionContainer.textContent = description ?? '';\n\t\t\tthis.titleDescriptionContainer.setAttribute('title', description ?? '');\n\t\t}\n\t\telse if (description && this.titleContainer) {\n\t\t\tthis.titleDescriptionContainer = after(this.titleContainer, $('span.description', { title: description }, description));\n\t\t}\n\t}\n\n\tprotected updateTitleDescription(description?: string | undefined): void {\n\t\tthis.setTitleDescription(description);\n\n\t\tthis._titleDescription = description;\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tprivate calculateTitle(title: string): string {\n\t\tconst viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!;\n\t\tconst model = this.viewDescriptorService.getViewContainerModel(viewContainer);\n\t\tconst viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id);\n\t\tconst isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer;\n\n\t\tif (!isDefault && viewDescriptor?.containerTitle && model.title !== viewDescriptor.containerTitle) {\n\t\t\treturn `${viewDescriptor.containerTitle}: ${title}`;\n\t\t}\n\n\t\treturn title;\n\t}\n\n\tprotected renderBody(container: HTMLElement): void {\n\t\tthis.viewWelcomeController = this._register(new ViewWelcomeController(container, this, this.instantiationService, this.openerService, this.telemetryService, this.contextKeyService));\n\t}\n\n\tprotected layoutBody(height: number, width: number): void {\n\t\tthis.viewWelcomeController.layout(height, width);\n\t}\n\n\tonDidScrollRoot() {\n\t\t// noop\n\t}\n\n\tgetProgressIndicator() {\n\t\tif (this.progressBar === undefined) {\n\t\t\t// Progress bar\n\t\t\tthis.progressBar = this._register(new ProgressBar(this.element, defaultProgressBarStyles));\n\t\t\tthis.progressBar.hide();\n\t\t}\n\n\t\tif (this.progressIndicator === undefined) {\n\t\t\tconst that = this;\n\t\t\tthis.progressIndicator = new ScopedProgressIndicator(assertIsDefined(this.progressBar), new class extends AbstractProgressScope {\n\t\t\t\tconstructor() {\n\t\t\t\t\tsuper(that.id, that.isBodyVisible());\n\t\t\t\t\tthis._register(that.onDidChangeBodyVisibility(isVisible => isVisible ? this.onScopeOpened(that.id) : this.onScopeClosed(that.id)));\n\t\t\t\t}\n\t\t\t}());\n\t\t}\n\t\treturn this.progressIndicator;\n\t}\n\n\tprotected getProgressLocation(): string {\n\t\treturn this.viewDescriptorService.getViewContainerByViewId(this.id)!.id;\n\t}\n\n\tprotected getBackgroundColor(): string {\n\t\tswitch (this.viewDescriptorService.getViewLocationById(this.id)) {\n\t\t\tcase ViewContainerLocation.Panel:\n\t\t\t\treturn PANEL_BACKGROUND;\n\t\t\tcase ViewContainerLocation.Sidebar:\n\t\t\tcase ViewContainerLocation.AuxiliaryBar:\n\t\t\t\treturn SIDE_BAR_BACKGROUND;\n\t\t}\n\n\t\treturn SIDE_BAR_BACKGROUND;\n\t}\n\n\tfocus(): void {\n\t\tif (this.shouldShowWelcome()) {\n\t\t\tthis.viewWelcomeController.focus();\n\t\t} else if (this.element) {\n\t\t\tthis.element.focus();\n\t\t\tthis._onDidFocus.fire();\n\t\t}\n\t}\n\n\tprivate setActions(): void {\n\t\tif (this.toolbar) {\n\t\t\tconst primaryActions = [...this.menuActions.getPrimaryActions()];\n\t\t\tif (this.shouldShowFilterInHeader()) {\n\t\t\t\tprimaryActions.unshift(VIEWPANE_FILTER_ACTION);\n\t\t\t}\n\t\t\tthis.toolbar.setActions(prepareActions(primaryActions), prepareActions(this.menuActions.getSecondaryActions()));\n\t\t\tthis.toolbar.context = this.getActionsContext();\n\t\t}\n\t}\n\n\tprivate updateActionsVisibility(): void {\n\t\tif (!this.headerContainer) {\n\t\t\treturn;\n\t\t}\n\t\tconst shouldAlwaysShowActions = this.configurationService.getValue('workbench.view.alwaysShowHeaderActions');\n\t\tthis.headerContainer.classList.toggle('actions-always-visible', shouldAlwaysShowActions);\n\t}\n\n\tprotected updateActions(): void {\n\t\tthis.setActions();\n\t\tthis._onDidChangeTitleArea.fire();\n\t}\n\n\tgetActionViewItem(action: IAction, options?: IDropdownMenuActionViewItemOptions): IActionViewItem | undefined {\n\t\tif (action.id === VIEWPANE_FILTER_ACTION.id) {\n\t\t\tconst that = this;\n\t\t\treturn new class extends BaseActionViewItem {\n\t\t\t\tconstructor() { super(null, action); }\n\t\t\t\toverride setFocusable(): void { /* noop input elements are focusable by default */ }\n\t\t\t\toverride get trapsArrowNavigation(): boolean { return true; }\n\t\t\t\toverride render(container: HTMLElement): void {\n\t\t\t\t\tcontainer.classList.add('viewpane-filter-container');\n\t\t\t\t\tappend(container, that.getFilterWidget()!.element);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\treturn createActionViewItem(this.instantiationService, action, { ...options, ...{ menuAsChild: action instanceof SubmenuItemAction } });\n\t}\n\n\tgetActionsContext(): unknown {\n\t\treturn undefined;\n\t}\n\n\tgetActionRunner(): IActionRunner | undefined {\n\t\treturn undefined;\n\t}\n\n\tgetOptimalWidth(): number {\n\t\treturn 0;\n\t}\n\n\tsaveState(): void {\n\t\t// Subclasses to implement for saving state\n\t}\n\n\tshouldShowWelcome(): boolean {\n\t\treturn false;\n\t}\n\n\tgetFilterWidget()", + "fileName": "./2.tst" + }, + "diffs": [ + { + "originalRange": "[1,3)", + "modifiedRange": "[1,52)", + "innerChanges": null + }, + { + "originalRange": "[7,8)", + "modifiedRange": "[56,57)", + "innerChanges": [ + { + "originalRange": "[7,64 -> 7,64]", + "modifiedRange": "[56,64 -> 56,73]" + } + ] + }, + { + "originalRange": "[20,21)", + "modifiedRange": "[69,70)", + "innerChanges": [ + { + "originalRange": "[20,8 -> 20,25]", + "modifiedRange": "[69,8 -> 69,14]" + } + ] + }, + { + "originalRange": "[42,43)", + "modifiedRange": "[91,172)", + "innerChanges": null + }, + { + "originalRange": "[44,44)", + "modifiedRange": "[173,175)", + "innerChanges": null + }, + { + "originalRange": "[49,50)", + "modifiedRange": "[180,181)", + "innerChanges": [ + { + "originalRange": "[49,1 -> 49,1]", + "modifiedRange": "[180,1 -> 180,2]" + } + ] + }, + { + "originalRange": "[51,52)", + "modifiedRange": "[182,183)", + "innerChanges": [ + { + "originalRange": "[51,1 -> 51,1]", + "modifiedRange": "[182,1 -> 182,2]" + } + ] + }, + { + "originalRange": "[95,100)", + "modifiedRange": "[226,227)", + "innerChanges": [ + { + "originalRange": "[95,1 -> 99,1]", + "modifiedRange": "[226,1 -> 226,1]" + }, + { + "originalRange": "[99,31 -> 99,31]", + "modifiedRange": "[226,31 -> 226,32]" + } + ] + }, + { + "originalRange": "[129,131)", + "modifiedRange": "[256,256)", + "innerChanges": null + }, + { + "originalRange": "[324,326)", + "modifiedRange": "[449,449)", + "innerChanges": null + }, + { + "originalRange": "[327,342)", + "modifiedRange": "[450,451)", + "innerChanges": [ + { + "originalRange": "[327,8 -> 329,9]", + "modifiedRange": "[450,8 -> 450,8]" + }, + { + "originalRange": "[329,24 -> 330,26]", + "modifiedRange": "[450,23 -> 450,27]" + }, + { + "originalRange": "[330,31 -> 331,28]", + "modifiedRange": "[450,32 -> 450,32]" + }, + { + "originalRange": "[331,47 -> 331,74]", + "modifiedRange": "[450,51 -> 450,52]" + }, + { + "originalRange": "[331,88 -> 333,9]", + "modifiedRange": "[450,66 -> 450,74]" + }, + { + "originalRange": "[333,13 -> 337,30]", + "modifiedRange": "[450,78 -> 450,88]" + }, + { + "originalRange": "[337,37 -> 339,5]", + "modifiedRange": "[450,95 -> 450,96]" + }, + { + "originalRange": "[339,8 -> 339,78]", + "modifiedRange": "[450,99 -> 450,114]" + }, + { + "originalRange": "[339,87 -> 340,3]", + "modifiedRange": "[450,123 -> 450,137]" + }, + { + "originalRange": "[340,8 -> 340,59]", + "modifiedRange": "[450,142 -> 450,157]" + }, + { + "originalRange": "[340,66 -> 341,26]", + "modifiedRange": "[450,164 -> 450,183]" + } + ] + }, + { + "originalRange": "[345,351)", + "modifiedRange": "[454,455)", + "innerChanges": [ + { + "originalRange": "[345,1 -> 346,2]", + "modifiedRange": "[454,1 -> 454,1]" + }, + { + "originalRange": "[346,24 -> 347,27]", + "modifiedRange": "[454,23 -> 454,27]" + }, + { + "originalRange": "[347,30 -> 348,53]", + "modifiedRange": "[454,30 -> 454,43]" + }, + { + "originalRange": "[348,60 -> 350,4 EOL]", + "modifiedRange": "[454,50 -> 454,52 EOL]" + } + ] + }, + { + "originalRange": "[394,395)", + "modifiedRange": "[498,499)", + "innerChanges": [ + { + "originalRange": "[394,24 -> 394,27]", + "modifiedRange": "[498,24 -> 498,28]" + } + ] + }, + { + "originalRange": "[457,540)", + "modifiedRange": "[561,561)", + "innerChanges": null + } + ] +} \ No newline at end of file diff --git a/src/vs/editor/test/node/diffing/fixtures/noisy-move1/legacy.invalid.diff.json b/src/vs/editor/test/node/diffing/fixtures/noisy-move1/legacy.invalid.diff.json new file mode 100644 index 00000000000..e69de29bb2d