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 </pre> 41 </body> 42 </html>""") 43 44 file.close() 45 46 47# render in html 48def renderHtml(text, highlights, sourceFileName, outputFileName): 49 splittedText = highlightSplit(text, highlights) 50 51 file = open(outputFileName, 'a') 52 file.write("<hr/><p><b>" + sourceFileName + "</b></p>") 53 54 # insert highlight tags in a temp buffer 55 temp = "" 56 count = 0 57 for slice in splittedText: 58 if count % 2 == 0: 59 temp += escape(slice) + '<span class="highlight tooltip">' 60 else: 61 temp += escape(slice) + "<em>" + highlights[(count - 1) / 2][2] \ 62 + "</em></span>" 63 count += 1 64 65 temp += "</span>" # close the superfluous last highlight 66 67 file.write('<table><tr><td><pre class="code"><span class="linenumber">') 68 count = 1 69 for line in temp.split('\n'): 70 file.write(str(count).rjust(4)+"<br>") 71 count += 1 72 73 file.write('</span></pre></td><td><pre class="code">') 74 75 for line in temp.split('\n'): 76 file.write('<span class="linehead"> </span>' + line.replace('\r', ' ') \ 77 + '<br>') 78 79 file.write("</pre></td></tr></table>") 80 81 file.close() 82 83 84# highlight overlap check 85def highlightOverlaps(highlight1, highlight2): 86 #print "hl1", highlight1, "hl2", highlight2 87 return not(highlight2[0] > highlight1[1] or highlight1[0] > highlight2[1]) 88 89 90# splits the string in three parts before, between and after the highlight 91def splitByHighlight(string, highlight): 92 return (string[:highlight[0]], string[highlight[0]:highlight[1]], \ 93 string[highlight[1]:]) 94 95 96# splits the source text on highlights boundaries so that we can escape to html 97# without the need to recalculate the highlights positions 98def highlightSplit(string, highlights): 99 splittedString = [] 100 text = string 101 offset = 0 102 lastEnd = 0 103 for (start, end, name) in highlights: 104 if start >= lastEnd: 105 (before, between, after) = splitByHighlight( \ 106 text, (start - offset, end - offset)) 107 splittedString.append(before) 108 splittedString.append(between) 109 text = after 110 lastEnd = end 111 offset += len(before + between) 112 else: 113 print "overlap ", (start, end, name) 114 splittedString.append(text) 115 return splittedString 116 117 118# checkHighlights() checks for highlights overlaps 119def checkHighlights(highlights): 120 highlights.sort() 121 122 index = 0 123 lastHighlight = (-2, -1, '') 124 125 # merge overlapping highlights 126 for highlight in highlights: 127 if highlightOverlaps(highlight, lastHighlight): 128 129 newStart = min(lastHighlight[0], highlight[0]) 130 newEnd = max(lastHighlight[1], highlight[1]) 131 newComment = lastHighlight[2] 132 133 if (newComment.find(highlight[2]) == -1): 134 newComment += " + " + highlight[2] 135 136 highlight = (newStart, newEnd, newComment) 137 highlights[index] = highlight 138 139 # mark highlight to be deleted 140 highlights[index - 1] = (0, 0, "") 141 142 lastHighlight = highlight 143 index += 1 144 145 # remove "to be deleted" highlights 146 return [ (start, end, comment) for (start, end, comment) in highlights \ 147 if (start, end, comment) != (0, 0, "") ] 148 149 150def cssStyle(): 151 return """ 152 .highlight { 153 background: #ffff00; 154 color: #000000; 155 } 156 157 .linehead { 158 background: #ddd; 159 font-size: 1px; 160 } 161 162 .highlight .linehead { 163 background: #ffff00;; 164 color: #999; 165 text-align: right; 166 font-size: 8px; 167 } 168 169 .linenumber { 170 background: #eee; 171 color: #999; 172 text-align: right; 173 } 174 175 td { 176 border-spacing: 0px; 177 border-width: 0px; 178 padding: 0px 179 } 180 181 div.code pre { 182 font-family: monospace; 183 } 184 185 .tooltip em { 186 display:none; 187 } 188 189 .tooltip:hover { 190 border: 0; 191 position: relative; 192 z-index: 500; 193 text-decoration:none; 194 } 195 196 .tooltip:hover em { 197 font-style: normal; 198 display: block; 199 position: absolute; 200 top: 20px; 201 left: -10px; 202 padding: 5px; 203 color: #000; 204 border: 1px solid #bbb; 205 background: #ffc; 206 width: auto; 207 }""" 208