feat(parser): add code block title and line highlighting - #41
Conversation
Implements github.com/engineervix/issues/6 - title="..." attribute renders a <figure class="code-block"> with a <div class="code-title"> header bar above the <pre>. - {n,m-p} attribute highlights specific lines (1-indexed) with a <span class="highlight-line"> class (accent bg + left border). - Both can be combined on the same fence. - Plain code blocks (no custom attrs) are untouched. Implementation: - Extends internal/parser/highlight.go via AST transformer (priority 200) and custom NodeRenderer. - Chroma is called directly with line numbers; HTML post-processed to inject highlight-line class. - 28 new unit tests covering all combinations and edge cases. - CSS rules for .code-block / .code-title / .code-body / .highlight-line (light + dark variants) added to assets/theme.css. - docs/guide/03-markdown.md updated with rendered examples.
engineervix
left a comment
There was a problem hiding this comment.
Summary
Reviewed the Go parser extension for code-block titles + line highlighting. Build and go vet are clean, CI is green, and test coverage is thorough (28 new tests covering quoting, ordering, D2 interop, out-of-range, empty title, etc.).
What's good:
- Title text and the Chroma fallback path are properly HTML-escaped — no XSS via
title="…". - Plain code blocks (no custom attrs) keep the old zero-overhead path unchanged — verified by
TestCodeBlockPlainPassthrough. - D2 diagram blocks are correctly unaffected (transformer priority 100 vs. 200 — confirmed the ordering in
d2.go). - Architecture matches the existing extension pattern in this codebase (AST transformer + NodeRenderer pair, same as the D2 extension).
Requesting changes for one item: the unbounded highlight-range expansion (inline comment on highlight.go:304) — I reproduced a 2+ minute hang from a single typo'd range ({2-2000000000}) in a standalone test. The rest are non-blocking nits (inline comments): a redundant/duplicate code path, a couple of literal-tab-byte string literals, and an unused parameter — none change behavior, just worth cleaning up.
Checked against the Web Interface Guidelines skill too — no violations, since this PR touches static CSS with no interactive elements.
… extension Addresses review feedback on engineervix#41: - Cap {lo-hi} expansion at 10k lines. A typo'd range like {2-2000000000} previously tried to build a slice with billions of ints and hung indefinitely instead of being silently dropped like other malformed input. - Remove the looksLikeSingleAttr branch/helper in codeAttrsTransformer.Transform — it duplicated the fallback path below it for the same inputs. - Use \t escapes instead of literal tab bytes in two string/rune literals. - Drop the unused darkStyle/darkStyleName plumbing in codeAttrsExtension, codeAttrsRenderer, and renderCodeBlockBody; classed HTML only needs the light style since dark colours come from the separate [data-theme="dark"] stylesheet (same reasoning already documented for newMarkdown's highlighting.WithStyle call).
engineervix
left a comment
There was a problem hiding this comment.
All four review findings addressed in 10722b6 (unbounded highlight-range hang capped, redundant code path removed, literal-tab-byte literals fixed, unused darkStyle plumbing dropped) — verified build/vet/tests pass, and re-ran the original hang repro to confirm it now returns immediately. CI is green.
engineervix
left a comment
There was a problem hiding this comment.
Reversing decision to approve PR as there are several things wrong with the styling
…de colours - Switch Chroma to inline line numbers (WithLineNumbers, no LineNumbersInTable) instead of the two-<pre> table layout. Fixes gutter/code misalignment and the ~48px gap between them (each <pre> had its own padding), and removes the need to special-case main.js's copy button against a second, number-only <pre>. - Drop the left accent bar on highlighted lines (box-shadow), matching mkdocs-material/VitePress convention. - Bleed the highlight-line background into the code block's own padding so it reaches the card edges instead of stopping short. - Scope ChromaCSS's light-theme rules to :root:not([data-theme="dark"]) (previously only dark rules were scoped). A Chroma style commonly leaves some token types uncoloured, relying on the base foreground — github-dark has no explicit entry for plain identifiers or punctuation, so those tokens rendered in github (light)'s near-black colour even in dark mode, since an unscoped rule that directly matches an element always wins over an inherited value regardless of specificity. This was a pre-existing site-wide bug, not specific to the new highlighting feature. - Bump .highlight-line's selector depth to match the real DOM nesting: scoping the light rules above made Chroma's own .hl rule 4 classes deep, which briefly outranked the previous 3-class override.
Summary
Adds two new capabilities to the parser for fenced code blocks:
titleattribute (e.g. ```go title="main.go"`), rendered as a header above the block.Changes