Skip to content

Commit 7001908

Browse files
@Kartikayy007: Add syntax highlighting to code blocks in reports and fix and the Outdated section name (#883)
Run experiment for #881 before merging, credit goes to @Kartikayy007. --------- Co-authored-by: Kartikay Singh pundir <[email protected]>
1 parent 00bc7e2 commit 7001908

File tree

4 files changed

+127
-15
lines changed

4 files changed

+127
-15
lines changed

Diff for: report/common.py

+25-2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class Benchmark:
7373
signature: str = ''
7474
project: str = ''
7575
function: str = ''
76+
language: str = ''
7677

7778

7879
@dataclasses.dataclass
@@ -129,6 +130,7 @@ def run_log(self) -> str:
129130
class Target:
130131
code: str
131132
fixer_prompt: Optional[str] = None
133+
build_script_code: Optional[str] = None
132134

133135

134136
@dataclasses.dataclass
@@ -414,7 +416,9 @@ def _get_targets_agent(self, benchmark: str, trial: str) -> Target:
414416
build_script_code = f.read()
415417

416418
# TODO(dongge): Properly show build script code in reports.
417-
return Target(code=fuzz_target_code, fixer_prompt=build_script_code)
419+
return Target(code=fuzz_target_code,
420+
fixer_prompt=None,
421+
build_script_code=build_script_code)
418422

419423
def get_samples(self, results: list[evaluator.Result],
420424
targets: list[str]) -> list[Sample]:
@@ -641,7 +645,9 @@ def _create_benchmark(
641645
function = benchmark_id.split('-')[-1]
642646
signature = self._find_benchmark_signature(project,
643647
function) or benchmark_id
644-
return Benchmark(benchmark_id, status, result, signature, project, function)
648+
language = self._find_benchmark_language(project, function)
649+
return Benchmark(benchmark_id, status, result, signature, project, function,
650+
language)
645651

646652
def _find_benchmark_signature(self, project: str,
647653
target_function: str) -> str:
@@ -673,6 +679,23 @@ def _find_benchmark_signature(self, project: str,
673679

674680
return matched_prefix_signature
675681

682+
def _find_benchmark_language(self, project: str, target_function: str) -> str:
683+
"""Finds the programming language of the benchmark."""
684+
if not self._benchmark_dir:
685+
return ''
686+
687+
project_path = os.path.join(self._benchmark_dir, f'{project}.yaml')
688+
if not FileSystem(project_path).isfile():
689+
return ''
690+
691+
try:
692+
with FileSystem(project_path).open() as f:
693+
benchmark_data = yaml.safe_load(f)
694+
return benchmark_data.get('language', '')
695+
except Exception as e:
696+
logging.error('Failed to read benchmark file %s: %s', project_path, e)
697+
return ''
698+
676699

677700
def _parse_log_parts(log: str) -> list[LogPart]:
678701
"""Parse log into parts."""

Diff for: report/templates/base.html

+23
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,30 @@
100100
line-height: 1.5;
101101
white-space: pre;
102102
}
103+
104+
.hljs {
105+
background: transparent;
106+
padding: 0;
107+
}
103108
</style>
109+
<!-- added highlight.js for syntax highlighting -->
110+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css">
111+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
112+
<!-- some Additional language -->
113+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/bash.min.js"></script>
114+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/c.min.js"></script>
115+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/cpp.min.js"></script>
116+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/java.min.js"></script>
117+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/python.min.js"></script>
118+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/rust.min.js"></script>
119+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/go.min.js"></script>
120+
<script>
121+
document.addEventListener('DOMContentLoaded', (event) => {
122+
document.querySelectorAll('pre code.syntax-highlight').forEach((block) => {
123+
hljs.highlightElement(block);
124+
});
125+
});
126+
</script>
104127
<body>
105128
LLM: {{ model }}
106129
{% block content %}{% endblock %}

Diff for: report/templates/sample.html

+16-5
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
#}{% extends 'base.html' %}
1717

1818
{% block content %}
19-
<h1>{{ benchmark }} / {{ sample.id }}</h1>
20-
Bug: {{ sample.result.crashes and not sample.result.is_semantic_error }}
19+
<h1>{{ benchmark_id }} / {{ sample.id }}</h1>
20+
Bug: {{ sample.result.crashes|default(false) and not sample.result.is_semantic_error|default(false) }}
2121
<br>
22-
Crash reason: {{ sample.result.semantic_error }}
22+
Crash reason: {{ sample.result.semantic_error|default('') }}
2323
<br>
2424
<br>
2525

@@ -52,10 +52,21 @@ <h3>Final code</h3>
5252
{% else %}
5353
<h3>Code #{{ loop.index - 1}}</h3>
5454
{% endif %}
55+
56+
{% if target.code is defined and target.code %}
57+
<div class="code-container">
58+
<pre class="line-numbers">{% for line in target.code|remove_trailing_empty_lines|splitlines %}<span>{{ loop.index }}</span>{% endfor %}</pre>
59+
<pre class="code-content"><code class="syntax-highlight language-{% if benchmark.language is defined and benchmark.language %}{{ benchmark.language | lower }}{% else %}plaintext{% endif %}">{{ target.code|remove_trailing_empty_lines }}</code></pre>
60+
</div>
61+
{% endif %}
62+
63+
{% if target.build_script_code is defined and target.build_script_code %}
64+
<h3>Build Script</h3>
5565
<div class="code-container">
56-
<pre class="line-numbers">{% for line in target.code.splitlines() %}<span>{{ loop.index }}</span>{% endfor %}</pre>
57-
<pre class="code-content">{% for line in target.code.splitlines() %}<code>{{ line }}</code>{% endfor %}</pre>
66+
<pre class="line-numbers">{% for line in target.build_script_code|remove_trailing_empty_lines|splitlines %}<span>{{ loop.index }}</span>{% endfor %}</pre>
67+
<pre class="code-content"><code class="syntax-highlight language-bash">{{ target.build_script_code|remove_trailing_empty_lines }}</code></pre>
5868
</div>
69+
{% endif %}
5970
{% endfor %}
6071

6172
<h2>Logs</h2>

Diff for: report/web.py

+63-8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import shutil
2222
import threading
2323
import time
24+
import traceback
2425
import urllib.parse
2526
from functools import partial
2627
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
@@ -65,6 +66,33 @@ def _cov_report_link(link: str):
6566
return link_path + 'index.html'
6667
return link_path + 'report.html'
6768

69+
@staticmethod
70+
def _remove_trailing_empty_lines(code: str) -> str:
71+
"""Remove trailing empty lines from code."""
72+
if not code:
73+
return ""
74+
75+
try:
76+
lines = code.splitlines()
77+
while lines and not lines[-1].strip():
78+
lines.pop()
79+
80+
return '\n'.join(lines)
81+
except Exception as e:
82+
logging.warning("Error in remove_trailing_empty_lines filter: %s", e)
83+
return code # Return original code on error
84+
85+
@staticmethod
86+
def _splitlines(text: str) -> list:
87+
"""Split text into lines, similar to Python's splitlines()."""
88+
if not text:
89+
return []
90+
try:
91+
return text.splitlines()
92+
except Exception as e:
93+
logging.warning("Error in splitlines filter: %s", e)
94+
return [text] # Return original as single line on error
95+
6896
def __init__(self, template_globals: Optional[Dict[str, Any]] = None):
6997
self._env = jinja2.Environment(
7098
loader=jinja2.FileSystemLoader("report/templates"),
@@ -73,6 +101,9 @@ def __init__(self, template_globals: Optional[Dict[str, Any]] = None):
73101
self._env.filters['urlencode_filter'] = self._urlencode_filter
74102
self._env.filters['percent'] = self._percent
75103
self._env.filters['cov_report_link'] = self._cov_report_link
104+
self._env.filters[
105+
'remove_trailing_empty_lines'] = self._remove_trailing_empty_lines
106+
self._env.filters['splitlines'] = self._splitlines
76107

77108
if template_globals:
78109
for key, val in template_globals.items():
@@ -233,18 +264,42 @@ def _write_benchmark_sample(self, benchmark: Benchmark, sample: Sample,
233264
sample_targets: List[Target]):
234265
"""Generate the sample page and write to filesystem."""
235266
try:
236-
rendered = self._jinja.render(
237-
'sample.html',
238-
benchmark=benchmark.id,
239-
sample=sample,
240-
logs=self._results.get_logs(benchmark.id, sample.id),
241-
run_logs=self._results.get_run_logs(benchmark.id, sample.id),
242-
triage=self._results.get_triage(benchmark.id, sample.id),
243-
targets=sample_targets)
267+
# Ensure all required variables are available
268+
logs = self._results.get_logs(benchmark.id, sample.id) or []
269+
run_logs = self._results.get_run_logs(benchmark.id, sample.id) or ""
270+
triage = self._results.get_triage(benchmark.id, sample.id) or {
271+
"result": "",
272+
"triager_prompt": ""
273+
}
274+
275+
rendered = self._jinja.render('sample.html',
276+
benchmark=benchmark,
277+
benchmark_id=benchmark.id,
278+
sample=sample,
279+
logs=logs,
280+
run_logs=run_logs,
281+
triage=triage,
282+
targets=sample_targets)
244283
self._write(f'sample/{benchmark.id}/{sample.id}.html', rendered)
245284
except Exception as e:
246285
logging.error('Failed to write sample/%s/%s:\n%s', benchmark.id,
247286
sample.id, e)
287+
logging.error('Exception details: %s', traceback.format_exc())
288+
# Create a simple error page so users see something
289+
try:
290+
error_html = f"""
291+
<html>
292+
<head><title>Error rendering {benchmark.id}/{sample.id}</title></head>
293+
<body>
294+
<h1>Error rendering sample page</h1>
295+
<p>An error occurred while rendering this page. Please check the logs for details.</p>
296+
<pre>{str(e)}</pre>
297+
</body>
298+
</html>
299+
"""
300+
self._write(f'sample/{benchmark.id}/{sample.id}.html', error_html)
301+
except Exception:
302+
pass # Ignore errors in error handling
248303

249304

250305
def generate_report(args: argparse.Namespace) -> None:

0 commit comments

Comments
 (0)