# Note: Work in progress import os import re import time import codecs from StringIO import StringIO 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'\xF0', u'<'), (u'>', u'\xF1', u'>'), (u'&', u'\xF2', u'&')] line_pos_comment = re.compile(r'/\*.*?<<<<<<<<<<<<<<.*?\*/\n*', re.DOTALL) class AnnotationCCodeWriter(CCodeWriter): def __init__(self, create_from=None, buffer=None, copy_formatting=True): CCodeWriter.__init__(self, create_from, buffer, copy_formatting=True) if create_from is None: self.annotation_buffer = StringIO() self.annotations = [] self.last_pos = None self.code = {} else: # When creating an insertion point, keep references to the same database self.annotation_buffer = create_from.annotation_buffer self.annotations = create_from.annotations self.code = create_from.code self.last_pos = create_from.last_pos def create_new(self, create_from, buffer, copy_formatting): return AnnotationCCodeWriter(create_from, buffer, copy_formatting) def write(self, s): CCodeWriter.write(self, s) self.annotation_buffer.write(s) def mark_pos(self, pos): if pos is not None: CCodeWriter.mark_pos(self, pos) if self.last_pos: pos_code = self.code.setdefault(self.last_pos[0].filename,{}) code = pos_code.get(self.last_pos[1], "") pos_code[self.last_pos[1]] = code + self.annotation_buffer.getvalue() self.annotation_buffer = StringIO() self.last_pos = pos 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 in range(len(lines)): line = lines[k] 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() all.reverse() 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:] html_filename = os.path.splitext(target_filename)[0] + ".html" f = codecs.open(html_filename, "w", encoding="UTF-8") f.write(u'\n' % Version.watermark) f.write(u'\n') f.write(u""" """) f.write(u'\n') f.write(u'

Generated by Cython %s\n' % Version.watermark) c_file = Utils.decode_filename(os.path.basename(target_filename)) f.write(u'

Raw output: %s\n' % (c_file, c_file)) k = 0 py_c_api = re.compile(u'(Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)\(') py_marco_api = re.compile(u'(Py[A-Z][a-z]+_[A-Z][A-Z_]+)\(') pyx_c_api = re.compile(u'(__Pyx_[A-Z][a-z_][A-Za-z_]+)\(') pyx_macro_api = re.compile(u'(__Pyx_[A-Z][A-Z_]+)\(') error_goto = re.compile(ur'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})') refnanny = re.compile(u'(__Pyx_X?(GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)') code_source_file = self.code[source_filename] for line in lines: k += 1 try: code = code_source_file[k] except KeyError: code = '' code = code.replace('<', '<') code, py_c_api_calls = py_c_api.subn(ur"\1(", code) code, pyx_c_api_calls = pyx_c_api.subn(ur"\1(", code) code, py_macro_api_calls = py_marco_api.subn(ur"\1(", code) code, pyx_macro_api_calls = pyx_macro_api.subn(ur"\1(", code) code, refnanny_calls = refnanny.subn(ur"\1", code) code, error_goto_calls = error_goto.subn(ur"\1", code) code = code.replace(u";", u";") score = 5*py_c_api_calls + 2*pyx_c_api_calls + py_macro_api_calls + pyx_macro_api_calls - refnanny_calls color = u"FFFF%02x" % int(255/(1+score/10.0)) f.write(u"

" % (color, k))

            f.write(u" %d: " % k)
            for c, cc, html in special_chars:
                line = line.replace(cc, html)
            f.write(line.rstrip())

            f.write(u'
\n') code = re.sub(line_pos_comment, '', code) # inline annotations are redundant f.write(u"
%s
" % (k, color, code)) f.write(u'\n') f.close() # TODO: make this cleaner def escape(raw_string): raw_string = raw_string.replace(u"\'", ur"’") raw_string = raw_string.replace(u'\"', ur'"') raw_string = raw_string.replace(u'\n', ur'
\n') raw_string = raw_string.replace(u'\t', ur'\t') return raw_string class AnnotationItem(object): def __init__(self, style, text, tag="", size=0): self.style = style self.text = text self.tag = tag self.size = size def start(self): return u"%s" % (self.style, self.text, self.tag) def end(self): return self.size, u""