HTML report: display 'verbose' message using clickable expandable divs
This commit is contained in:
parent
45a2986f34
commit
ab6178f739
|
@ -14,6 +14,7 @@ from pygments.formatters import HtmlFormatter
|
||||||
from xml.sax import parse as xml_parse
|
from xml.sax import parse as xml_parse
|
||||||
from xml.sax import SAXParseException as XmlParseException
|
from xml.sax import SAXParseException as XmlParseException
|
||||||
from xml.sax.handler import ContentHandler as XmlContentHandler
|
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
|
Turns a cppcheck xml file into a browsable html report along
|
||||||
|
@ -56,6 +57,25 @@ h1 {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 4px;
|
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 {
|
.highlight .hll {
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
}
|
}
|
||||||
|
@ -156,8 +176,42 @@ HTML_HEAD = """
|
||||||
<style>
|
<style>
|
||||||
%s
|
%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>
|
</head>
|
||||||
<body>
|
<body onload="init_expandables()">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<h1>Cppcheck report - %s: %s </h1>
|
<h1>Cppcheck report - %s: %s </h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -189,6 +243,18 @@ HTML_FOOTER = """
|
||||||
HTML_ERROR = "<span class='error2'><--- %s</span>\n"
|
HTML_ERROR = "<span class='error2'><--- %s</span>\n"
|
||||||
HTML_INCONCLUSIVE = "<span class='inconclusive2'><--- %s</span>\n"
|
HTML_INCONCLUSIVE = "<span class='inconclusive2'><--- %s</span>\n"
|
||||||
|
|
||||||
|
HTML_EXPANDABLE_ERROR = "<div class='verbose expandable'><span class='error2'><--- %s <span class='marker'>[+]</span></span><div class='content'>%s</div></div>\n"""
|
||||||
|
HTML_EXPANDABLE_INCONCLUSIVE = "<div class='verbose expandable'><span class='inconclusive2'><--- %s <span class='marker'>[+]</span></span><div class='content'>%s</div></div>\n"""
|
||||||
|
|
||||||
|
# escape() and unescape() takes care of &, < and >.
|
||||||
|
html_escape_table = {
|
||||||
|
'"': """,
|
||||||
|
"'": "'"
|
||||||
|
}
|
||||||
|
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):
|
class AnnotateCodeFormatter(HtmlFormatter):
|
||||||
errors = []
|
errors = []
|
||||||
|
@ -203,8 +269,16 @@ class AnnotateCodeFormatter(HtmlFormatter):
|
||||||
if error['line'] == line_no:
|
if error['line'] == line_no:
|
||||||
try:
|
try:
|
||||||
if error['inconclusive'] == 'true':
|
if error['inconclusive'] == 'true':
|
||||||
|
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'])
|
t = t.replace('\n', HTML_INCONCLUSIVE % error['msg'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
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'])
|
t = t.replace('\n', HTML_ERROR % error['msg'])
|
||||||
|
|
||||||
line_no = line_no + 1
|
line_no = line_no + 1
|
||||||
|
@ -253,6 +327,7 @@ class CppCheckHandler(XmlContentHandler):
|
||||||
'id': attributes['id'],
|
'id': attributes['id'],
|
||||||
'severity': attributes['severity'],
|
'severity': attributes['severity'],
|
||||||
'msg': attributes['msg'],
|
'msg': attributes['msg'],
|
||||||
|
'verbose': attributes.get('verbose'),
|
||||||
'inconclusive': attributes['inconclusive']
|
'inconclusive': attributes['inconclusive']
|
||||||
})
|
})
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -261,14 +336,14 @@ class CppCheckHandler(XmlContentHandler):
|
||||||
'line': 0,
|
'line': 0,
|
||||||
'id': attributes['id'],
|
'id': attributes['id'],
|
||||||
'severity': attributes['severity'],
|
'severity': attributes['severity'],
|
||||||
'msg': attributes['msg']
|
'msg': attributes['msg'],
|
||||||
|
'verbose': attributes.get('verbose')
|
||||||
})
|
})
|
||||||
elif name == 'location':
|
elif name == 'location':
|
||||||
assert self.errors
|
assert self.errors
|
||||||
self.errors[-1]['file'] = attributes['file']
|
self.errors[-1]['file'] = attributes['file']
|
||||||
self.errors[-1]['line'] = int(attributes['line'])
|
self.errors[-1]['line'] = int(attributes['line'])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Configure all the options this little utility is using.
|
# Configure all the options this little utility is using.
|
||||||
parser = optparse.OptionParser()
|
parser = optparse.OptionParser()
|
||||||
|
@ -374,6 +449,7 @@ if __name__ == '__main__':
|
||||||
lineanchors='line',
|
lineanchors='line',
|
||||||
encoding=options.source_encoding)
|
encoding=options.source_encoding)
|
||||||
htmlFormatter.errors = errors
|
htmlFormatter.errors = errors
|
||||||
|
|
||||||
with io.open(os.path.join(options.report_dir, htmlfile),
|
with io.open(os.path.join(options.report_dir, htmlfile),
|
||||||
'w') as output_file:
|
'w') as output_file:
|
||||||
output_file.write(HTML_HEAD %
|
output_file.write(HTML_HEAD %
|
||||||
|
|
Loading…
Reference in New Issue