X-Git-Url: http://git.droids-corp.org/?p=diff2html.git;a=blobdiff_plain;f=diff2html.py;h=337667faadfec6247fb4e14b4736cc3867e8b73a;hp=59d445dbf9cdf9dfd655a6bacf881feafd56c7bf;hb=dd0649dbd5ba5463535a8a2cb4c2335a78e4fec6;hpb=715a85a7ac2a121d30b421b128cb96533c3001b2 diff --git a/diff2html.py b/diff2html.py index 59d445d..337667f 100644 --- a/diff2html.py +++ b/diff2html.py @@ -18,23 +18,13 @@ # 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 # # 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 +33,87 @@ # and display those directly. -import sys, re, htmlentitydefs +import sys, re, htmlentitydefs, getopt, StringIO + +# minimum line size, we add a zero-sized breakable space every +# LINESIZE characters +linesize = 20 +tabsize = 8 +show_CR = False + + +html_hdr = """ + + + HTML Diff + + + +""" + +html_footer = """ + +""" -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+"." + 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 = str(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 = 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)) 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 +121,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 +158,275 @@ 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 = "" for c in s: # used by diffs - if c==DIFFON: + if c == DIFFON: t += '' - elif c==DIFFOFF: + elif c == DIFFOFF: t += "" # special html chars elif htmlentitydefs.codepoint2name.has_key(ord(c)): - t += "&%s;"%(htmlentitydefs.codepoint2name[ord(c)]) + t += "&%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 + elif c == "\t" and ponct == 1: + n = tabsize-(i%tabsize) + if n == 0: + n = tabsize t += ('»'+' '*(n-1)) - elif c==" " and ponct==1: + elif c == " " and ponct == 1: t += '·' - elif c=="\n" and ponct==1: - 1 # Quietly drop it. - #t += '\' + elif c == "\n" and ponct == 1: + if show_CR: + t += '\' else: t += c i += 1 - if linesize and (WORDBREAK.count(c)==1): + if linesize and (WORDBREAK.count(c) == 1): t += '​' - i=0 - if linesize and i>linesize: - i=0 + i = 0 + if linesize and i > linesize: + i = 0 t += "​" - + 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)) -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)) + output_file.write("%s\n"%convert(f2, linesize=linesize)) -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) + if s1 != None and s1 != "": + output_file.write('%d ' % line1) + output_file.write('') + output_file.write(convert(s1, linesize=linesize, ponct=1)) + 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) + output_file.write('') + output_file.write(convert(s2, linesize=linesize, ponct=1)) + 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