def test_side_by_side8(self): display_lines = [ logging.red( logging.red_diff('1') + ' 0 2' + ' ' * (self.max_chars - 5)) + '|' + logging.green(logging.green_diff('2') + ' 0 2'), logging.red('1 ' + logging.red_diff('0') + ' 2' + ' ' * (self.max_chars - 5)) + '|' + logging.green('1 ' + logging.green_diff('1') + ' 2'), logging.red('1 0 ' + logging.red_diff('2') + ' ' * (self.max_chars - 5)) + '|' + logging.green('1 0 ' + logging.green_diff('3')), ] self.snippet_call_test('1 0 2\n1 0 2\n1 0 2', '2 0 2\n1 1 2\n1 0 3', display_lines)
def test_side_by_side7(self): display_lines = [ logging.red(logging.red_diff('0 2') + ' ' * (self.max_chars - 3)) + '|' + logging.green(''), logging.red(logging.red_diff('1 2') + ' ' * (self.max_chars - 3)) + '|' + logging.green(''), '2 2' + ' ' * (self.max_chars - 3) + '|2 2', '3 2' + ' ' * (self.max_chars - 3) + '|3 2', '4 2' + ' ' * (self.max_chars - 3) + '|4 2', logging.red(' ' * (self.max_chars)) + '|' + logging.green(logging.green_diff('5 2')), logging.red(' ' * (self.max_chars)) + '|' + logging.green(logging.green_diff('6 2')), ] self.snippet_call_test('0 2\n1 2\n2 2\n3 2\n4 2', '2 2\n3 2\n4 2\n5 2\n6 2', display_lines)
def test_side_by_side4(self): display_lines = [ 'Alice' + ' ' * (self.max_chars - 5) + '|Alice', logging.red('B' + logging.red_diff('0') + 'b' + ' ' * (self.max_chars - 3)) + '|' + logging.green('B' + logging.green_diff('o') + 'b'), 'Alice' + ' ' * (self.max_chars - 5) + '|Alice', ] self.snippet_call_test('Alice\nB0b\nAlice', 'Alice\nBob\nAlice', display_lines)
def test_side_by_side2(self): display_lines = [ '98 |Alice' + ' ' * (self.max_chars - 9) + '|Alice', '99 |Bob' + ' ' * (self.max_chars - 7) + '|Bob', '100|Alice' + ' ' * (self.max_chars - 9) + '|Alice', '101|' + logging.red(logging.red_diff('Bob') + ' ' * (self.max_chars - 7)) + '|' + logging.green(logging.green_diff('John')), '102|' + logging.red( logging.red_diff('Alice') + ' ' * (self.max_chars - 9)) + '|' + logging.green(logging.green_diff('John')), '103|Bob' + ' ' * (self.max_chars - 7) + '|Bob', '104|Alice' + ' ' * (self.max_chars - 9) + '|Alice', '... (1 lines) ...', ] output = ('\n' * 97 + 'Alice\nBob\nAlice\nBob\nAlice\nBob\nAlice\nBob').replace( '\n', os.linesep) expect = ('\n' * 97 + 'Alice\nBob\nAlice\nJohn\nJohn\nBob\nAlice\nBob').replace( '\n', os.linesep) self.snippet_call_test(output, expect, display_lines, 3)
def test_side_by_side1(self): display_lines = [ '41|Alice' + ' ' * (self.max_chars - 8) + '|Alice', '42|Bob' + ' ' * (self.max_chars - 6) + '|Bob', '43|Alice' + ' ' * (self.max_chars - 8) + '|Alice', '44|' + logging.red(logging.red_diff('Bob') + ' ' * (self.max_chars - 6)) + '|' + logging.green(logging.green_diff('John')), '45|' + logging.red( logging.red_diff('Alice') + ' ' * (self.max_chars - 8)) + '|' + logging.green(logging.green_diff('John')), '46|Bob' + ' ' * (self.max_chars - 6) + '|Bob', '47|Alice' + ' ' * (self.max_chars - 8) + '|Alice', '... (1 lines) ...', ] output = ('\n' * 40 + 'Alice\nBob\nAlice\nBob\nAlice\nBob\nAlice\nBob').replace( '\n', os.linesep) expect = ('\n' * 40 + 'Alice\nBob\nAlice\nJohn\nJohn\nBob\nAlice\nBob').replace( '\n', os.linesep) self.snippet_call_test(output, expect, display_lines, 2)
def side_by_side_diff(old_text: str, new_text: str) -> Generator[Tuple[bool, bool, str, str, int, int], None, None]: """ Calculates a side-by-side line-based difference view. """ line_split = re.compile(r'(?:\r?\n)') dmp = diff_match_patch.diff_match_patch() diff = dmp.diff_main(old_text, new_text) dmp.diff_cleanupSemantic(diff) open_entry = ([''], [''], [0], [0]) for change_type, entry in diff: assert change_type in [-1, 0, 1] entry = (entry.replace('&', '&').replace('<', '<').replace('>', '>')) lines = line_split.split(entry) # Merge with previous entry if still open ls, rs, lnums, rnums = open_entry line = lines[0] if line: if change_type == 0: ls[-1] += line rs[-1] += line lnums[-1] += len(line) rnums[-1] += len(line) elif change_type == 1: rs[-1] = rs[-1] or '' rs[-1] += log.green_diff(line) if line else '' rnums[-1] += len(line) elif change_type == -1: ls[-1] = ls[-1] or '' ls[-1] += log.red_diff(line) if line else '' lnums[-1] += len(line) lines = lines[1:] if lines: if change_type == 0: # Push out open entry for entry in yield_open_entry(open_entry): yield entry # Directly push out lines until last for line in lines[:-1]: yield (True, False, line, line, len(line), len(line)) # Keep last line open open_entry = ([lines[-1]], [lines[-1]], [len(lines[-1])], [len(lines[-1])]) elif change_type == 1: ls, rs, lnums, rnums = open_entry for line in lines: rs.append(log.green_diff(line) if line else '') rnums.append(len(line)) elif change_type == -1: ls, rs, lnums, rnums = open_entry for line in lines: ls.append(log.red_diff(line) if line else '') lnums.append(len(line)) # Push out open entry for entry in yield_open_entry(open_entry): yield entry
def test_side_by_side2(self): self.snippet_call_test( 'kmy', 'kmv', (logging.red('km' + logging.red_diff('y') + ' ' * (self.max_chars - 3)) + '|' + logging.green('km' + logging.green_diff('v')), ))