Cython has moved to github.
cython-devel
view Cython/Compiler/Annotate.py @ 1293:e333af7a02b5
fix Cython code context comments in C code when annotation is enables
| author | Stefan Behnel <scoder@users.berlios.de> |
|---|---|
| date | Sat Nov 01 06:01:48 2008 +0100 (3 years ago) |
| parents | a09347d7b470 |
| children | a89b05b78236 |
line source
1 # Note: Work in progress
3 import os
4 import re
5 import time
6 import codecs
7 from StringIO import StringIO
9 import Version
10 from Code import CCodeWriter
11 from Cython import Utils
13 # need one-characters subsitutions (for now) so offsets aren't off
14 special_chars = [(u'<', u'\xF0', u'<'),
15 (u'>', u'\xF1', u'>'),
16 (u'&', u'\xF2', u'&')]
18 class AnnotationCCodeWriter(CCodeWriter):
20 def __init__(self, create_from=None, buffer=None, copy_formatting=True):
21 CCodeWriter.__init__(self, create_from, buffer, copy_formatting=True)
22 if create_from is None:
23 self.annotation_buffer = StringIO()
24 self.annotations = []
25 self.last_pos = None
26 self.code = {}
27 else:
28 # When creating an insertion point, keep references to the same database
29 self.annotation_buffer = create_from.annotation_buffer
30 self.annotations = create_from.annotations
31 self.code = create_from.code
32 self.last_pos = create_from.last_pos
34 def create_new(self, create_from, buffer, copy_formatting):
35 return AnnotationCCodeWriter(create_from, buffer, copy_formatting)
37 def write(self, s):
38 CCodeWriter.write(self, s)
39 self.annotation_buffer.write(s)
41 def mark_pos(self, pos):
42 if pos is not None:
43 CCodeWriter.mark_pos(self, pos)
44 if self.last_pos:
45 code = self.code.get(self.last_pos[1], "")
46 self.code[self.last_pos[1]] = code + self.annotation_buffer.getvalue()
47 self.annotation_buffer = StringIO()
48 self.last_pos = pos
50 def annotate(self, pos, item):
51 self.annotations.append((pos, item))
53 def save_annotation(self, source_filename, target_filename):
54 self.mark_pos(None)
55 f = Utils.open_source_file(source_filename)
56 lines = f.readlines()
57 for k in range(len(lines)):
58 line = lines[k]
59 for c, cc, html in special_chars:
60 line = line.replace(c, cc)
61 lines[k] = line
62 f.close()
63 all = []
64 for pos, item in self.annotations:
65 if pos[0] == source_filename:
66 start = item.start()
67 size, end = item.end()
68 if size:
69 all.append((pos, start))
70 all.append(((source_filename, pos[1], pos[2]+size), end))
71 else:
72 all.append((pos, start+end))
74 all.sort()
75 all.reverse()
76 for pos, item in all:
77 _, line_no, col = pos
78 line_no -= 1
79 col += 1
80 line = lines[line_no]
81 lines[line_no] = line[:col] + item + line[col:]
83 html_filename = os.path.splitext(target_filename)[0] + ".html"
84 f = codecs.open(html_filename, "w", encoding="UTF-8")
85 f.write(u'<html>\n')
86 f.write(u"""
87 <head>
88 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
89 <style type="text/css">
91 body { font-family: courier; font-size: 12; }
93 .code { font-size: 9; color: #444444; display: none; margin-left: 20px; }
94 .py_api { color: red; }
95 .pyx_api { color: #FF3000; }
96 .py_macro_api { color: #FF8000; }
97 .error_goto { color: #FF8000; }
99 .tag { }
101 .coerce { color: #008000; border: 1px dotted #008000 }
103 .py_attr { color: #FF0000; font-weight: bold; }
104 .c_attr { color: #0000FF; }
106 .py_call { color: #FF0000; font-weight: bold; }
107 .c_call { color: #0000FF; }
109 .line { margin: 0em }
111 </style>
112 <script>
113 function toggleDiv(id) {
114 theDiv = document.getElementById(id);
115 if (theDiv.style.display == 'none') theDiv.style.display = 'block';
116 else theDiv.style.display = 'none';
117 }
118 </script>
119 </head>
120 """)
121 f.write(u'<body>\n')
122 f.write(u'<p>Generated by Cython %s on %s\n' % (Version.version, time.asctime()))
123 c_file = Utils.encode_filename(os.path.basename(target_filename))
124 f.write(u'<p>Raw output: <a href="%s">%s</a>\n' % (c_file, c_file))
125 k = 0
127 py_c_api = re.compile(u'(Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)')
128 pyx_api = re.compile(u'(__Pyx[A-Za-z_]+)\(')
129 py_marco_api = re.compile(u'(Py[A-Za-z]*_[A-Z][A-Z_]+)')
130 error_goto = re.compile(ur'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})')
132 for line in lines:
134 k += 1
135 try:
136 code = self.code[k]
137 except KeyError:
138 code = ''
140 code, c_api_calls = py_c_api.subn(ur"<span class='py_api'>\1</span>", code)
141 code, pyx_api_calls = pyx_api.subn(ur"<span class='pyx_api'>\1</span>(", code)
142 code, macro_api_calls = py_marco_api.subn(ur"<span class='py_macro_api'>\1</span>", code)
143 code, error_goto_calls = error_goto.subn(ur"<span class='error_goto'>\1</span>", code)
145 code = code.replace(u"<span class='error_goto'>;", u";<span class='error_goto'>")
147 color = u"FFFF%02x" % int(255/(1+(5*c_api_calls+2*pyx_api_calls+macro_api_calls)/10.0))
148 f.write(u"<pre class='line' style='background-color: #%s' onclick='toggleDiv(\"line%s\")'>" % (color, k))
150 f.write(u" %d: " % k)
151 for c, cc, html in special_chars:
152 line = line.replace(cc, html)
153 f.write(line.rstrip())
155 f.write(u'</pre>\n')
156 f.write(u"<pre id='line%s' class='code' style='background-color: #%s'>%s</pre>" % (k, color, code))
157 f.write(u'</body></html>\n')
158 f.close()
161 # TODO: make this cleaner
162 def escape(raw_string):
163 raw_string = raw_string.replace(u"\'", ur"’")
164 raw_string = raw_string.replace(u'\"', ur'"')
165 raw_string = raw_string.replace(u'\n', ur'<br>\n')
166 raw_string = raw_string.replace(u'\t', ur'\t')
167 return raw_string
170 class AnnotationItem:
172 def __init__(self, style, text, tag="", size=0):
173 self.style = style
174 self.text = text
175 self.tag = tag
176 self.size = size
178 def start(self):
179 return u"<span class='tag %s' title='%s'>%s" % (self.style, self.text, self.tag)
181 def end(self):
182 return self.size, u"</span>"
