diff --git a/kittens/diff/images.py b/kittens/diff/images.py new file mode 100644 index 000000000..273d0957f --- /dev/null +++ b/kittens/diff/images.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +# License: GPL v3 Copyright: 2018, Kovid Goyal + +import shutil +import warnings + + +class ImageSupportWarning(Warning): + pass + + +def images_supported(): + ans = getattr(images_supported, 'ans', None) + if ans is None: + ans = shutil.which('convert') is not None + images_supported.ans = ans + if not ans: + warnings.warn('ImageMagick not found images cannot be displayed', ImageSupportWarning) + return ans diff --git a/kittens/diff/main.py b/kittens/diff/main.py index 75bc7547c..03bd12117 100644 --- a/kittens/diff/main.py +++ b/kittens/diff/main.py @@ -4,6 +4,7 @@ import os import sys +import warnings from collections import defaultdict from functools import partial from gettext import gettext as _ @@ -17,6 +18,7 @@ from ..tui.loop import Loop from .collect import create_collection, data_for_path, set_highlight_data from .config import init_config +from .images import ImageSupportWarning from .patch import Differ, set_diff_command from .render import LineRef, render_diff @@ -305,7 +307,16 @@ def on_eot(self): '''.format, config_help=CONFIG_HELP.format(conf_name='diff', appname=appname)) +def showwarning(message, category, filename, lineno, file=None, line=None): + if category is ImageSupportWarning: + showwarning.warnings.append(message) + + +showwarning.warnings = [] + + def main(args): + warnings.showwarning = showwarning msg = 'Show a side-by-side diff of the specified files/directories' args, items = parse_args(args[1:], OPTIONS, 'file_or_directory file_or_directory', msg, 'kitty +kitten diff') if len(items) != 2: @@ -319,6 +330,9 @@ def main(args): loop = Loop() handler = DiffHandler(args, opts, left, right) loop.loop(handler) + for message in showwarning.warnings: + from kitty.utils import safe_print + safe_print(message, file=sys.stderr) if loop.return_code != 0: if handler.report_traceback_on_exit: print(handler.report_traceback_on_exit, file=sys.stderr) diff --git a/kittens/diff/render.py b/kittens/diff/render.py index 76319d6ff..99606d760 100644 --- a/kittens/diff/render.py +++ b/kittens/diff/render.py @@ -8,11 +8,12 @@ from kitty.fast_data_types import truncate_point_for_length, wcswidth from .collect import ( - Segment, data_for_path, highlights_for_path, lines_for_path, path_name_map, - sanitize + Segment, data_for_path, highlights_for_path, is_image, lines_for_path, + path_name_map, sanitize ) from .config import formats from .diff_speedup import split_with_highlights as _split_with_highlights +from .images import images_supported class Ref: @@ -352,6 +353,11 @@ def rename_lines(path, other_path, args, columns, margin_size): yield m + line +def image_lines(left_path, right_path, columns, margin_size): + if False: + yield 0 + + def render_diff(collection, diff_map, args, columns): largest_line_number = 0 for path, item_type, other_path in collection: @@ -366,20 +372,30 @@ def render_diff(collection, diff_map, args, columns): for i, (path, item_type, other_path) in enumerate(collection): item_ref = Reference(path) is_binary = isinstance(data_for_path(path), bytes) + is_img = is_binary and is_image(path) and images_supported() yield from yield_lines_from(title_lines(path, other_path, args, columns, margin_size), item_ref, False) if item_type == 'diff': if is_binary: - ans = yield_lines_from(binary_lines(path, other_path, columns, margin_size), item_ref) + if is_img: + ans = image_lines(path, other_path, columns, margin_size) + else: + ans = yield_lines_from(binary_lines(path, other_path, columns, margin_size), item_ref) else: ans = lines_for_diff(path, other_path, diff_map[path], args, columns, margin_size) elif item_type == 'add': if is_binary: - ans = yield_lines_from(binary_lines(None, path, columns, margin_size), item_ref) + if is_img: + ans = image_lines(None, path, columns, margin_size) + else: + 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': if is_binary: - ans = yield_lines_from(binary_lines(path, None, columns, margin_size), item_ref) + if is_img: + ans = image_lines(path, None, columns, margin_size) + else: + 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':