HTML report: display 'verbose' message using clickable expandable divs

This commit is contained in:
Samuel Degrande 2014-10-15 21:49:22 +02:00 committed by PKEuS
parent 45a2986f34
commit ab6178f739
1 changed files with 82 additions and 6 deletions

View File

@ -14,6 +14,7 @@ from pygments.formatters import HtmlFormatter
from xml.sax import parse as xml_parse
from xml.sax import SAXParseException as XmlParseException
from xml.sax.handler import ContentHandler as XmlContentHandler
from xml.sax.saxutils import escape
"""
Turns a cppcheck xml file into a browsable html report along
@ -56,6 +57,25 @@ h1 {
display: inline-block;
margin-left: 4px;
}
div.verbose {
display: inline-block;
vertical-align: top;
cursor: help;
}
div.verbose div.content {
display: none;
position: absolute;
padding: 10px;
margin: 4px;
max-width: 40%;
white-space: pre-wrap;
border: 1px solid black;
background-color: #FFFFCC;
cursor: auto;
}
.highlight .hll {
padding: 1px;
}
@ -155,9 +175,43 @@ HTML_HEAD = """
<link rel="stylesheet" href="style.css">
<style>
%s
</style>
</style>
<script language="javascript">
function getStyle(el,styleProp) {
if (el.currentStyle)
var y = el.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
return y;
}
function toggle() {
var el = this.expandable_content;
var mark = this.expandable_marker;
if (el.style.display == "block") {
el.style.display = "none";
mark.innerHTML = "[+]";
} else {
el.style.display = "block";
mark.innerHTML = "[-]";
}
}
function init_expandables() {
var elts = document.getElementsByClassName("expandable");
for (var i = 0; i < elts.length; i++) {
var el = elts[i];
var clickable = el.getElementsByTagName("span")[0];
var marker = clickable.getElementsByClassName("marker")[0];
var content = el.getElementsByClassName("content")[0];
var width = clickable.clientWidth - parseInt(getStyle(content, "padding-left")) - parseInt(getStyle(content, "padding-right"));
content.style.width = width + "px";
clickable.expandable_content = content;
clickable.expandable_marker = marker;
clickable.onclick = toggle;
}
}
</script>
</head>
<body>
<body onload="init_expandables()">
<div id="header">
<h1>Cppcheck report - %s: %s </h1>
</div>
@ -189,6 +243,18 @@ HTML_FOOTER = """
HTML_ERROR = "<span class='error2'>&lt;--- %s</span>\n"
HTML_INCONCLUSIVE = "<span class='inconclusive2'>&lt;--- %s</span>\n"
HTML_EXPANDABLE_ERROR = "<div class='verbose expandable'><span class='error2'>&lt;--- %s <span class='marker'>[+]</span></span><div class='content'>%s</div></div>\n"""
HTML_EXPANDABLE_INCONCLUSIVE = "<div class='verbose expandable'><span class='inconclusive2'>&lt;--- %s <span class='marker'>[+]</span></span><div class='content'>%s</div></div>\n"""
# escape() and unescape() takes care of &, < and >.
html_escape_table = {
'"': "&quot;",
"'": "&apos;"
}
html_unescape_table = {v:k for k, v in html_escape_table.items()}
def html_escape(text):
return escape(text, html_escape_table)
class AnnotateCodeFormatter(HtmlFormatter):
errors = []
@ -203,9 +269,17 @@ class AnnotateCodeFormatter(HtmlFormatter):
if error['line'] == line_no:
try:
if error['inconclusive'] == 'true':
t = t.replace('\n', HTML_INCONCLUSIVE % error['msg'])
if error.get('verbose'):
index = t.rfind('\n')
t = t[:index] + HTML_EXPANDABLE_INCONCLUSIVE % (error['msg'], html_escape(error['verbose'].replace("\\012", '\n'))) + t[index+1:]
else:
t = t.replace('\n', HTML_INCONCLUSIVE % error['msg'])
except KeyError:
t = t.replace('\n', HTML_ERROR % error['msg'])
if error.get('verbose'):
index = t.rfind('\n')
t = t[:index] + HTML_EXPANDABLE_ERROR % (error['msg'], html_escape(error['verbose'].replace("\\012", '\n'))) + t[index+1:]
else:
t = t.replace('\n', HTML_ERROR % error['msg'])
line_no = line_no + 1
yield i, t
@ -253,6 +327,7 @@ class CppCheckHandler(XmlContentHandler):
'id': attributes['id'],
'severity': attributes['severity'],
'msg': attributes['msg'],
'verbose': attributes.get('verbose'),
'inconclusive': attributes['inconclusive']
})
except KeyError:
@ -261,14 +336,14 @@ class CppCheckHandler(XmlContentHandler):
'line': 0,
'id': attributes['id'],
'severity': attributes['severity'],
'msg': attributes['msg']
'msg': attributes['msg'],
'verbose': attributes.get('verbose')
})
elif name == 'location':
assert self.errors
self.errors[-1]['file'] = attributes['file']
self.errors[-1]['line'] = int(attributes['line'])
if __name__ == '__main__':
# Configure all the options this little utility is using.
parser = optparse.OptionParser()
@ -374,6 +449,7 @@ if __name__ == '__main__':
lineanchors='line',
encoding=options.source_encoding)
htmlFormatter.errors = errors
with io.open(os.path.join(options.report_dir, htmlfile),
'w') as output_file:
output_file.write(HTML_HEAD %