Skip to content

Instantly share code, notes, and snippets.

@thomasfaingnaert
Last active June 3, 2022 02:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomasfaingnaert/2b21a0a9d0768063fa932be350f3eb49 to your computer and use it in GitHub Desktop.
Save thomasfaingnaert/2b21a0a9d0768063fa932be350f3eb49 to your computer and use it in GitHub Desktop.
Fancy git-diff output with syntax highlighting
#!/usr/bin/env python3
# Inspired by: https://gist.github.com/oprypin/9668969
import argparse
import pygments
import pygments.formatters
import pygments.lexers
import re
import sys
parser = argparse.ArgumentParser(description = 'Make git-diff output fancier by including syntax highlighting using Pygments.')
parser.add_argument('input', nargs='?', type=argparse.FileType('r'), default=sys.stdin, help='File containing the git-diff output')
parser.add_argument('--output', '-o', nargs='?', type=argparse.FileType('w'), default=sys.stdout, help='Output HTML file')
args = parser.parse_args()
# Regular expressions to ignore in the output.
ignore_patterns = [r'^diff --git', r'^index [0-9a-fA-F]+..[0-9a-fA-F]+ [0-9a-fA-F]+']
ignore_regexes = [re.compile(pat) for pat in ignore_patterns]
# Pygments setup.
formatter = pygments.formatters.HtmlFormatter(nowrap=True)
infile = args.input
outfile = args.output
outfile.write('<!DOCTYPE html>')
outfile.write('<html>')
outfile.write('<head>')
outfile.write('<title>Diff</title>')
outfile.write('<style>')
outfile.write(formatter.get_style_defs())
outfile.write('.diff_header { font-size: 1.6em; font-weight: bold; }')
outfile.write('.diff_minus { background-color: rgba(255, 0, 0, 0.3) }')
outfile.write('.diff_plus { background-color: rgba(0, 255, 0, 0.3) }')
outfile.write('.diff_special { background-color: rgba(128, 128, 128, 0.3); font-size: 1.3em; }')
outfile.write('.err { border: none; }')
outfile.write('</style>')
outfile.write('</head>')
outfile.write('<body>')
outfile.write('<div>')
outfile.write('<pre>')
filename = ''
def highlight(line, filename):
try:
lexer = pygments.lexers.get_lexer_for_filename(filename)
return pygments.highlight(line, lexer, formatter)
except:
return line
for line in infile.readlines():
if any(regex.match(line) for regex in ignore_regexes):
continue
if line.startswith('--- ') or line.startswith('+++ '):
filename = line[4:].rstrip('\n')
if line.startswith('@@'):
pos = line.find('@@', 2)
line_range = line[:pos+2]
context = line[pos+2:]
highlighted_line = line_range + highlight(context, filename)
elif line.startswith('+++') or line.startswith('---'):
highlighted_line = f'<div class="diff_header">{line}</div>'
elif line.startswith('+') or line.startswith('-'):
highlighted_line = line[:1] + highlight(line[1:], filename)
else:
highlighted_line = highlight(line, filename)
cls = {'+': 'diff_plus', '-': 'diff_minus', '@': 'diff_special'}.get(line[0:1], '')
if cls != '':
cls = f' class="{cls}"'
outfile.write(f'<div{cls}>{highlighted_line}</div>')
outfile.write('</pre>')
outfile.write('</div>')
outfile.write('</body>')
outfile.write('</html>')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment