X-Git-Url: http://git.droids-corp.org/?p=diff2html.git;a=blobdiff_plain;f=diff2html.py;h=92bbf362acf9a1b55b073c842181caa3112f2a59;hp=59d445dbf9cdf9dfd655a6bacf881feafd56c7bf;hb=c23d783c8f55be1471c90c51b9bbab4dd302e7c9;hpb=715a85a7ac2a121d30b421b128cb96533c3001b2 diff --git a/diff2html.py b/diff2html.py index 59d445d..92bbf36 100644 --- a/diff2html.py +++ b/diff2html.py @@ -1,4 +1,5 @@ #! /usr/bin/python +# coding=utf-8 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,23 +19,14 @@ # Transform a unified diff from stdin to a colored # side-by-side HTML page on stdout. # -# Author: Olivier MATZ +# Authors: Olivier MATZ +# Alan De Smet +# Sergey Satskiy +# scito # # Inspired by diff2html.rb from Dave Burt # (mainly for html theme) # -# Changed by Alan De Smet 2009-01-25 -# - Remove headers and footers that are undesirable for for CVSTrac -# integration. -# - Change style sheet to own preferences -# - Adjust LINESIZE code to reset counter and allow breaks whenever -# WORDBREAK characters are encountered. -# - Don't display offset info (it's redundant with the line numbers) -# instead show vertical ellipsis -# - If part of a "change" is actually blank, it's an addition or -# deletion, not a "change" where the entire line changed. -# - Don't display "\" for end of line; unnecessary noise. - # TODO: # - The sane function currently mashes non-ASCII characters to "." # Instead be clever and convert to something like "xF0" @@ -43,58 +35,104 @@ # and display those directly. -import sys, re, htmlentitydefs +import sys, re, htmlentitydefs, getopt, StringIO, codecs, datetime + +# minimum line size, we add a zero-sized breakable space every +# LINESIZE characters +linesize = 20 +tabsize = 8 +show_CR = False +encoding = "utf-8" +lang = "en" + +desc = "File comparison" +dtnow = datetime.datetime.now() +modified_date = "%s+01:00"%dtnow.isoformat() + +html_hdr = """ + + + + + + HTML Diff{0} + + + + + + + + + +""" + +html_footer = """ +
+

Modified at {1}. HTML formatting created by diff2html.

