From 6d068d9259e2173a965b5d57347405ef578f1a76 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Sun, 28 Jun 2026 06:43:08 -0700 Subject: [PATCH 1/2] html report: add packet summary to sidebar header and per-file omit button in Files view Signed-off-by: Zeev Belinsky --- scripts/cov_html_report.py | 40 ++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/scripts/cov_html_report.py b/scripts/cov_html_report.py index 03a3cbca..65d8feca 100755 --- a/scripts/cov_html_report.py +++ b/scripts/cov_html_report.py @@ -137,6 +137,12 @@ .tree-fn.active .tree-label { color: #fff; } .tree-root { background: #252526; font-weight: bold; border-bottom: 1px solid #444; } .tree-root .tree-label { color: #ccc; } +.tree-omit-btn { + margin-left: auto; background: transparent; border: none; + color: #a44; font-size: 0.85em; cursor: pointer; padding: 0 4px; + border-radius: 3px; line-height: 1; flex-shrink: 0; +} +.tree-omit-btn:hover { color: #f99; background: #3c2222; } #detail { flex: 1; overflow: hidden; display: flex; flex-direction: column; padding: 16px 20px; background: #1e1e1e; color: #ccc; } #detail h2 { font-size: 1em; margin-bottom: 10px; color: #9cdcfe; border-bottom: 1px solid #333; padding-bottom: 6px; flex-shrink: 0; } @@ -618,14 +624,15 @@ } // Collapse single-child directory chains (a/b/c → a/b/c) for compactness. -function treeRowHtml(label, pct, depth, kind, key, isOpen, dataAttr) { +function treeRowHtml(label, pct, depth, kind, key, isOpen, dataAttr, extra) { var pad = 10 + depth * 14; var arrow = kind === 'leaf' ? '' : '' + (isOpen ? '▾' : '▸') + ''; var badge = '' + pct + '%'; return '
' + arrow + badge - + '' + escSvg(label) + '
'; + + '' + escSvg(label) + '' + + (extra || '') + ''; } function renderTreeNode(node, depth, out) { @@ -649,8 +656,11 @@ fileKeys.forEach(function(k) { var f = node.files[k]; var isOpen = !treeCollapsed[f.path]; + var safePath = f.path.replace(/'/g, "\\'"); + var omitBtn = ''; out.push(treeRowHtml(f.name, nodePct(f), depth, 'file', f.path, isOpen, - 'onclick="toggleTreeNode(\'' + f.path.replace(/'/g, "\\'") + '\')"')); + 'onclick="toggleTreeNode(\'' + safePath + '\')"', omitBtn)); if (isOpen) { // functions in this file, sorted by pct asc f.fns.slice().sort(function(a, b) { @@ -753,6 +763,23 @@ if (nextFn) show(nextFn); } +// Omit all functions belonging to a given source file path. +function omitFile(filePath) { + var fns = Object.keys(fnSrc).filter(function(fn) { return fnSrc[fn] === filePath; }); + var visible = fns.filter(function(fn) { return !isOmitted(fn); }); + if (!visible.length) return; + if (!confirm('Omit all ' + visible.length + ' function(s) in ' + filePath + '?')) return; + visible.forEach(function(fn) { localOmit[fn] = 1; }); + saveLocalOmit(); + refreshOmitUi(); + onTestChange(); + refreshDetail(); + if (currentFunc && isOmitted(currentFunc)) { + var first = document.querySelector('.fn-entry:not([style*="display: none"]):not([style*="display:none"])'); + if (first) show(first.dataset.fn); + } +} + // Restore a single session-omitted function (live — no reload needed). function restoreOmit(fn) { delete localOmit[fn]; @@ -1027,6 +1054,10 @@ def build_html(funcs, cov_data, test_covs, fn_src, omit_names=None, omit_header= execd, total = packet_counts(lines) fn_packets[name] = [execd, total] + total_exec_pkts = sum(v[0] for v in fn_packets.values()) + total_pkts = sum(v[1] for v in fn_packets.values()) + pkt_pct = round(100 * total_exec_pkts / total_pkts) if total_pkts else 0 + callees, callers = build_call_graphs(cov_data, tracked_fns) fn_data_js = 'var fnData = {\n' + ',\n'.join(fn_data_entries) + '\n};' @@ -1149,7 +1180,8 @@ def build_html(funcs, cov_data, test_covs, fn_src, omit_names=None, omit_header= '