private void ProcessConflict(Merge.Conflict conflict) { string[] userLines = SlyceMerge.GetLinesFromRange(user, conflict.Ranges[Merge.UserIndex]); string[] newgenLines = SlyceMerge.GetLinesFromRange(newgen, conflict.Ranges[Merge.NewGenIndex]); if (userLines.Length == 0 && newgenLines.Length == 0) { // user and template have both deleted some lines. Add them in as virtual lines. foreach (string line in SlyceMerge.GetLinesFromRange(prevgen, conflict.Ranges[Merge.PrevGenIndex])) { vdo.AddLineToLeft(line, ChangeType.UserAndTemplate); } return; } Diff diff = new Diff(userLines, newgenLines, true, true); foreach (Diff.Hunk hunk in diff) { if (hunk.Same) { foreach (string line in hunk.Original()) { vdo.AddLine(line, ChangeType.None); } continue; } // Conflict VisualDiffOutput.ConflictRange crange = new VisualDiffOutput.ConflictRange(); crange.StartLineIndex = vdo.LeftLines.Count; for (int i = hunk.Left.Start; i <= hunk.Left.End; i++) { vdo.LeftLines.Add(new DiffLine(userLines[i], ChangeType.User)); vdo.RightLines.Add(new DiffLine("", ChangeType.User, true)); } for (int i = hunk.Right.Start; i <= hunk.Right.End; i++) { vdo.LeftLines.Add(new DiffLine(newgenLines[i], ChangeType.Template)); vdo.RightLines.Add(new DiffLine("", ChangeType.Template, true)); } crange.EndLineIndex = vdo.LeftLines.Count; vdo.ConflictRanges.Add(crange); vdo.DiffType = TypeOfDiff.Conflict; } }
/// <summary> /// Perform 3-way merge /// </summary> /// <returns>Merged text.</returns> /// <param name="merge"></param> /// <param name="prevGenLines">Previously generated version ie: 'base version'.</param> /// <param name="userLines">User-modified version of 'base'.</param> /// <param name="nextGenLines">Latest generated version of 'base'.</param> internal static string GetMergedOutput(SlyceMergeResult merge, string[] prevGenLines, string[] userLines, string[] nextGenLines) { // default values and initialisation merge.DiffType = TypeOfDiff.ExactCopy; merge.Lines = new List <LineText>(200); string output = ""; int lineCounter = -1; const string pilcrowString = "¶"; const char pilcrow = '¶'; // diff the User version and LatestGenerated version against the PrevGenerated version IList res = Merge.MergeLists(prevGenLines, new[] { userLines, nextGenLines }); // handle empty input if (res.Count == 1 && res[0].Equals(string.Empty)) { return(string.Empty); } string conflictTypeName = typeof(Merge.Conflict).FullName; // process each line from the diff foreach (object line in res) { lineCounter++; string lineTypeName = line.GetType().ToString(); if (lineTypeName == "System.String") { string thisLine = (string)line; merge.Lines.Add(new LineText(thisLine.Replace(pilcrowString, ""), lineCounter, TypeOfLine.Normal)); } else if (lineTypeName == conflictTypeName) { Merge.Conflict conf = (Merge.Conflict)line; Range[] ranges = conf.Ranges; Range rangeUser = ranges[0]; Range rangeNewGen = ranges[1]; string[] conflictUserLines = GetLinesFromRange(userLines, rangeUser); string[] conflictNewGenLines = GetLinesFromRange(nextGenLines, rangeNewGen); // Get diff of the conflicts Diff diff = new Diff(conflictUserLines, conflictNewGenLines, true, false); foreach (Diff.Hunk hunk in diff) { if (hunk.Same) { string same = GetPortionOfString(conflictUserLines, hunk.Left.Start, hunk.Left.End); same = RemoveTrailingCharacter(pilcrowString, same); same = same.Replace(pilcrowString, "\r\n"); output += same; merge.Lines.Add(new LineText(same, lineCounter, TypeOfLine.Normal)); } else { // Get the user modified lines string userPortion = GetPortionOfString(conflictUserLines, hunk.Left.Start, hunk.Left.End); userPortion = RemoveTrailingCharacter(pilcrowString, userPortion); // Get the newly generated lines string newGenPortion = GetPortionOfString(conflictNewGenLines, hunk.Right.Start, hunk.Right.End); newGenPortion = RemoveTrailingCharacter(pilcrowString, newGenPortion); merge.SetDiffType(TypeOfDiff.Conflict); TypeOfLine lineType = newGenPortion.Length > 0 ? TypeOfLine.User : TypeOfLine.Normal; string[] userSplitLines = userPortion.Split(pilcrow); if (userPortion.Length > 0) { merge.Lines.Add(new LineText(userSplitLines[0], lineCounter, lineType)); } for (int myCount = 1; myCount < userSplitLines.Length; myCount++) { lineCounter++; merge.Lines.Add(new LineText(userSplitLines[myCount], lineCounter, lineType)); } lineType = userPortion.Length > 0 ? TypeOfLine.NewGen : TypeOfLine.Normal; string[] newGenSplitLines = newGenPortion.Split(pilcrow); if (newGenPortion.Length > 0) { merge.Lines.Add(new LineText(newGenSplitLines[0], lineCounter, lineType)); } for (int myCount = 1; myCount < newGenSplitLines.Length; myCount++) { lineCounter++; merge.Lines.Add(new LineText(newGenSplitLines[myCount], lineCounter, lineType)); } } } } else { throw new Exception(string.Format("Unexpected line type: {0}\nText1:{1}\n\nText2:{2}\n\nText3:{3}", line.GetType(), prevGenLines, userLines, nextGenLines)); } } return(output); }