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