Source code for mkinit.util.util_diff

# -*- coding: utf-8 -*-
"""
Port of ubelt utilities + difftext wrapper around difflib
"""
from __future__ import print_function, division, absolute_import, unicode_literals
import os
import sys

# Global state that determines if ANSI-coloring text is allowed
# (which is mainly to address non-ANSI complient windows consoles)
# complient with https://no-color.org/
NO_COLOR = bool(os.environ.get("NO_COLOR"))


[docs] def difftext(text1, text2, context_lines=0, ignore_whitespace=False, colored=False): r""" Uses difflib to return a difference string between two similar texts Args: text1 (str): old text text2 (str): new text context_lines (int): number of lines of unchanged context ignore_whitespace (bool): colored (bool): if true highlight the diff Returns: str: formatted difference text message References: http://www.java2s.com/Code/Python/Utility/IntelligentdiffbetweentextfilesTimPeters.htm Example: >>> # build test data >>> text1 = 'one\ntwo\nthree' >>> text2 = 'one\ntwo\nfive' >>> # execute function >>> result = difftext(text1, text2) >>> # verify results >>> print(result) - three + five Example: >>> # build test data >>> text1 = 'one\ntwo\nthree\n3.1\n3.14\n3.1415\npi\n3.4\n3.5\n4' >>> text2 = 'one\ntwo\nfive\n3.1\n3.14\n3.1415\npi\n3.4\n4' >>> # execute function >>> context_lines = 1 >>> result = difftext(text1, text2, context_lines, colored=True) >>> # verify results >>> print(result) """ import difflib text1_lines = text1.splitlines() text2_lines = text2.splitlines() if ignore_whitespace: text1_lines = [t.rstrip() for t in text1_lines] text2_lines = [t.rstrip() for t in text2_lines] ndiff_kw = dict( linejunk=difflib.IS_LINE_JUNK, charjunk=difflib.IS_CHARACTER_JUNK ) else: ndiff_kw = {} all_diff_lines = list(difflib.ndiff(text1_lines, text2_lines, **ndiff_kw)) if context_lines is None: diff_lines = all_diff_lines else: # boolean for every line if it is marked or not ismarked_list = [len(line) > 0 and line[0] in "+-?" for line in all_diff_lines] # flag lines that are within context_lines away from a diff line isvalid_list = ismarked_list[:] for i in range(1, context_lines + 1): isvalid_list[:-i] = list( map(any, zip(isvalid_list[:-i], ismarked_list[i:])) ) isvalid_list[i:] = list(map(any, zip(isvalid_list[i:], ismarked_list[:-i]))) USE_BREAK_LINE = True if USE_BREAK_LINE: # insert a visual break when there is a break in context diff_lines = [] prev = False visual_break = "\n <... FILTERED CONTEXT ...> \n" # print(isvalid_list) for line, valid in zip(all_diff_lines, isvalid_list): if valid: diff_lines.append(line) elif prev: if False: diff_lines.append(visual_break) prev = valid else: diff_lines = [ line for line, flag in zip(all_diff_lines, isvalid_list) if flag ] text = "\n".join(diff_lines) if colored: text = highlight_code(text, lexer_name="diff") return text
[docs] def highlight_code(text, lexer_name="python", **kwargs): """ Highlights a block of text using ANSI tags based on language syntax. Args: text (str): plain text to highlight lexer_name (str): name of language. eg: python, docker, c++ **kwargs: passed to pygments.lexers.get_lexer_by_name Returns: str: text - highlighted text If pygments is not installed, the plain text is returned. Example: >>> text = 'import mkinit; print(mkinit)' >>> new_text = highlight_code(text) >>> print(new_text) """ if NO_COLOR: return text # Resolve extensions to languages lexer_name = { "py": "python", "h": "cpp", "cpp": "cpp", "cxx": "cpp", "c": "cpp", }.get(lexer_name.replace(".", ""), lexer_name) try: import pygments import pygments.lexers import pygments.formatters import pygments.formatters.terminal if sys.platform.startswith("win32"): # nocover # Hack on win32 to support colored output import colorama colorama.init() formater = pygments.formatters.terminal.TerminalFormatter(bg="dark") lexer = pygments.lexers.get_lexer_by_name(lexer_name, **kwargs) new_text = pygments.highlight(text, lexer, formater) except ImportError: # nocover import warnings warnings.warn("pygments is not installed, code will not be highlighted") new_text = text return new_text