refactor unify code_listing/highlighted_code_listing internals

Extract numbered_lines as a shared helper parameterized by a line-rendering function. Both code_listing and highlighted_code_listing are now thin wrappers that pass their content formatter to the shared anchor/numbering logic.

Commit
8772566b26b67ecaa2c94f4c0ecfc32691f2e56c
Author
Claude Sonnet 4 <claude@anthropic.invalid>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
lib/views/ui.ml
index a5be2e94..7f714072 100644..100644
@@ -324,11 +324,7 @@
324 324
325 325 (* Code *)
326 326
327 Removed: let code_listing ?id ?class_ ?(anchor_prefix = "") content =
328 Removed: (* Anchor and text alternate as siblings of one grid container, so the
329 Removed: stylesheet can align numbers against wrapping lines without a table. The
330 Removed: leading tab and trailing newline preserve the source's shape when the
331 Removed: listing is copied. *)
327 Added: let numbered_lines ?id ?class_ ?(anchor_prefix = "") render_line lines =
332 328 let numbered_line index line =
333 329 let number = index + 1 in
334 330 let name = Printf.sprintf "%s%d" anchor_prefix number in
@@ -341,32 +337,27 @@
341 337 Aria.label "Line %d" number;
342 338 ]
343 339 [ text (string_of_int number) ];
344 Removed: HTML.span [ HTML.class_ "line" ] [ txt "\t%s\n" line ];
340 Added: HTML.span [ HTML.class_ "line" ] (render_line line);
345 341 ]
346 342 in
347 Removed: block ?id ?class_
348 Removed: (String.split_on_char '\n' content |> List.mapi numbered_line |> List.concat)
343 Added: block ?id ?class_ (List.mapi numbered_line lines |> List.concat)
349 344
350 Removed: let highlighted_code_listing ?id ?class_ ?(anchor_prefix = "") lines =
345 Added: let code_listing ?id ?class_ ?anchor_prefix content =
346 Added: (* Anchor and text alternate as siblings of one grid container, so the
347 Added: stylesheet can align numbers against wrapping lines without a table. The
348 Added: leading tab and trailing newline preserve the source's shape when the
349 Added: listing is copied. *)
350 Added: numbered_lines ?id ?class_ ?anchor_prefix
351 Added: (fun line -> [ txt "\t%s\n" line ])
352 Added: (String.split_on_char '\n' content)
353 Added:
354 Added: let highlighted_code_listing ?id ?class_ ?anchor_prefix lines =
351 355 (* Same grid layout as code_listing, but each line is a list of pre-rendered
352 356 nodes (highlighted spans) rather than plain text. The tab/newline framing
353 357 is identical so copy-paste behaviour is preserved. *)
354 Removed: let numbered_line index line_nodes =
355 Removed: let number = index + 1 in
356 Removed: let name = Printf.sprintf "%s%d" anchor_prefix number in
357 Removed: [
358 Removed: HTML.a
359 Removed: [
360 Removed: HTML.id "%s" name;
361 Removed: HTML.class_ "line-anchor";
362 Removed: HTML.href "#%s" name;
363 Removed: Aria.label "Line %d" number;
364 Removed: ]
365 Removed: [ text (string_of_int number) ];
366 Removed: HTML.span [ HTML.class_ "line" ] (txt "\t" :: line_nodes);
367 Removed: ]
368 Removed: in
369 Removed: block ?id ?class_ (List.mapi numbered_line lines |> List.concat)
358 Added: numbered_lines ?id ?class_ ?anchor_prefix
359 Added: (fun line_nodes -> txt "\t" :: line_nodes)
360 Added: lines
370 361
371 362 (* Diffs *)
372 363