1# 2# Copyright 2009, Alexandre Deckner, alex@zappotek.com 3# Distributed under the terms of the MIT License. 4# 5from cgi import escape 6 7 8# prints match to stdout 9def printMatch(name, match, source): 10 start = match.start() 11 end = match.end() 12 startLine = source.count('\n', 0, start) 13 startColumn = start - source.rfind('\n', 0, start) 14 print name + " (line " + str(startLine + 1) + ", " + str(startColumn) \ 15 + "): '" + match.group().replace('\n','\\n') + "'" 16 17 18def openHtml(fileList, outputFileName): 19 file = open(outputFileName, 'w') 20 file.write(""" 21 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 22 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 23 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 24 <head> 25 <title>Style violations</title> 26 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 27 <style type="text/css">""" + cssStyle() + """</style> 28 </head> 29 <body> 30 <p><b>File list:</b><br/>""") 31 for fileName in fileList: 32 file.write(fileName + "<br/>") 33 file.write("</p>") 34 file.close() 35 36 37def closeHtml(outputFileName): 38 file = open(outputFileName, 'a') 39 file.write(""" 40 </body> 41 </html>""") 42 43 file.close() 44 45 46# render in html 47def renderHtml(text, highlights, sourceFileName, outputFileName): 48 splittedText = highlightSplit(text, highlights) 49 50 file = open(outputFileName, 'a') 51 file.write("<hr/><p><b>" + sourceFileName + "</b></p>") 52 53 # insert highlight tags in a temp buffer 54 temp = "" 55 count = 0 56 for slice in splittedText: 57 if count % 2 == 0: 58 temp += escape(slice) + '<span class="highlight tooltip">' 59 else: 60 temp += escape(slice) + "<em>" + highlights[(count - 1) / 2][2] \ 61 + "</em></span>" 62 count += 1 63 64 temp += "</span>" # close the superfluous last highlight 65 66 file.write('<table><tr><td><pre class="code"><span class="linenumber">') 67 count = 1 68 for line in temp.split('\n'): 69 file.write(str(count).rjust(4)+"<br/>") 70 count += 1 71 72 file.write('</span></pre></td><td><pre class="code">') 73 74 for line in temp.split('\n'): 75 file.write('<span class="linehead"> </span>' + line.replace('\r', ' ') \ 76 + '<br/>') 77 78 file.write("</pre></td></tr></table>") 79 80 file.close() 81 82 83# highlight overlap check 84def highlightOverlaps(highlight1, highlight2): 85 #print "hl1", highlight1, "hl2", highlight2 86 return not(highlight2[0] > highlight1[1] or highlight1[0] > highlight2[1]) 87 88 89# splits the string in three parts before, between and after the highlight 90def splitByHighlight(string, highlight): 91 return (string[:highlight[0]], string[highlight[0]:highlight[1]], \ 92 string[highlight[1]:]) 93 94 95# splits the source text on highlights boundaries so that we can escape to html 96# without the need to recalculate the highlights positions 97def highlightSplit(string, highlights): 98 splittedString = [] 99 text = string 100 offset = 0 101 lastEnd = 0 102 for (start, end, name) in highlights: 103 if start >= lastEnd: 104 (before, between, after) = splitByHighlight( \ 105 text, (start - offset, end - offset)) 106 splittedString.append(before) 107 splittedString.append(between) 108 text = after 109 lastEnd = end 110 offset += len(before + between) 111 else: 112 print "overlap ", (start, end, name) 113 splittedString.append(text) 114 return splittedString 115 116 117# checkHighlights() checks for highlights overlaps 118def checkHighlights(highlights): 119 highlights.sort() 120 121 index = 0 122 lastHighlight = (-2, -1, '') 123 124 # merge overlapping highlights 125 for highlight in highlights: 126 if highlightOverlaps(highlight, lastHighlight): 127 128 newStart = min(lastHighlight[0], highlight[0]) 129 newEnd = max(lastHighlight[1], highlight[1]) 130 newComment = lastHighlight[2] 131 132 if (newComment.find(highlight[2]) == -1): 133 newComment += " + " + highlight[2] 134 135 highlight = (newStart, newEnd, newComment) 136 highlights[index] = highlight 137 138 # mark highlight to be deleted 139 highlights[index - 1] = (0, 0, "") 140 141 lastHighlight = highlight 142 index += 1 143 144 # remove "to be deleted" highlights 145 return [ (start, end, comment) for (start, end, comment) in highlights \ 146 if (start, end, comment) != (0, 0, "") ] 147 148 149def cssStyle(): 150 return """ 151 .highlight { 152 background: #ffff00; 153 color: #000000; 154 } 155 156 .linehead { 157 background: #ddd; 158 font-size: 1px; 159 } 160 161 .highlight .linehead { 162 background: #ffff00;; 163 color: #999; 164 text-align: right; 165 font-size: 8px; 166 } 167 168 .linenumber { 169 background: #eee; 170 color: #999; 171 text-align: right; 172 } 173 174 td { 175 border-spacing: 0px; 176 border-width: 0px; 177 padding: 0px 178 } 179 180 div.code pre { 181 font-family: monospace; 182 } 183 184 .tooltip em { 185 display:none; 186 } 187 188 .tooltip:hover { 189 border: 0; 190 position: relative; 191 z-index: 500; 192 text-decoration:none; 193 } 194 195 .tooltip:hover em { 196 font-style: normal; 197 display: block; 198 position: absolute; 199 top: 20px; 200 left: -10px; 201 padding: 5px; 202 color: #000; 203 border: 1px solid #bbb; 204 background: #ffc; 205 width: auto; 206 }""" 207