Replace plan JSON with colored S-expression display

- Add plan_to_sexp() to convert plan to S-expression format
- Syntax highlighting for S-expressions:
  - Pink: special forms (plan, recipe, def, ->)
  - Blue: primitives (source, effect, sequence, etc.)
  - Purple: keywords (:input, :name, etc.)
  - Green: strings
  - Yellow: parentheses
  - Gray: comments

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gilesb
2026-01-12 00:23:12 +00:00
parent 82d94f6e0e
commit f554122b07
2 changed files with 87 additions and 4 deletions

View File

@@ -156,15 +156,41 @@
{% endfor %}
</div>
<!-- Plan JSON -->
<details class="mt-6">
<!-- Plan S-expression -->
<details class="mt-6" open>
<summary class="cursor-pointer text-gray-400 hover:text-white text-sm mb-2">
Show Plan JSON
Plan (S-expression)
</summary>
<div class="bg-gray-900 rounded-lg border border-gray-700 p-4 overflow-x-auto">
<pre class="text-sm text-gray-300 whitespace-pre-wrap">{{ plan | tojson(indent=2) }}</pre>
<pre class="text-sm font-mono sexp-code">{{ plan_sexp }}</pre>
</div>
</details>
<style>
.sexp-code {
line-height: 1.6;
}
</style>
<script>
// Syntax highlight S-expressions
document.querySelectorAll('.sexp-code').forEach(el => {
let html = el.textContent;
// Comments
html = html.replace(/(;;.*)/g, '<span class="text-gray-500">$1</span>');
// Keywords (:keyword)
html = html.replace(/(:[a-zA-Z_-]+)/g, '<span class="text-purple-400">$1</span>');
// Strings
html = html.replace(/("(?:[^"\\]|\\.)*")/g, '<span class="text-green-400">$1</span>');
// Special forms
html = html.replace(/\b(plan|recipe|def|->)\b/g, '<span class="text-pink-400 font-semibold">$1</span>');
// Primitives
html = html.replace(/\((source|effect|sequence|segment|resize|transform|layer|blend|mux|analyze)\b/g,
'(<span class="text-blue-400">$1</span>');
// Parentheses
html = html.replace(/(\(|\))/g, '<span class="text-yellow-500">$1</span>');
el.innerHTML = html;
});
</script>
{% else %}
<p class="text-gray-500">No plan available for this run.</p>
{% endif %}