Update accept actions for new conflict parser

This commit is contained in:
Phil Price 2017-05-22 18:31:04 -07:00
parent 4dcf156655
commit 1535f99ffe
4 changed files with 55 additions and 61 deletions

View file

@ -52,35 +52,11 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict
}
else if (type === interfaces.CommitType.Both) {
// Replace [ Conflict Range ] with [ Current Content ] + \n + [ Incoming Content ]
//
// NOTE: Due to headers and splitters NOT covering \n (this is so newlines inserted)
// by the user after (e.g. <<<<< HEAD do not fall into the header range but the
// content ranges), we can't push 3x deletes, we need to replace the range with the
// union of the content.
const currentContent = editor.document.getText(this.current.content);
const incomingContent = editor.document.getText(this.incoming.content);
let finalContent = '';
if (!this.isNewlineOnly(currentContent)) {
finalContent += currentContent;
}
if (!this.isNewlineOnly(incomingContent)) {
if (finalContent.length > 0) {
finalContent += '\n';
}
finalContent += incomingContent;
}
if (finalContent.length > 0 && !this.isNewlineOnly(finalContent)) {
finalContent += '\n';
}
edit.setEndOfLine(vscode.EndOfLine.LF);
edit.replace(this.range, finalContent);
edit.replace(this.range, currentContent.concat(incomingContent));
}
}
@ -90,12 +66,8 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict
return;
}
let updatedContent = content.concat('\n');
edit.setEndOfLine(vscode.EndOfLine.LF);
// Replace [ Conflict Range ] with [ Current Content ]
edit.replace(this.range, updatedContent);
edit.replace(this.range, content);
}
private isNewlineOnly(text: string) {

View file

@ -8,6 +8,7 @@ export interface IMergeRegion {
name: string;
header: vscode.Range;
content: vscode.Range;
decoratorContent: vscode.Range;
}
export enum CommitType {

View file

@ -6,14 +6,14 @@ import * as vscode from 'vscode';
import * as interfaces from './interfaces';
import { DocumentMergeConflict } from './documentMergeConflict';
const startMarker = '<<<<<<<';
const startMarker = '<<<<<<< ';
const splitterMarker = '=======';
const endMarker = '>>>>>>>';
const endMarker = '>>>>>>> ';
interface IPartialMergeConflictDescriptor {
currentHeader: vscode.Range;
splitter?: vscode.Range;
incomingFooter?: vscode.Range;
currentHeader: vscode.TextLine;
splitter?: vscode.TextLine;
incomingFooter?: vscode.TextLine;
}
export class MergeConflictParser {
@ -37,9 +37,7 @@ export class MergeConflictParser {
break;
}
currentConflict = {
currentHeader: line.range
};
currentConflict = { currentHeader: line };
}
else if (line.text.startsWith(splitterMarker)) {
@ -47,16 +45,16 @@ export class MergeConflictParser {
continue; // Ignore
}
currentConflict.splitter = line.range;
currentConflict.splitter = line;
}
else if (line.text.startsWith(endMarker)) {
if (currentConflict === null) {
continue; // Ignore
}
currentConflict.incomingFooter = line.range;
currentConflict.incomingFooter = line;
let completeDescriptor = MergeConflictParser.completePartialMergeDescriptor(currentConflict);
let completeDescriptor = MergeConflictParser.completePartialMergeDescriptor(document, currentConflict);
if (completeDescriptor !== null) {
conflictDescriptors.push(completeDescriptor);
@ -71,30 +69,43 @@ export class MergeConflictParser {
.map(descriptor => new DocumentMergeConflict(document, descriptor));
}
private static completePartialMergeDescriptor(partial: IPartialMergeConflictDescriptor): interfaces.IDocumentMergeConflictDescriptor | null {
// Assume that descriptor.current.header, descriptor.incoming.header and descriptor.spliiter
// have valid ranges, fill in content and total ranges from these parts.
private static completePartialMergeDescriptor(document: vscode.TextDocument, partial: IPartialMergeConflictDescriptor): interfaces.IDocumentMergeConflictDescriptor | null {
// Validate we have valid ranges
if (!partial.currentHeader || !partial.splitter || !partial.incomingFooter) {
return null;
}
// Assume that descriptor.current.header, descriptor.incoming.header and descriptor.spliiter
// have valid ranges, fill in content and total ranges from these parts.
// NOTE: We need to shift the decortator range back one character so the splitter does not end up with
// two decoration colors (current and splitter), if we take the new line from the content into account
// the decorator will wrap to the next line.
return {
current: {
header: partial.currentHeader,
// Current content is range between header and splitter
content: new vscode.Range(partial.currentHeader.end, partial.splitter.start),
name: ''
header: partial.currentHeader.range,
decoratorContent: new vscode.Range(
partial.currentHeader.rangeIncludingLineBreak.end,
MergeConflictParser.shiftBackOneCharacter(document, partial.splitter.range.start)),
// Current content is range between header (shifted for linebreak) and splitter start
content: new vscode.Range(
partial.currentHeader.rangeIncludingLineBreak.end,
partial.splitter.range.start),
name: document.getText(partial.currentHeader.range).substring(startMarker.length)
},
splitter: partial.splitter,
splitter: partial.splitter.range,
incoming: {
header: partial.incomingFooter,
// Incoming content is range between splitter and footer
content: new vscode.Range(partial.splitter.end, partial.incomingFooter.end),
name: ''
header: partial.incomingFooter.range,
decoratorContent: new vscode.Range(
partial.splitter.rangeIncludingLineBreak.end,
MergeConflictParser.shiftBackOneCharacter(document, partial.incomingFooter.range.start)),
// Incoming content is range between splitter (shifted for linebreak) and footer start
content: new vscode.Range(
partial.splitter.rangeIncludingLineBreak.end,
partial.incomingFooter.range.start),
name: document.getText(partial.incomingFooter.range).substring(endMarker.length)
},
// Entire range is between current header start and incoming header end
range: new vscode.Range(partial.currentHeader.start, partial.incomingFooter.end)
// Entire range is between current header start and incoming header end (including line break)
range: new vscode.Range(partial.currentHeader.range.start, partial.incomingFooter.rangeIncludingLineBreak.end)
};
}
@ -103,8 +114,19 @@ export class MergeConflictParser {
return false;
}
// TODO: Ask source control if the file contains a conflict
let text = document.getText();
return text.includes('<<<<<<<') && text.includes('>>>>>>>');
return text.includes(startMarker) && text.includes(endMarker);
}
private static shiftBackOneCharacter(document: vscode.TextDocument, range: vscode.Position): vscode.Position {
let line = range.line;
let character = range.character - 1;
if (character < 0) {
line--;
character = document.lineAt(line).range.end.character;
}
return new vscode.Position(line, character);
}
}

View file

@ -7,7 +7,6 @@ import * as interfaces from './interfaces';
import { loadMessageBundle } from 'vscode-nls';
const localize = loadMessageBundle();
export default class MergeDectorator implements vscode.Disposable {
private decorations: { [key: string]: vscode.TextEditorDecorationType } = {};
@ -169,8 +168,8 @@ export default class MergeDectorator implements vscode.Disposable {
conflicts.forEach(conflict => {
// TODO, this could be more effective, just call getMatchPositions once with a map of decoration to position
pushDecoration('current.content', { range: conflict.current.content });
pushDecoration('incoming.content', { range: conflict.incoming.content });
pushDecoration('current.content', { range: conflict.current.decoratorContent });
pushDecoration('incoming.content', { range: conflict.incoming.decoratorContent });
if (this.config.enableDecorations) {
pushDecoration('current.header', { range: conflict.current.header });