+
+ +""" -html_hdr=""" +table_hdr = """ """ -html_footer=""" +table_footer = """
""" -DIFFON="\x01" -DIFFOFF="\x02" +DIFFON = "\x01" +DIFFOFF = "\x02" -buffer=[] -add_cpt, del_cpt = 0,0 -line1, line2 = 0,0 -hunk_off1, hunk_size1, hunk_off2, hunk_size2 = 0,0,0,0 +buf = [] +add_cpt, del_cpt = 0, 0 +line1, line2 = 0, 0 +hunk_off1, hunk_size1, hunk_off2, hunk_size2 = 0, 0, 0, 0 -# minimum line size, we add a zero-sized breakable space every -# LINESIZE characters -LINESIZE=20 -TAB=4 # Characters we're willing to word wrap on -WORDBREAK=" \t;.,/):" +WORDBREAK = " \t;.,/):" def sane(x): - r="" + r = "" for i in x: j = ord(i) - if i not in ['\t', '\n'] and ((j < 32) or (j >= 127)): - r=r+"." + if i not in ['\t', '\n'] and (j < 32): + r = r + "." else: - r=r+i + r = r + i return r def linediff(s, t): if len(s): - s=str(reduce(lambda x,y:x+y, [ sane(c) for c in s ])) + s = unicode(reduce(lambda x, y:x+y, [ sane(c) for c in s ])) if len(t): - t=str(reduce(lambda x,y:x+y, [ sane(c) for c in t ])) - - m,n = len(s), len(t) - d=[[(0,0) for i in range(n+1)] for i in range(m+1)] - x=[[(0,0) for i in range(n+1)] for i in range(m+1)] - - - d[0][0] = (0, (0,0)) + t = unicode(reduce(lambda x, y:x+y, [ sane(c) for c in t ])) + + m, n = len(s), len(t) + d = [[(0, 0) for i in range(n+1)] for i in range(m+1)] + + + d[0][0] = (0, (0, 0)) for i in range(m+1)[1:]: - d[i][0] = (i,(i-1,0)) + d[i][0] = (i,(i-1, 0)) for j in range(n+1)[1:]: - d[0][j] = (j,(0,j-1)) + d[0][j] = (j,(0, j-1)) for i in range(m+1)[1:]: for j in range(n+1)[1:]: @@ -102,34 +140,34 @@ def linediff(s, t): cost = 0 else: cost = 1 - d[i][j] = min((d[i-1][j][0] + 1, (i-1,j)), - (d[i][j-1][0] + 1, (i,j-1)), - (d[i-1][j-1][0] + cost, (i-1,j-1))) - - l=[] - coord = (m,n) - while coord != (0,0): + d[i][j] = min((d[i-1][j][0] + 1, (i-1, j)), + (d[i][j-1][0] + 1, (i, j-1)), + (d[i-1][j-1][0] + cost, (i-1, j-1))) + + l = [] + coord = (m, n) + while coord != (0, 0): l.insert(0, coord) - x,y = coord + x, y = coord coord = d[x][y][1] l1 = [] l2 = [] for coord in l: - cx,cy = coord + cx, cy = coord child_val = d[cx][cy][0] - + father_coord = d[cx][cy][1] - fx,fy = father_coord + fx, fy = father_coord father_val = d[fx][fy][0] diff = (cx-fx, cy-fy) - if diff == (0,1): + if diff == (0, 1): l1.append("") l2.append(DIFFON + t[fy] + DIFFOFF) - elif diff == (1,0): + elif diff == (1, 0): l1.append(DIFFON + s[fx] + DIFFOFF) l2.append("") elif child_val-father_val == 1: @@ -139,198 +177,296 @@ def linediff(s, t): l1.append(s[fx]) l2.append(t[fy]) - r1,r2 = (reduce(lambda x,y:x+y, l1), reduce(lambda x,y:x+y, l2)) - return r1,r2 + r1, r2 = (reduce(lambda x, y:x+y, l1), reduce(lambda x, y:x+y, l2)) + return r1, r2 def convert(s, linesize=0, ponct=0): - i=0 - t="" - l=[] + i = 0 + t = u"" for c in s: # used by diffs - if c==DIFFON: - t += '' - elif c==DIFFOFF: - t += "" + if c == DIFFON: + t += u'' + elif c == DIFFOFF: + t += u"" # special html chars elif htmlentitydefs.codepoint2name.has_key(ord(c)): - t += "&%s;"%(htmlentitydefs.codepoint2name[ord(c)]) + t += u"&%s;" % (htmlentitydefs.codepoint2name[ord(c)]) i += 1 # special highlighted chars - elif c=="\t" and ponct==1: - n = TAB-(i%TAB) - if n==0: - n=TAB - t += ('»'+' '*(n-1)) - elif c==" " and ponct==1: - t += '·' - elif c=="\n" and ponct==1: - 1 # Quietly drop it. - #t += '\' + elif c == "\t" and ponct == 1: + n = tabsize-(i%tabsize) + if n == 0: + n = tabsize + t += (u'»'+' '*(n-1)) + elif c == " " and ponct == 1: + t += u'·' + elif c == "\n" and ponct == 1: + if show_CR: + t += u'\' else: t += c i += 1 - if linesize and (WORDBREAK.count(c)==1): - t += '​' - i=0 - if linesize and i>linesize: - i=0 - t += "​" - + if linesize and (WORDBREAK.count(c) == 1): + t += u'​' + i = 0 + if linesize and i > linesize: + i = 0 + t += u"​" + return t -def add_comment(s): - sys.stdout.write('%s\n'%convert(s)) +def add_comment(s, output_file): + output_file.write(('%s\n'%convert(s)).encode(encoding)) + -def add_filename(f1, f2): - sys.stdout.write("%s"%convert(f1, linesize=LINESIZE)) - sys.stdout.write("%s\n"%convert(f2, linesize=LINESIZE)) +def add_filename(f1, f2, output_file): + output_file.write(("%s"%convert(f1, linesize=linesize)).encode(encoding)) + output_file.write(("%s\n"%convert(f2, linesize=linesize)).encode(encoding)) -def add_hunk(): - global hunk_off1 - global hunk_size1 - global hunk_off2 - global hunk_size2 - # Don't bother displaying, it's redundant with the line numbers. - #sys.stdout.write('Offset %d, %d lines modified'%(hunk_off1, hunk_size1)) - #sys.stdout.write('Offset %d, %d lines modified\n'%(hunk_off2, hunk_size2)) - # ⋮ - vertical ellipsis - sys.stdout.write('⋮⋮'); + +def add_hunk(output_file, show_hunk_infos): + if show_hunk_infos: + output_file.write('Offset %d, %d lines modified'%(hunk_off1, hunk_size1)) + output_file.write('Offset %d, %d lines modified\n'%(hunk_off2, hunk_size2)) + else: + # ⋮ - vertical ellipsis + output_file.write('⋮⋮') -def add_line(s1, s2): +def add_line(s1, s2, output_file): global line1 global line2 - if s1==None and s2==None: - type="unmodified" - elif s1==None or s1=="": - type="added" - elif s2==None or s1=="": - type="deleted" - elif s1==s2: - type="unmodified" + if s1 == None and s2 == None: + type_name = "unmodified" + elif s1 == None or s1 == "": + type_name = "added" + elif s2 == None or s1 == "": + type_name = "deleted" + elif s1 == s2: + type_name = "unmodified" else: - type="changed" - s1,s2 = linediff(s1, s2) - - sys.stdout.write(''%type) - if s1!=None and s1!="": - sys.stdout.write('%d '%line1) - sys.stdout.write('') - sys.stdout.write(convert(s1, linesize=LINESIZE, ponct=1)) - sys.stdout.write('') + type_name = "changed" + s1, s2 = linediff(s1, s2) + + output_file.write(('' % type_name).encode(encoding)) + if s1 != None and s1 != "": + output_file.write(('%d ' % line1).encode(encoding)) + output_file.write(''.encode(encoding)) + output_file.write(convert(s1, linesize=linesize, ponct=1).encode(encoding)) + output_file.write('') else: - s1="" - sys.stdout.write(' ') - - if s2!=None and s2!="": - sys.stdout.write('%d '%line2) - sys.stdout.write('') - sys.stdout.write(convert(s2, linesize=LINESIZE, ponct=1)) - sys.stdout.write('') + s1 = "" + output_file.write(' ') + + if s2 != None and s2 != "": + output_file.write(('%d '%line2).encode(encoding)) + output_file.write('') + output_file.write(convert(s2, linesize=linesize, ponct=1).encode(encoding)) + output_file.write('') else: - s2="" - sys.stdout.write('') + s2 = "" + output_file.write('') - sys.stdout.write('\n') + output_file.write('\n') - if s1!="": + if s1 != "": line1 += 1 - if s2!="": + if s2 != "": line2 += 1 -def empty_buffer(): - global buffer +def empty_buffer(output_file): + global buf global add_cpt global del_cpt if del_cpt == 0 or add_cpt == 0: - for l in buffer: - add_line(l[0], l[1]) + for l in buf: + add_line(l[0], l[1], output_file) elif del_cpt != 0 and add_cpt != 0: l0, l1 = [], [] - for l in buffer: + for l in buf: if l[0] != None: l0.append(l[0]) if l[1] != None: l1.append(l[1]) - max = (len(l0) > len(l1)) and len(l0) or len(l1) - for i in range(max): + max_len = (len(l0) > len(l1)) and len(l0) or len(l1) + for i in range(max_len): s0, s1 = "", "" - if i