fixed bytes to string issue and removed template file
This commit is contained in:
parent
4949162dc8
commit
d6b00ca790
3 changed files with 335 additions and 328 deletions
|
|
@ -2,7 +2,12 @@
|
||||||
|
|
||||||
A python script that takes two files and compares the differences between them (side-by-side) in an HTML format.
|
A python script that takes two files and compares the differences between them (side-by-side) in an HTML format.
|
||||||
|
|
||||||
###Usage
|
### Installation
|
||||||
|
```
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
```
|
```
|
||||||
diff2HtmlCompare.py [-h] [-v] file1 file2
|
diff2HtmlCompare.py [-h] [-v] file1 file2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
# MIT License
|
# MIT License
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016 Alex Goodman
|
# Copyright (c) 2016 Alex Goodman
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
# this software and associated documentation files (the "Software"), to deal in
|
# this software and associated documentation files (the "Software"), to deal in
|
||||||
# the Software without restriction, including without limitation the rights to
|
# the Software without restriction, including without limitation the rights to
|
||||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
# of the Software, and to permit persons to whom the Software is furnished to do
|
# of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
# so, subject to the following conditions:
|
# so, subject to the following conditions:
|
||||||
#
|
#
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
# copies or substantial portions of the Software.
|
# copies or substantial portions of the Software.
|
||||||
#
|
#
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
|
@ -31,300 +31,379 @@ from pygments.lexer import RegexLexer
|
||||||
from pygments.formatters import HtmlFormatter
|
from pygments.formatters import HtmlFormatter
|
||||||
from pygments.token import *
|
from pygments.token import *
|
||||||
|
|
||||||
|
HTML_TEMPLATE = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="no-js">
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
html_title: browser tab title
|
||||||
|
reset_css: relative path to reset css file
|
||||||
|
pygments_css: relative path to pygments css file
|
||||||
|
diff_css: relative path to diff layout css file
|
||||||
|
page_title: title shown at the top of the page. This should be the filename of the files being diff'd
|
||||||
|
original_code: full html contents of original file
|
||||||
|
modified_code: full html contents of modified file
|
||||||
|
jquery_js: path to jquery.min.js
|
||||||
|
diff_js: path to diff.js
|
||||||
|
-->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>
|
||||||
|
%(html_title)s
|
||||||
|
</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
<link rel="stylesheet" href="%(reset_css)s" type="text/css">
|
||||||
|
<link class="syntaxdef" rel="stylesheet" href="%(pygments_css)s" type="text/css">
|
||||||
|
<link rel="stylesheet" href="%(diff_css)s" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="" id="topbar">
|
||||||
|
<div id="filetitle">
|
||||||
|
<!--➜ -->%(page_title)s
|
||||||
|
</div>
|
||||||
|
<div class="switches">
|
||||||
|
<div class="switch">
|
||||||
|
<input id="showoriginal" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
||||||
|
<label for="showoriginal" data-on="✔ Original" data-off="Original"></label>
|
||||||
|
</div>
|
||||||
|
<div class="switch">
|
||||||
|
<input id="showmodified" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
||||||
|
<label for="showmodified" data-on="✔ Modified" data-off="Modified"></label>
|
||||||
|
</div>
|
||||||
|
<div class="switch">
|
||||||
|
<input id="highlight" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
||||||
|
<label for="highlight" data-on="✔ Highlight" data-off="Highlight"></label>
|
||||||
|
</div>
|
||||||
|
<div class="switch">
|
||||||
|
<input id="codeprintmargin" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
||||||
|
<label for="codeprintmargin" data-on="✔ Margin" data-off="Margin"></label>
|
||||||
|
</div>
|
||||||
|
<div class="switch">
|
||||||
|
<input id="dosyntaxhighlight" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
||||||
|
<label for="dosyntaxhighlight" data-on="✔ Syntax" data-off="Syntax"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="maincontainer" class="">
|
||||||
|
<div id="leftcode" class="left-inner-shadow codebox divider-outside-bottom">
|
||||||
|
<div class="codefiletab">
|
||||||
|
❬ Original
|
||||||
|
</div>
|
||||||
|
<div class="printmargin">
|
||||||
|
01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||||
|
</div>
|
||||||
|
%(original_code)s
|
||||||
|
</div>
|
||||||
|
<div id="rightcode" class="left-inner-shadow codebox divider-outside-bottom">
|
||||||
|
<div class="codefiletab">
|
||||||
|
❭ Modified
|
||||||
|
</div>
|
||||||
|
<div class="printmargin">
|
||||||
|
01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||||
|
</div>
|
||||||
|
%(modified_code)s
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="%(jquery_js)s" type="text/javascript"></script>
|
||||||
|
<script src="%(diff_js)s" type="text/javascript"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class DefaultLexer(RegexLexer):
|
class DefaultLexer(RegexLexer):
|
||||||
"""
|
"""
|
||||||
Simply lex each line as a token.
|
Simply lex each line as a token.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = 'Default'
|
name = 'Default'
|
||||||
aliases = ['default']
|
aliases = ['default']
|
||||||
filenames = ['*']
|
filenames = ['*']
|
||||||
|
|
||||||
tokens = {
|
tokens = {
|
||||||
'root': [
|
'root': [
|
||||||
(r'.*\n', Text),
|
(r'.*\n', Text),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class DiffHtmlFormatter(HtmlFormatter):
|
class DiffHtmlFormatter(HtmlFormatter):
|
||||||
"""
|
"""
|
||||||
Formats a single source file with pygments and adds diff highlights based on the
|
Formats a single source file with pygments and adds diff highlights based on the
|
||||||
diff details given.
|
diff details given.
|
||||||
"""
|
"""
|
||||||
isLeft = False
|
isLeft = False
|
||||||
diffs = None
|
diffs = None
|
||||||
|
|
||||||
def __init__(self, isLeft, diffs, *args, **kwargs):
|
def __init__(self, isLeft, diffs, *args, **kwargs):
|
||||||
self.isLeft = isLeft
|
self.isLeft = isLeft
|
||||||
self.diffs = diffs
|
self.diffs = diffs
|
||||||
super(DiffHtmlFormatter, self).__init__(*args, **kwargs)
|
super(DiffHtmlFormatter, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def wrap(self, source, outfile):
|
def wrap(self, source, outfile):
|
||||||
return self._wrap_code(source)
|
return self._wrap_code(source)
|
||||||
|
|
||||||
def getDiffLineNos(self):
|
def getDiffLineNos(self):
|
||||||
retlinenos = []
|
retlinenos = []
|
||||||
for idx, ((left_no, left_line),(right_no, right_line),change) in enumerate(self.diffs):
|
for idx, ((left_no, left_line), (right_no, right_line), change) in enumerate(self.diffs):
|
||||||
no = None
|
no = None
|
||||||
if self.isLeft:
|
|
||||||
if change:
|
|
||||||
if isinstance(left_no, int) and isinstance(right_no, int):
|
|
||||||
no = '<span class="lineno_q lineno_leftchange">' + str(left_no) + "</span>"
|
|
||||||
elif isinstance(left_no, int) and not isinstance(right_no, int):
|
|
||||||
no = '<span class="lineno_q lineno_leftdel">' + str(left_no) + "</span>"
|
|
||||||
elif not isinstance(left_no, int) and isinstance(right_no, int):
|
|
||||||
no = '<span class="lineno_q lineno_leftadd"> </span>'
|
|
||||||
else:
|
|
||||||
no = '<span class="lineno_q">' + str(left_no) + "</span>"
|
|
||||||
else:
|
|
||||||
if change:
|
|
||||||
if isinstance(left_no, int) and isinstance(right_no, int):
|
|
||||||
no = '<span class="lineno_q lineno_rightchange">' + str(right_no) + "</span>"
|
|
||||||
elif isinstance(left_no, int) and not isinstance(right_no, int):
|
|
||||||
no = '<span class="lineno_q lineno_rightdel"> </span>'
|
|
||||||
elif not isinstance(left_no, int) and isinstance(right_no, int):
|
|
||||||
no = '<span class="lineno_q lineno_rightadd">' + str(right_no) + "</span>"
|
|
||||||
else:
|
|
||||||
no = '<span class="lineno_q">' + str(right_no) + "</span>"
|
|
||||||
|
|
||||||
retlinenos.append(no)
|
|
||||||
|
|
||||||
return retlinenos
|
|
||||||
|
|
||||||
def _wrap_code(self, source):
|
|
||||||
|
|
||||||
source = list(source)
|
|
||||||
yield 0, '<pre>'
|
|
||||||
|
|
||||||
for idx, ((left_no, left_line),(right_no, right_line),change) in enumerate(self.diffs):
|
|
||||||
#print idx, ((left_no, left_line),(right_no, right_line),change)
|
|
||||||
try:
|
|
||||||
if self.isLeft:
|
if self.isLeft:
|
||||||
if change:
|
if change:
|
||||||
if isinstance(left_no, int) and isinstance(right_no, int) and left_no <= len(source):
|
if isinstance(left_no, int) and isinstance(right_no, int):
|
||||||
i,t = source[left_no-1]
|
no = '<span class="lineno_q lineno_leftchange">' + \
|
||||||
t = '<span class="left_diff_change">' + t + "</span>"
|
str(left_no) + "</span>"
|
||||||
elif isinstance(left_no, int) and not isinstance(right_no, int) and left_no <= len(source):
|
elif isinstance(left_no, int) and not isinstance(right_no, int):
|
||||||
i,t = source[left_no-1]
|
no = '<span class="lineno_q lineno_leftdel">' + \
|
||||||
t = '<span class="left_diff_del">' + t + "</span>"
|
str(left_no) + "</span>"
|
||||||
elif not isinstance(left_no, int) and isinstance(right_no, int):
|
elif not isinstance(left_no, int) and isinstance(right_no, int):
|
||||||
i,t = 1, left_line
|
no = '<span class="lineno_q lineno_leftadd"> </span>'
|
||||||
t = '<span class="left_diff_add">' + t + "</span>"
|
else:
|
||||||
else:
|
no = '<span class="lineno_q">' + str(left_no) + "</span>"
|
||||||
raise
|
|
||||||
else:
|
|
||||||
if left_no <= len(source):
|
|
||||||
i,t = source[left_no-1]
|
|
||||||
else:
|
|
||||||
i = 1
|
|
||||||
t = left_line
|
|
||||||
else:
|
else:
|
||||||
if change:
|
if change:
|
||||||
if isinstance(left_no, int) and isinstance(right_no, int) and right_no <= len(source):
|
if isinstance(left_no, int) and isinstance(right_no, int):
|
||||||
i,t = source[right_no-1]
|
no = '<span class="lineno_q lineno_rightchange">' + \
|
||||||
t = '<span class="right_diff_change">' + t + "</span>"
|
str(right_no) + "</span>"
|
||||||
elif isinstance(left_no, int) and not isinstance(right_no, int):
|
elif isinstance(left_no, int) and not isinstance(right_no, int):
|
||||||
i,t = 1, right_line
|
no = '<span class="lineno_q lineno_rightdel"> </span>'
|
||||||
t = '<span class="right_diff_del">' + t + "</span>"
|
elif not isinstance(left_no, int) and isinstance(right_no, int):
|
||||||
elif not isinstance(left_no, int) and isinstance(right_no, int) and right_no <= len(source):
|
no = '<span class="lineno_q lineno_rightadd">' + \
|
||||||
i,t = source[right_no-1]
|
str(right_no) + "</span>"
|
||||||
t = '<span class="right_diff_add">' + t + "</span>"
|
else:
|
||||||
else:
|
no = '<span class="lineno_q">' + str(right_no) + "</span>"
|
||||||
raise
|
|
||||||
else:
|
|
||||||
if right_no <= len(source):
|
|
||||||
i,t = source[right_no-1]
|
|
||||||
else:
|
|
||||||
i = 1
|
|
||||||
t = right_line
|
|
||||||
yield i, t
|
|
||||||
except:
|
|
||||||
#print "WARNING! failed to enumerate diffs fully!"
|
|
||||||
pass # this is expected sometimes
|
|
||||||
yield 0, '\n</pre>'
|
|
||||||
|
|
||||||
|
retlinenos.append(no)
|
||||||
|
|
||||||
def _wrap_tablelinenos(self, inner):
|
return retlinenos
|
||||||
dummyoutfile = io.StringIO()
|
|
||||||
lncount = 0
|
|
||||||
for t, line in inner:
|
|
||||||
if t:
|
|
||||||
lncount += 1
|
|
||||||
dummyoutfile.write(line)
|
|
||||||
|
|
||||||
fl = self.linenostart
|
def _wrap_code(self, source):
|
||||||
mw = len(str(lncount + fl - 1))
|
|
||||||
sp = self.linenospecial
|
|
||||||
st = self.linenostep
|
|
||||||
la = self.lineanchors
|
|
||||||
aln = self.anchorlinenos
|
|
||||||
nocls = self.noclasses
|
|
||||||
|
|
||||||
lines = []
|
source = list(source)
|
||||||
for i in self.getDiffLineNos():
|
yield 0, '<pre>'
|
||||||
lines.append('%s' % (i,))
|
|
||||||
|
|
||||||
ls = ''.join(lines)
|
for idx, ((left_no, left_line), (right_no, right_line), change) in enumerate(self.diffs):
|
||||||
|
# print idx, ((left_no, left_line),(right_no, right_line),change)
|
||||||
|
try:
|
||||||
|
if self.isLeft:
|
||||||
|
if change:
|
||||||
|
if isinstance(left_no, int) and isinstance(right_no, int) and left_no <= len(source):
|
||||||
|
i, t = source[left_no - 1]
|
||||||
|
t = '<span class="left_diff_change">' + t + "</span>"
|
||||||
|
elif isinstance(left_no, int) and not isinstance(right_no, int) and left_no <= len(source):
|
||||||
|
i, t = source[left_no - 1]
|
||||||
|
t = '<span class="left_diff_del">' + t + "</span>"
|
||||||
|
elif not isinstance(left_no, int) and isinstance(right_no, int):
|
||||||
|
i, t = 1, left_line
|
||||||
|
t = '<span class="left_diff_add">' + t + "</span>"
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
if left_no <= len(source):
|
||||||
|
i, t = source[left_no - 1]
|
||||||
|
else:
|
||||||
|
i = 1
|
||||||
|
t = left_line
|
||||||
|
else:
|
||||||
|
if change:
|
||||||
|
if isinstance(left_no, int) and isinstance(right_no, int) and right_no <= len(source):
|
||||||
|
i, t = source[right_no - 1]
|
||||||
|
t = '<span class="right_diff_change">' + t + "</span>"
|
||||||
|
elif isinstance(left_no, int) and not isinstance(right_no, int):
|
||||||
|
i, t = 1, right_line
|
||||||
|
t = '<span class="right_diff_del">' + t + "</span>"
|
||||||
|
elif not isinstance(left_no, int) and isinstance(right_no, int) and right_no <= len(source):
|
||||||
|
i, t = source[right_no - 1]
|
||||||
|
t = '<span class="right_diff_add">' + t + "</span>"
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
if right_no <= len(source):
|
||||||
|
i, t = source[right_no - 1]
|
||||||
|
else:
|
||||||
|
i = 1
|
||||||
|
t = right_line
|
||||||
|
yield i, t
|
||||||
|
except:
|
||||||
|
# print "WARNING! failed to enumerate diffs fully!"
|
||||||
|
pass # this is expected sometimes
|
||||||
|
yield 0, '\n</pre>'
|
||||||
|
|
||||||
# in case you wonder about the seemingly redundant <div> here: since the
|
def _wrap_tablelinenos(self, inner):
|
||||||
# content in the other cell also is wrapped in a div, some browsers in
|
dummyoutfile = io.StringIO()
|
||||||
# some configurations seem to mess up the formatting...
|
lncount = 0
|
||||||
if nocls:
|
for t, line in inner:
|
||||||
yield 0, ('<table class="%stable">' % self.cssclass +
|
if t:
|
||||||
'<tr><td><div class="linenodiv" '
|
lncount += 1
|
||||||
'style="background-color: #f0f0f0; padding-right: 10px">'
|
dummyoutfile.write(line)
|
||||||
'<pre style="line-height: 125%">' +
|
|
||||||
ls + '</pre></div></td><td class="code">')
|
|
||||||
else:
|
|
||||||
yield 0, ('<table class="%stable">' % self.cssclass +
|
|
||||||
'<tr><td class="linenos"><div class="linenodiv"><pre>' +
|
|
||||||
ls + '</pre></div></td><td class="code">')
|
|
||||||
yield 0, dummyoutfile.getvalue()
|
|
||||||
yield 0, '</td></tr></table>'
|
|
||||||
|
|
||||||
|
fl = self.linenostart
|
||||||
|
mw = len(str(lncount + fl - 1))
|
||||||
|
sp = self.linenospecial
|
||||||
|
st = self.linenostep
|
||||||
|
la = self.lineanchors
|
||||||
|
aln = self.anchorlinenos
|
||||||
|
nocls = self.noclasses
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
for i in self.getDiffLineNos():
|
||||||
|
lines.append('%s' % (i,))
|
||||||
|
|
||||||
|
ls = ''.join(lines)
|
||||||
|
|
||||||
|
# in case you wonder about the seemingly redundant <div> here: since the
|
||||||
|
# content in the other cell also is wrapped in a div, some browsers in
|
||||||
|
# some configurations seem to mess up the formatting...
|
||||||
|
if nocls:
|
||||||
|
yield 0, ('<table class="%stable">' % self.cssclass +
|
||||||
|
'<tr><td><div class="linenodiv" '
|
||||||
|
'style="background-color: #f0f0f0; padding-right: 10px">'
|
||||||
|
'<pre style="line-height: 125%">' +
|
||||||
|
ls + '</pre></div></td><td class="code">')
|
||||||
|
else:
|
||||||
|
yield 0, ('<table class="%stable">' % self.cssclass +
|
||||||
|
'<tr><td class="linenos"><div class="linenodiv"><pre>' +
|
||||||
|
ls + '</pre></div></td><td class="code">')
|
||||||
|
yield 0, dummyoutfile.getvalue()
|
||||||
|
yield 0, '</td></tr></table>'
|
||||||
|
|
||||||
|
|
||||||
class CodeDiff(object):
|
class CodeDiff(object):
|
||||||
"""
|
"""
|
||||||
Manages a pair of source files and generates a single html diff page comparing
|
Manages a pair of source files and generates a single html diff page comparing
|
||||||
the contents.
|
the contents.
|
||||||
"""
|
"""
|
||||||
pygmentsStyleOpt = "vs"
|
pygmentsStyleOpt = "vs"
|
||||||
pygmentsCssFile="./deps/codeformats/%s.css" % pygmentsStyleOpt
|
pygmentsCssFile = "./deps/codeformats/%s.css" % pygmentsStyleOpt
|
||||||
diffCssFile="./deps/diff.css"
|
diffCssFile = "./deps/diff.css"
|
||||||
diffJsFile="./deps/diff.js"
|
diffJsFile = "./deps/diff.js"
|
||||||
resetCssFile="./deps/reset.css"
|
resetCssFile = "./deps/reset.css"
|
||||||
jqueryJsFile="./deps/jquery.min.js"
|
jqueryJsFile = "./deps/jquery.min.js"
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, fromfile, tofile, fromtxt=None, totxt=None, name=None):
|
def __init__(self, fromfile, tofile, fromtxt=None, totxt=None, name=None):
|
||||||
|
|
||||||
self.filename = name
|
|
||||||
self.fromfile = fromfile
|
|
||||||
if fromtxt == None:
|
|
||||||
try:
|
|
||||||
with open(fromfile) as f:
|
|
||||||
self.fromlines = f.readlines()
|
|
||||||
except Exception as e:
|
|
||||||
print("Problem reading file %s" % fromfile)
|
|
||||||
print(e)
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
self.fromlines = [n + "\n" for n in fromtxt.split("\n")]
|
|
||||||
self.leftcode = "".join(self.fromlines)
|
|
||||||
|
|
||||||
self.tofile = tofile
|
|
||||||
if totxt == None:
|
|
||||||
try:
|
|
||||||
with open(tofile) as f:
|
|
||||||
self.tolines = f.readlines()
|
|
||||||
except Exception as e:
|
|
||||||
print("Problem reading file %s" % tofile)
|
|
||||||
print(e)
|
|
||||||
sys.exit(1)
|
|
||||||
else:
|
|
||||||
self.tolines = [n + "\n" for n in totxt.split("\n")]
|
|
||||||
self.rightcode = "".join(self.tolines)
|
|
||||||
|
|
||||||
|
self.filename = name
|
||||||
|
self.fromfile = fromfile
|
||||||
|
if fromtxt == None:
|
||||||
|
try:
|
||||||
|
with open(fromfile) as f:
|
||||||
|
self.fromlines = f.readlines()
|
||||||
|
except Exception as e:
|
||||||
|
print("Problem reading file %s" % fromfile)
|
||||||
|
print(e)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
self.fromlines = [n + "\n" for n in fromtxt.split("\n")]
|
||||||
|
self.leftcode = "".join(self.fromlines)
|
||||||
|
|
||||||
def getDiffDetails(self, fromdesc='', todesc='', context=False, numlines=5, tabSize=8):
|
self.tofile = tofile
|
||||||
|
if totxt == None:
|
||||||
|
try:
|
||||||
|
with open(tofile) as f:
|
||||||
|
self.tolines = f.readlines()
|
||||||
|
except Exception as e:
|
||||||
|
print("Problem reading file %s" % tofile)
|
||||||
|
print(e)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
self.tolines = [n + "\n" for n in totxt.split("\n")]
|
||||||
|
self.rightcode = "".join(self.tolines)
|
||||||
|
|
||||||
# change tabs to spaces before it gets more difficult after we insert
|
def getDiffDetails(self, fromdesc='', todesc='', context=False, numlines=5, tabSize=8):
|
||||||
# markkup
|
|
||||||
def expand_tabs(line):
|
|
||||||
# hide real spaces
|
|
||||||
line = line.replace(' ','\0')
|
|
||||||
# expand tabs into spaces
|
|
||||||
line = line.expandtabs(tabSize)
|
|
||||||
# replace spaces from expanded tabs back into tab characters
|
|
||||||
# (we'll replace them with markup after we do differencing)
|
|
||||||
line = line.replace(' ','\t')
|
|
||||||
return line.replace('\0',' ').rstrip('\n')
|
|
||||||
|
|
||||||
self.fromlines = [expand_tabs(line) for line in self.fromlines]
|
# change tabs to spaces before it gets more difficult after we insert
|
||||||
self.tolines = [expand_tabs(line) for line in self.tolines]
|
# markkup
|
||||||
|
def expand_tabs(line):
|
||||||
|
# hide real spaces
|
||||||
|
line = line.replace(' ', '\0')
|
||||||
|
# expand tabs into spaces
|
||||||
|
line = line.expandtabs(tabSize)
|
||||||
|
# replace spaces from expanded tabs back into tab characters
|
||||||
|
# (we'll replace them with markup after we do differencing)
|
||||||
|
line = line.replace(' ', '\t')
|
||||||
|
return line.replace('\0', ' ').rstrip('\n')
|
||||||
|
|
||||||
# create diffs iterator which generates side by side from/to data
|
self.fromlines = [expand_tabs(line) for line in self.fromlines]
|
||||||
if context:
|
self.tolines = [expand_tabs(line) for line in self.tolines]
|
||||||
context_lines = numlines
|
|
||||||
else:
|
|
||||||
context_lines = None
|
|
||||||
|
|
||||||
diffs = difflib._mdiff(self.fromlines, self.tolines, context_lines, linejunk=None, charjunk=difflib.IS_CHARACTER_JUNK)
|
# create diffs iterator which generates side by side from/to data
|
||||||
return list(diffs)
|
if context:
|
||||||
|
context_lines = numlines
|
||||||
|
else:
|
||||||
|
context_lines = None
|
||||||
|
|
||||||
|
diffs = difflib._mdiff(self.fromlines, self.tolines, context_lines,
|
||||||
|
linejunk=None, charjunk=difflib.IS_CHARACTER_JUNK)
|
||||||
|
return list(diffs)
|
||||||
|
|
||||||
def format(self, verbose=False):
|
def format(self, verbose=False):
|
||||||
self.diffs = self.getDiffDetails(self.fromfile, self.tofile)
|
self.diffs = self.getDiffDetails(self.fromfile, self.tofile)
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
for diff in self.diffs:
|
for diff in self.diffs:
|
||||||
print("%-6s %-80s %-80s" % ( diff[2], diff[0], diff[1] ))
|
print("%-6s %-80s %-80s" % (diff[2], diff[0], diff[1]))
|
||||||
|
|
||||||
fields = ( (self.leftcode, True, self.fromfile) , (self.rightcode, False, self.tofile) )
|
fields = ((self.leftcode, True, self.fromfile),
|
||||||
|
(self.rightcode, False, self.tofile))
|
||||||
|
|
||||||
codeContents = []
|
codeContents = []
|
||||||
for (code, isLeft, filename) in fields:
|
for (code, isLeft, filename) in fields:
|
||||||
|
|
||||||
inst = DiffHtmlFormatter(isLeft,
|
inst = DiffHtmlFormatter(isLeft,
|
||||||
self.diffs,
|
self.diffs,
|
||||||
nobackground=False,
|
nobackground=False,
|
||||||
linenos=True,
|
linenos=True,
|
||||||
style=self.pygmentsStyleOpt)
|
style=self.pygmentsStyleOpt)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.lexer = guess_lexer_for_filename(self.filename, code)
|
self.lexer = guess_lexer_for_filename(self.filename, code)
|
||||||
|
|
||||||
except pygments.util.ClassNotFound:
|
|
||||||
if verbose:
|
|
||||||
print("No Lexer Found! Using default...")
|
|
||||||
|
|
||||||
self.lexer = DefaultLexer()
|
except pygments.util.ClassNotFound:
|
||||||
|
if verbose:
|
||||||
formatted = pygments.highlight(code, self.lexer, inst)
|
print("No Lexer Found! Using default...")
|
||||||
|
|
||||||
codeContents.append(formatted)
|
|
||||||
|
|
||||||
diffTemplate = open("./templates/diff_template.html",'r').read()
|
self.lexer = DefaultLexer()
|
||||||
|
|
||||||
answers = {
|
formatted = pygments.highlight(code, self.lexer, inst)
|
||||||
"html_title": self.filename,
|
|
||||||
"reset_css": self.resetCssFile,
|
|
||||||
"pygments_css": self.pygmentsCssFile,
|
|
||||||
"diff_css": self.diffCssFile,
|
|
||||||
"page_title": self.filename,
|
|
||||||
"original_code": codeContents[0],
|
|
||||||
"modified_code": codeContents[1],
|
|
||||||
"jquery_js": self.jqueryJsFile,
|
|
||||||
"diff_js": self.diffJsFile,
|
|
||||||
}
|
|
||||||
|
|
||||||
self.htmlContents = diffTemplate % answers
|
codeContents.append(formatted)
|
||||||
|
|
||||||
|
|
||||||
def write(self, path="index.html"):
|
answers = {
|
||||||
fh = open(path,'w')
|
"html_title": self.filename,
|
||||||
fh.write(self.htmlContents.encode('utf8'))
|
"reset_css": self.resetCssFile,
|
||||||
fh.close()
|
"pygments_css": self.pygmentsCssFile,
|
||||||
|
"diff_css": self.diffCssFile,
|
||||||
|
"page_title": self.filename,
|
||||||
|
"original_code": codeContents[0],
|
||||||
|
"modified_code": codeContents[1],
|
||||||
|
"jquery_js": self.jqueryJsFile,
|
||||||
|
"diff_js": self.diffJsFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.htmlContents = HTML_TEMPLATE % answers
|
||||||
|
|
||||||
|
def write(self, path="index.html"):
|
||||||
|
fh = open(path, 'w')
|
||||||
|
fh.write(self.htmlContents)
|
||||||
|
fh.close()
|
||||||
|
|
||||||
|
|
||||||
def main(fromfile, tofile, verbose=False):
|
def main(fromfile, tofile, verbose=False):
|
||||||
codeDiff = CodeDiff(fromfile, tofile, name=tofile)
|
codeDiff = CodeDiff(fromfile, tofile, name=tofile)
|
||||||
codeDiff.format(verbose)
|
codeDiff.format(verbose)
|
||||||
codeDiff.write()
|
codeDiff.write()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
description = """Given two source files this application\
|
description = """Given two source files this application\
|
||||||
creates an html page which highlights the differences between the two. """
|
creates an html page which highlights the differences between the two. """
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description=description)
|
parser = argparse.ArgumentParser(description=description)
|
||||||
parser.add_argument('-v', action='store_true', help='show verbose output.')
|
parser.add_argument('-v', action='store_true', help='show verbose output.')
|
||||||
parser.add_argument('file1', help='source file to compare ("before" file).')
|
parser.add_argument(
|
||||||
parser.add_argument('file2', help='source file to compare ("after" file).')
|
'file1', help='source file to compare ("before" file).')
|
||||||
|
parser.add_argument('file2', help='source file to compare ("after" file).')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
main(args.file1, args.file2, args.v)
|
main(args.file1, args.file2, args.v)
|
||||||
|
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html class="no-js">
|
|
||||||
<head>
|
|
||||||
<!--
|
|
||||||
html_title: browser tab title
|
|
||||||
reset_css: relative path to reset css file
|
|
||||||
pygments_css: relative path to pygments css file
|
|
||||||
diff_css: relative path to diff layout css file
|
|
||||||
page_title: title shown at the top of the page. This should be the filename of the files being diff'd
|
|
||||||
original_code: full html contents of original file
|
|
||||||
modified_code: full html contents of modified file
|
|
||||||
jquery_js: path to jquery.min.js
|
|
||||||
diff_js: path to diff.js
|
|
||||||
-->
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>
|
|
||||||
%(html_title)s
|
|
||||||
</title>
|
|
||||||
<meta name="description" content="">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
<link rel="stylesheet" href="%(reset_css)s" type="text/css">
|
|
||||||
<link class="syntaxdef" rel="stylesheet" href="%(pygments_css)s" type="text/css">
|
|
||||||
<link rel="stylesheet" href="%(diff_css)s" type="text/css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="" id="topbar">
|
|
||||||
<div id="filetitle">
|
|
||||||
<!--➜ -->%(page_title)s
|
|
||||||
</div>
|
|
||||||
<div class="switches">
|
|
||||||
<div class="switch">
|
|
||||||
<input id="showoriginal" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
|
||||||
<label for="showoriginal" data-on="✔ Original" data-off="Original"></label>
|
|
||||||
</div>
|
|
||||||
<div class="switch">
|
|
||||||
<input id="showmodified" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
|
||||||
<label for="showmodified" data-on="✔ Modified" data-off="Modified"></label>
|
|
||||||
</div>
|
|
||||||
<div class="switch">
|
|
||||||
<input id="highlight" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
|
||||||
<label for="highlight" data-on="✔ Highlight" data-off="Highlight"></label>
|
|
||||||
</div>
|
|
||||||
<div class="switch">
|
|
||||||
<input id="codeprintmargin" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
|
||||||
<label for="codeprintmargin" data-on="✔ Margin" data-off="Margin"></label>
|
|
||||||
</div>
|
|
||||||
<div class="switch">
|
|
||||||
<input id="dosyntaxhighlight" class="toggle toggle-yes-no menuoption" type="checkbox" checked>
|
|
||||||
<label for="dosyntaxhighlight" data-on="✔ Syntax" data-off="Syntax"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="maincontainer" class="">
|
|
||||||
<div id="leftcode" class="left-inner-shadow codebox divider-outside-bottom">
|
|
||||||
<div class="codefiletab">
|
|
||||||
❬ Original
|
|
||||||
</div>
|
|
||||||
<div class="printmargin">
|
|
||||||
01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
||||||
</div>
|
|
||||||
%(original_code)s
|
|
||||||
</div>
|
|
||||||
<div id="rightcode" class="left-inner-shadow codebox divider-outside-bottom">
|
|
||||||
<div class="codefiletab">
|
|
||||||
❭ Modified
|
|
||||||
</div>
|
|
||||||
<div class="printmargin">
|
|
||||||
01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
||||||
</div>
|
|
||||||
%(modified_code)s
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script src="%(jquery_js)s" type="text/javascript"></script>
|
|
||||||
<script src="%(diff_js)s" type="text/javascript"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue