From 67379c67cc4e633c9a2416fc46662f7b94964fb1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 5 May 2018 13:38:28 +0530 Subject: [PATCH] More work on the diff kitten --- kittens/diff/collect.py | 20 ++++++++++++---- kittens/diff/render.py | 53 ++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/kittens/diff/collect.py b/kittens/diff/collect.py index 603155836..c49f8ca9d 100644 --- a/kittens/diff/collect.py +++ b/kittens/diff/collect.py @@ -47,7 +47,12 @@ class Collection: def __iter__(self): for path in self.all_paths: typ = self.type_map[path] - data = self.changes[path] if typ == 'diff' else None + if typ == 'diff': + data = self.changes[path] + elif typ == 'rename': + data = self.renames[path] + else: + data = None yield path, self.type_map[path], data @@ -76,7 +81,7 @@ def collect_files(collection, left, right): for name, rh in rhash.items(): for n, ah in ahash.items(): if ah == rh and data_for_path(left_path_map[name]) == data_for_path(right_path_map[n]): - collection.add_rename(left_path_map[name], right_path_map[name]) + collection.add_rename(left_path_map[name], right_path_map[n]) added.discard(n) break else: @@ -103,9 +108,14 @@ def mime_type_for_path(path): @lru_cache(maxsize=1024) -def data_for_path(path): +def raw_data_for_path(path): with open(path, 'rb') as f: - ans = f.read() + return f.read() + + +@lru_cache(maxsize=1024) +def data_for_path(path): + ans = raw_data_for_path(path) if not mime_type_for_path(path).startswith('image/'): try: ans = ans.decode('utf-8') @@ -122,7 +132,7 @@ def lines_for_path(path): @lru_cache(maxsize=1024) def hash_for_path(path): - md5(data_for_path(path)).digest() + return md5(raw_data_for_path(path)).digest() def create_collection(left, right): diff --git a/kittens/diff/render.py b/kittens/diff/render.py index 766b360d1..0367e1c9e 100644 --- a/kittens/diff/render.py +++ b/kittens/diff/render.py @@ -124,13 +124,21 @@ def title_lines(left_path, args, columns, margin_size): def binary_lines(path, other_path, columns, margin_size): template = _('Binary file: {}') + available_cols = columns // 2 - margin_size - def fl(path): + def fl(path, fmt): text = template.format(human_readable(len(data_for_path(path)))) - text = place_in(text, columns // 2 - margin_size) - return margin_format(' ' * margin_size) + text_format(text) + text = place_in(text, available_cols) + return margin_format(' ' * margin_size) + fmt(text) - return fl(path) + fl(other_path) + if path is None: + filler = render_diff_line('', '', 'filler', margin_size, available_cols) + yield filler + fl(other_path, added_format) + elif other_path is None: + filler = render_diff_line('', '', 'filler', margin_size, available_cols) + yield fl(other_path, added_format) + filler + else: + yield fl(path, removed_format) + fl(other_path, added_format) def split_to_size(line, width): @@ -289,17 +297,24 @@ def all_lines(path, args, columns, margin_size, is_add=True): ltype = 'add' if is_add else 'remove' lines = lines_for_path(path) filler = render_diff_line('', '', 'filler', margin_size, available_cols) + msg_written = False for line_number in range(len(lines)): h = render_half_line(line_number, lines, ltype, margin_size, available_cols) for i, hl in enumerate(h): ref = Reference(path, LineRef(line_number, i)) - text = (filler + h) if is_add else (h + filler) + empty = filler + if not msg_written: + msg_written = True + empty = render_diff_line( + '', _('This file was added') if is_add else _('This file was removed'), + 'filler', margin_size, available_cols) + text = (empty + hl) if is_add else (hl + empty) yield Line(text, ref) def rename_lines(path, other_path, args, columns, margin_size): m = ' ' * margin_size - for line in split_to_size(margin_size + _('The file {0} was renamed to {1}').format( + for line in split_to_size(_('The file {0} was renamed to {1}').format( sanitize(path_name_map[path]), sanitize(path_name_map[other_path])), columns - margin_size): yield m + line @@ -316,19 +331,25 @@ def render_diff(collection, diff_map, args, columns): for path, item_type, other_path in collection: item_ref = Reference(path) + is_binary = isinstance(data_for_path(path), bytes) + yield from yield_lines_from(title_lines(path, args, columns, margin_size), item_ref) if item_type == 'diff': - yield from yield_lines_from(title_lines(path, args, columns, margin_size), item_ref) - is_binary = isinstance(data_for_path(path), bytes) if is_binary: - yield from yield_lines_from(binary_lines(path, other_path, columns, margin_size), item_ref) + ans = yield_lines_from(binary_lines(path, other_path, columns, margin_size), item_ref) else: - yield from lines_for_diff(path, other_path, diff_map[path], args, columns, margin_size) + ans = lines_for_diff(path, other_path, diff_map[path], args, columns, margin_size) elif item_type == 'add': - yield from yield_lines_from(title_lines(other_path, args, columns, margin_size), item_ref) - yield from all_lines(other_path, args, columns, margin_size, is_add=True) + if is_binary: + ans = yield_lines_from(binary_lines(None, path, columns, margin_size), item_ref) + else: + ans = all_lines(path, args, columns, margin_size, is_add=True) elif item_type == 'removal': - yield from yield_lines_from(title_lines(path, args, columns, margin_size), item_ref) - yield from all_lines(path, args, columns, margin_size, is_add=False) + if is_binary: + ans = yield_lines_from(binary_lines(path, None, columns, margin_size), item_ref) + else: + ans = all_lines(path, args, columns, margin_size, is_add=False) elif item_type == 'rename': - yield from yield_lines_from(title_lines(path, args, columns, margin_size), item_ref) - yield from yield_lines_from(rename_lines(path, other_path, args, columns, margin_size)) + ans = yield_lines_from(rename_lines(path, other_path, args, columns, margin_size), item_ref) + else: + raise ValueError('Unsupported item type: {}'.format(item_type)) + yield from ans