Commit 758dd001 authored by scoder's avatar scoder

Merge pull request #257 from Carreau/clean-annotate

Clean html-annotate generation
parents ca0f1e18 85b455b9
......@@ -10,13 +10,9 @@ import Version
from Code import CCodeWriter
from Cython import Utils
# need one-characters subsitutions (for now) so offsets aren't off
special_chars = [
(u'&', u'\xF2', u'&'),
(u'<', u'\xF0', u'&lt;'),
(u'>', u'\xF1', u'&gt;'),
]
from contextlib import closing
# need one-characters subsitutions (for now) so offsets aren't off
class AnnotationCCodeWriter(CCodeWriter):
......@@ -54,97 +50,123 @@ class AnnotationCCodeWriter(CCodeWriter):
def annotate(self, pos, item):
self.annotations.append((pos, item))
def save_annotation(self, source_filename, target_filename):
self.mark_pos(None)
f = Utils.open_source_file(source_filename)
lines = f.readlines()
for k, line in enumerate(lines):
for c, cc, html in special_chars:
line = line.replace(c, cc)
lines[k] = line
f.close()
all = []
if False:
for pos, item in self.annotations:
if pos[0].filename == source_filename:
start = item.start()
size, end = item.end()
if size:
all.append((pos, start))
all.append(((source_filename, pos[1], pos[2]+size), end))
else:
all.append((pos, start+end))
all.sort(reverse=True)
for pos, item in all:
_, line_no, col = pos
line_no -= 1
col += 1
line = lines[line_no]
lines[line_no] = line[:col] + item + line[col:]
def _css(self):
"""css template will later allow to choose a colormap"""
css = self._css_template
for i in range(255):
color = u"FFFF%02x" % int(255/(1+i/10.0))
css = css+'\n.cython.score-%s {background-color: #%s;}' % (str(i),color)
return css
_js = """
function toggleDiv(id) {
theDiv = id.nextElementSibling
if (theDiv.style.display != 'block') theDiv.style.display = 'block';
else theDiv.style.display = 'none';
}
"""
_css_template = """
body { font-family: courier; font-size: 12; }
.cython.code { font-size: 9; color: #444444; display: none; margin-left: 20px; }
.cython.py_c_api { color: red; }
.cython.py_macro_api { color: #FF7000; }
.cython.pyx_c_api { color: #FF3000; }
.cython.pyx_macro_api { color: #FF7000; }
.cython.refnanny { color: #FFA000; }
.cython.error_goto { color: #FFA000; }
.cython.tag { }
.cython.coerce { color: #008000; border: 1px dotted #008000 }
.cython.py_attr { color: #FF0000; font-weight: bold; }
.cython.c_attr { color: #0000FF; }
.cython.py_call { color: #FF0000; font-weight: bold; }
.cython.c_call { color: #0000FF; }
.cython.line { margin: 0em }
"""
def save_annotation(self, source_filename, target_filename):
with closing(Utils.open_source_file(source_filename)) as f:
lines = f.readlines()
code_source_file = self.code.get(source_filename, {})
c_file = Utils.decode_filename(os.path.basename(target_filename))
html_filename = os.path.splitext(target_filename)[0] + ".html"
f = codecs.open(html_filename, "w", encoding="UTF-8")
f.write(u'<!DOCTYPE html>\n')
f.write(u'<!-- Generated by Cython %s -->\n' % Version.watermark)
f.write(u'<html>\n')
f.write(u"""
with codecs.open(html_filename, "w", encoding="UTF-8") as out_buffer:
out_buffer.write(self._save_annotation(lines, code_source_file , c_file))
def _save_annotation_header(self, c_file):
outlist = []
outlist.append(u'<!DOCTYPE html>\n')
outlist.append(u'<!-- Generated by Cython %s -->\n' % Version.watermark)
outlist.append(u'<html>\n')
outlist.append(u"""
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
<style type="text/css">
{css}
</style>
<script>
{js}
</script>
</head>
""".format(css=self._css(), js=self._js))
outlist.append(u'<body>\n')
outlist.append(u'<p>Generated by Cython %s</p>\n' % Version.watermark)
if c_file :
outlist.append(u'<p>Raw output: <a href="%s">%s</a></p>\n' % (c_file, c_file))
return outlist
body { font-family: courier; font-size: 12; }
def _save_annotation_footer(self):
return (u'</body></html>\n',)
.code { font-size: 9; color: #444444; display: none; margin-left: 20px; }
.py_c_api { color: red; }
.py_macro_api { color: #FF7000; }
.pyx_c_api { color: #FF3000; }
.pyx_macro_api { color: #FF7000; }
.refnanny { color: #FFA000; }
.error_goto { color: #FFA000; }
.tag { }
.coerce { color: #008000; border: 1px dotted #008000 }
def _save_annotation(self, lines, code_source_file , c_file=None):
"""
lines : original cython source code split by lines
code_source_file : generated c code keyed by line number in original file
target filename : name of the file in which to store the generated html
c_file : filename in which the c_code has been written
.py_attr { color: #FF0000; font-weight: bold; }
.c_attr { color: #0000FF; }
"""
.py_call { color: #FF0000; font-weight: bold; }
.c_call { color: #0000FF; }
outlist = []
outlist.extend(self._save_annotation_header(c_file))
.line { margin: 0em }
outlist.extend(self._save_annotation_body(lines, code_source_file , c_file=None))
outlist.extend(self._save_annotation_footer())
return ''.join(outlist)
</style>
<script>
function toggleDiv(id) {
theDiv = document.getElementById(id);
if (theDiv.style.display != 'block') theDiv.style.display = 'block';
else theDiv.style.display = 'none';
}
</script>
</head>
""")
f.write(u'<body>\n')
f.write(u'<p>Generated by Cython %s\n' % Version.watermark)
c_file = Utils.decode_filename(os.path.basename(target_filename))
f.write(u'<p>Raw output: <a href="%s">%s</a>\n' % (c_file, c_file))
def _save_annotation_body(self, lines, code_source_file , c_file=None):
outlist=[]
pos_comment_marker = u'/* \N{HORIZONTAL ELLIPSIS} */\n'
zero_calls = dict((name, 0) for name in
'refnanny py_macro_api py_c_api pyx_macro_api pyx_c_api error_goto'.split())
self.mark_pos(None)
def annotate(match):
group_name = match.lastgroup
calls[group_name] += 1
return ur"<span class='%s'>%s</span>" % (
return ur"<span class='cython %s'>%s</span>" % (
group_name, match.group(group_name))
pos_comment_marker = u'/* \N{HORIZONTAL ELLIPSIS} */\n'
k = 0
code_source_file = self.code.get(source_filename, {})
for line in lines:
k += 1
for k, line in enumerate(lines):
line = html_escape(line)
try:
code = code_source_file[k]
except KeyError:
......@@ -159,19 +181,15 @@ function toggleDiv(id) {
code = _parse_code(annotate, code)
score = (5 * calls['py_c_api'] + 2 * calls['pyx_c_api'] +
calls['py_macro_api'] + calls['pyx_macro_api'])
color = u"FFFF%02x" % int(255/(1+score/10.0))
f.write(u"<pre class='line' style='background-color: #%s' onclick='toggleDiv(\"line%s\")'>" % (color, k))
f.write(u" %d: " % k)
for c, cc, html in special_chars:
line = line.replace(cc, html)
f.write(line.rstrip())
outlist.append(u"<pre class='cython line score-%s' onclick='toggleDiv(this)'>" % (score))
f.write(u'</pre>\n')
f.write(u"<pre id='line%s' class='code' style='background-color: #%s'>%s</pre>" % (k, color, code))
f.write(u'</body></html>\n')
f.close()
outlist.append(u" %d: " % k)
outlist.append(line.rstrip())
outlist.append(u'</pre>\n')
outlist.append(u"<pre class='cython code score-%s' >%s</pre>" % (score, code))
return outlist
_parse_code = re.compile(
ur'(?P<refnanny>__Pyx_X?(?:GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)|'
......@@ -201,7 +219,7 @@ class AnnotationItem(object):
self.size = size
def start(self):
return u"<span class='tag %s' title='%s'>%s" % (self.style, self.text, self.tag)
return u"<span class='cython tag %s' title='%s'>%s" % (self.style, self.text, self.tag)
def end(self):
return self.size, u"</span>"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment