Hunks.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Hunks.h"
  7. #include <AK/Debug.h>
  8. namespace Diff {
  9. Vector<Hunk> parse_hunks(DeprecatedString const& diff)
  10. {
  11. Vector<DeprecatedString> diff_lines = diff.split('\n');
  12. if (diff_lines.is_empty())
  13. return {};
  14. Vector<Hunk> hunks;
  15. size_t line_index = 0;
  16. HunkLocation current_location {};
  17. // Skip to first hunk
  18. while (diff_lines[line_index][0] != '@') {
  19. ++line_index;
  20. }
  21. while (line_index < diff_lines.size()) {
  22. if (diff_lines[line_index][0] == '@') {
  23. current_location = parse_hunk_location(diff_lines[line_index]);
  24. ++line_index;
  25. continue;
  26. }
  27. if (diff_lines[line_index][0] == ' ') {
  28. current_location.apply_offset(1, HunkLocation::LocationType::Both);
  29. ++line_index;
  30. continue;
  31. }
  32. Hunk hunk {};
  33. hunk.original_start_line = current_location.original_start_line;
  34. hunk.target_start_line = current_location.target_start_line;
  35. while (line_index < diff_lines.size() && diff_lines[line_index][0] == '-') {
  36. hunk.removed_lines.append(diff_lines[line_index].substring(1, diff_lines[line_index].length() - 1));
  37. current_location.apply_offset(1, HunkLocation::LocationType::Original);
  38. ++line_index;
  39. }
  40. while (line_index < diff_lines.size() && diff_lines[line_index][0] == '+') {
  41. hunk.added_lines.append(diff_lines[line_index].substring(1, diff_lines[line_index].length() - 1));
  42. current_location.apply_offset(1, HunkLocation::LocationType::Target);
  43. ++line_index;
  44. }
  45. while (line_index < diff_lines.size() && diff_lines[line_index][0] == ' ') {
  46. current_location.apply_offset(1, HunkLocation::LocationType::Both);
  47. ++line_index;
  48. }
  49. hunks.append(hunk);
  50. }
  51. if constexpr (HUNKS_DEBUG) {
  52. for (auto const& hunk : hunks) {
  53. dbgln("Hunk location:");
  54. dbgln(" orig: {}", hunk.original_start_line);
  55. dbgln(" target: {}", hunk.target_start_line);
  56. dbgln(" removed:");
  57. for (auto const& line : hunk.removed_lines)
  58. dbgln("- {}", line);
  59. dbgln(" added:");
  60. for (auto const& line : hunk.added_lines)
  61. dbgln("+ {}", line);
  62. }
  63. }
  64. return hunks;
  65. }
  66. HunkLocation parse_hunk_location(DeprecatedString const& location_line)
  67. {
  68. size_t char_index = 0;
  69. struct StartAndLength {
  70. size_t start { 0 };
  71. size_t length { 0 };
  72. };
  73. auto parse_start_and_length_pair = [](DeprecatedString const& raw) {
  74. auto index_of_separator = raw.find(',').value();
  75. auto start = raw.substring(0, index_of_separator).to_uint().value();
  76. auto length = raw.substring(index_of_separator + 1, raw.length() - index_of_separator - 1).to_uint().value();
  77. if (start != 0)
  78. start--;
  79. if (length != 0)
  80. length--;
  81. return StartAndLength { start, length };
  82. };
  83. while (char_index < location_line.length() && location_line[char_index++] != '-') {
  84. }
  85. VERIFY(char_index < location_line.length());
  86. size_t original_location_start_index = char_index;
  87. while (char_index < location_line.length() && location_line[char_index++] != ' ') {
  88. }
  89. VERIFY(char_index < location_line.length() && location_line[char_index] == '+');
  90. size_t original_location_end_index = char_index - 2;
  91. size_t target_location_start_index = char_index + 1;
  92. char_index += 1;
  93. while (char_index < location_line.length() && location_line[char_index++] != ' ') {
  94. }
  95. VERIFY(char_index < location_line.length());
  96. size_t target_location_end_index = char_index - 2;
  97. auto original_pair = parse_start_and_length_pair(location_line.substring(original_location_start_index, original_location_end_index - original_location_start_index + 1));
  98. auto target_pair = parse_start_and_length_pair(location_line.substring(target_location_start_index, target_location_end_index - target_location_start_index + 1));
  99. return { original_pair.start, original_pair.length, target_pair.start, target_pair.length };
  100. }
  101. void HunkLocation::apply_offset(size_t offset, HunkLocation::LocationType type)
  102. {
  103. if (type == LocationType::Original || type == LocationType::Both) {
  104. original_start_line += offset;
  105. original_length -= offset;
  106. }
  107. if (type == LocationType::Target || type == LocationType::Both) {
  108. target_start_line += offset;
  109. target_length -= offset;
  110. }
  111. }
  112. };