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