diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index efc0ff0cf7a..9c4ee8d7a16 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -81,6 +81,12 @@ "title": "%command.compare%", "original": "Compare Current Conflict", "command": "merge-conflict.compare" + }, + { + "category": "%command.category%", + "title": "%command.compareAll%", + "original": "Compare All Conflict in Current Editor", + "command": "merge-conflict.compareAll" } ], "menus": { @@ -114,6 +120,11 @@ "type": "boolean", "description": "%config.autoNavigateNextConflictEnabled%", "default": false + }, + "merge-conflict.diffViewContext": { + "type": "number", + "description": "%config.diffViewContext%", + "default": 0 } } } diff --git a/extensions/merge-conflict/package.nls.json b/extensions/merge-conflict/package.nls.json index 94599bf281e..ada72166f63 100644 --- a/extensions/merge-conflict/package.nls.json +++ b/extensions/merge-conflict/package.nls.json @@ -12,8 +12,10 @@ "command.next": "Next Conflict", "command.previous": "Previous Conflict", "command.compare": "Compare Current Conflict", + "command.compareAll": "Compare All Conflict in Current Editor", "config.title": "Merge Conflict", "config.autoNavigateNextConflictEnabled": "Whether to automatically navigate to the next merge conflict after resolving a merge conflict.", "config.codeLensEnabled": "Create a Code Lens for merge conflict blocks within editor.", - "config.decoratorsEnabled": "Create decorators for merge conflict blocks within editor." + "config.decoratorsEnabled": "Create decorators for merge conflict blocks within editor.", + "config.diffViewContext": "Controls how many unchanged lines around the merge conflict should be displayed in the diff view." } \ No newline at end of file diff --git a/extensions/merge-conflict/src/codelensProvider.ts b/extensions/merge-conflict/src/codelensProvider.ts index 6ee4f2f043b..39a82053ea4 100644 --- a/extensions/merge-conflict/src/codelensProvider.ts +++ b/extensions/merge-conflict/src/codelensProvider.ts @@ -85,11 +85,17 @@ export default class MergeConflictCodeLensProvider implements vscode.CodeLensPro arguments: [conflict] }; + let diffAllCommand: vscode.Command = { + command: 'merge-conflict.compareAll', + title: localize('compareAllChanges', 'Compare All Changes') + }; + items.push( new vscode.CodeLens(conflict.range, acceptCurrentCommand), new vscode.CodeLens(conflict.range.with(conflict.range.start.with({ character: conflict.range.start.character + 1 })), acceptIncomingCommand), new vscode.CodeLens(conflict.range.with(conflict.range.start.with({ character: conflict.range.start.character + 2 })), acceptBothCommand), - new vscode.CodeLens(conflict.range.with(conflict.range.start.with({ character: conflict.range.start.character + 3 })), diffCommand) + new vscode.CodeLens(conflict.range.with(conflict.range.start.with({ character: conflict.range.start.character + 3 })), diffCommand), + new vscode.CodeLens(conflict.range.with(conflict.range.start.with({ character: conflict.range.start.character + 4 })), diffAllCommand) ); }); diff --git a/extensions/merge-conflict/src/commandHandler.ts b/extensions/merge-conflict/src/commandHandler.ts index 3247b592f88..4bcca575430 100644 --- a/extensions/merge-conflict/src/commandHandler.ts +++ b/extensions/merge-conflict/src/commandHandler.ts @@ -39,7 +39,8 @@ export default class CommandHandler implements vscode.Disposable { this.registerTextEditorCommand('merge-conflict.accept.all-both', this.acceptAllBoth), this.registerTextEditorCommand('merge-conflict.next', this.navigateNext), this.registerTextEditorCommand('merge-conflict.previous', this.navigatePrevious), - this.registerTextEditorCommand('merge-conflict.compare', this.compare) + this.registerTextEditorCommand('merge-conflict.compare', this.compare), + this.registerTextEditorCommand('merge-conflict.compareAll', this.compareAll) ); } @@ -92,11 +93,36 @@ export default class CommandHandler implements vscode.Disposable { let range = conflict.current.content; const leftUri = editor.document.uri.with({ scheme: ContentProvider.scheme, - query: JSON.stringify({ scheme, range }) + query: JSON.stringify({ scheme, range, fullRange: conflict.range }) }); range = conflict.incoming.content; - const rightUri = leftUri.with({ query: JSON.stringify({ scheme, range }) }); + const rightUri = leftUri.with({ query: JSON.stringify({ scheme, range, fullRange: conflict.range }) }); + + const title = localize('compareChangesTitle', '{0}: Current Changes ⟷ Incoming Changes', fileName); + vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title); + } + + async compareAll(editor: vscode.TextEditor) { + const fileName = path.basename(editor.document.uri.fsPath); + const conflicts = await this.tracker.getConflicts(editor.document); + + // Still failed to find conflict, warn the user and exit + if (!conflicts) { + vscode.window.showWarningMessage(localize('cursorNotInConflict', 'Editor cursor is not within a merge conflict')); + return; + } + + const scheme = editor.document.uri.scheme; + let leftRanges = conflicts.map(conflict => [conflict.current.content, conflict.range]); + let rightRanges = conflicts.map(conflict => [conflict.incoming.content, conflict.range]); + + const leftUri = editor.document.uri.with({ + scheme: ContentProvider.scheme, + query: JSON.stringify({ type: 'full', scheme, ranges: leftRanges }) + }); + + const rightUri = leftUri.with({ query: JSON.stringify({ type: 'full', scheme, ranges: rightRanges }) }); const title = localize('compareChangesTitle', '{0}: Current Changes ⟷ Incoming Changes', fileName); vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title); diff --git a/extensions/merge-conflict/src/contentProvider.ts b/extensions/merge-conflict/src/contentProvider.ts index b22ab0a21c1..71bb82380f7 100644 --- a/extensions/merge-conflict/src/contentProvider.ts +++ b/extensions/merge-conflict/src/contentProvider.ts @@ -23,12 +23,40 @@ export default class MergeConflictContentProvider implements vscode.TextDocument async provideTextDocumentContent(uri: vscode.Uri): Promise { try { - const { scheme, range } = JSON.parse(uri.query) as { scheme: string; range: { line: number, character: number }[] }; - const [start, end] = range; + const { type, scheme, range, fullRange, ranges } = JSON.parse(uri.query) as { type: string, scheme: string; range: { line: number, character: number }[], fullRange: { line: number, character: number }[], ranges: [{ line: number, character: number }[], { line: number, character: number }[]][] }; - const document = await vscode.workspace.openTextDocument(uri.with({ scheme, query: '' })); - const text = document.getText(new vscode.Range(start.line, start.character, end.line, end.character)); - return text; + if (type === 'full') { + // complete diff + const document = await vscode.workspace.openTextDocument(uri.with({ scheme, query: '' })); + + let text = ''; + let lastPosition = new vscode.Position(0, 0); + ranges.forEach(rangeObj => { + let [range, fullRange] = rangeObj; + const [start, end] = range; + const [fullStart, fullEnd] = fullRange; + + text += document.getText(new vscode.Range(lastPosition.line, lastPosition.character, fullStart.line, fullStart.character)); + text += document.getText(new vscode.Range(start.line, start.character, end.line, end.character)); + lastPosition = new vscode.Position(fullEnd.line, fullEnd.character); + }); + + let documentEnd = document.lineAt(document.lineCount - 1).range.end; + text += document.getText(new vscode.Range(lastPosition.line, lastPosition.character, documentEnd.line, documentEnd.character)); + + return text; + } else { + const [start, end] = range; + const [fullStart, fullEnd] = fullRange; + const mergeConflictConfig = vscode.workspace.getConfiguration('merge-conflict'); + const context = Math.max(0, mergeConflictConfig.get('diffViewContext') || 0); + const document = await vscode.workspace.openTextDocument(uri.with({ scheme, query: '' })); + const text = + document.getText(new vscode.Range(Math.max(0, fullStart.line - context), 0, fullStart.line, fullStart.character)) + + document.getText(new vscode.Range(start.line, start.character, end.line, end.character)) + + document.getText(new vscode.Range(fullEnd.line, fullEnd.character, Math.min(document.lineCount, fullEnd.line + context + 1), 0)); + return text; + } } catch (ex) { await vscode.window.showErrorMessage('Unable to show comparison');