Create a list of diff hunks in Unified diff format. Each hunk has a header generated by PrintHeader above plus a body with lines prefixed with ' ' for no change, '-' for deletion and '+' for addition. 'context' represents the desired unchanged prefix/suffix around the diff. If two hunks are close enough that their contexts overlap, then they are joined into one hunk.
| 2673 | // If two hunks are close enough that their contexts overlap, then they are |
| 2674 | // joined into one hunk. |
| 2675 | std::string CreateUnifiedDiff(const std::vector<std::string>& left, |
| 2676 | const std::vector<std::string>& right, |
| 2677 | size_t context) { |
| 2678 | const std::vector<EditType> edits = CalculateOptimalEdits(left, right); |
| 2679 | |
| 2680 | size_t l_i = 0, r_i = 0, edit_i = 0; |
| 2681 | std::stringstream ss; |
| 2682 | while (edit_i < edits.size()) { |
| 2683 | // Find first edit. |
| 2684 | while (edit_i < edits.size() && edits[edit_i] == kMatch) { |
| 2685 | ++l_i; |
| 2686 | ++r_i; |
| 2687 | ++edit_i; |
| 2688 | } |
| 2689 | |
| 2690 | // Find the first line to include in the hunk. |
| 2691 | const size_t prefix_context = std::min(l_i, context); |
| 2692 | Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); |
| 2693 | for (size_t i = prefix_context; i > 0; --i) { |
| 2694 | hunk.PushLine(' ', left[l_i - i].c_str()); |
| 2695 | } |
| 2696 | |
| 2697 | // Iterate the edits until we found enough suffix for the hunk or the input |
| 2698 | // is over. |
| 2699 | size_t n_suffix = 0; |
| 2700 | for (; edit_i < edits.size(); ++edit_i) { |
| 2701 | if (n_suffix >= context) { |
| 2702 | // Continue only if the next hunk is very close. |
| 2703 | std::vector<EditType>::const_iterator it = edits.begin() + edit_i; |
| 2704 | while (it != edits.end() && *it == kMatch) ++it; |
| 2705 | if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { |
| 2706 | // There is no next edit or it is too far away. |
| 2707 | break; |
| 2708 | } |
| 2709 | } |
| 2710 | |
| 2711 | EditType edit = edits[edit_i]; |
| 2712 | // Reset count when a non match is found. |
| 2713 | n_suffix = edit == kMatch ? n_suffix + 1 : 0; |
| 2714 | |
| 2715 | if (edit == kMatch || edit == kRemove || edit == kReplace) { |
| 2716 | hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); |
| 2717 | } |
| 2718 | if (edit == kAdd || edit == kReplace) { |
| 2719 | hunk.PushLine('+', right[r_i].c_str()); |
| 2720 | } |
| 2721 | |
| 2722 | // Advance indices, depending on edit type. |
| 2723 | l_i += edit != kAdd; |
| 2724 | r_i += edit != kRemove; |
| 2725 | } |
| 2726 | |
| 2727 | if (!hunk.has_edits()) { |
| 2728 | // We are done. We don't want this hunk. |
| 2729 | break; |
| 2730 | } |
| 2731 | |
| 2732 | hunk.PrintTo(&ss); |