My aggregated monorepo of OCaml code, automaintained
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Simplify @figure to alt-as-caption plain text

Odoc collapses newlines to spaces inside a paragraph and a blank line
terminates the @tag body, leaving no way to distinguish attributes
from a rich-text caption within one paragraph. Restrict v1 to:

@figure src=foo.png alt="Screenshot" link=https://…

The alt doubles as a plain-text figcaption. Rich captions with inline
formatting can follow in a v2 code-block variant. Updates the plan
to record the design constraint and decision.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+23 -29
+23 -29
src/odoc_jons_plugins.ml
··· 673 673 let raw_block html = 674 674 Block.{ attr = []; desc = Raw_markup ("html", html) } 675 675 676 - (* Split the incoming body into (first paragraph text, remaining 677 - nestable blocks used as caption). *) 678 - let split_first_paragraph content = 679 - match content with 680 - | [] -> ("", []) 681 - | first :: rest -> 682 - let first_text = 683 - Api.text_of_nestable_block_elements [first] 684 - |> Stdlib.String.trim 685 - in 686 - (first_text, rest) 687 - 676 + (* v1 design: the entire tag body is treated as the attribute string. 677 + Syntax: [@figure src=foo.png alt="Caption text" link=https://…] 678 + The [alt] attribute doubles as the figcaption (plain text). For 679 + rich-text captions, fall back to raw HTML until a v2 exists. *) 688 680 let to_document ~tag:_ content = 689 - let attr_line, caption_blocks = split_first_paragraph content in 681 + let attr_line = 682 + Api.text_of_nestable_block_elements content 683 + |> Stdlib.String.trim 684 + in 690 685 let attrs = parse_attrs attr_line |> infer_src in 691 686 match find_attr "src" attrs with 692 687 | None -> ··· 695 690 Api.simple_output (Api.blocks_of_nestable_elements content) 696 691 | Some src -> 697 692 let alt = Option.value ~default:"" (find_attr "alt" attrs) in 693 + let caption = 694 + match find_attr "caption" attrs with 695 + | Some c -> c 696 + | None -> alt 697 + in 698 698 let link = find_attr "link" attrs in 699 699 let extra_class = Option.value ~default:"" (find_attr "class" attrs) in 700 - let open_tag = 701 - let cls = 702 - if extra_class = "" then "figure" 703 - else "figure " ^ extra_class 704 - in 705 - Printf.sprintf {|<figure class="%s">|} (escape cls) 700 + let cls = 701 + if extra_class = "" then "figure" 702 + else "figure " ^ extra_class 706 703 in 707 704 let img_html = 708 705 match link with ··· 713 710 Printf.sprintf {|<img src="%s" alt="%s">|} 714 711 (escape src) (escape alt) 715 712 in 716 - let caption_opening, caption_closing = 717 - if caption_blocks = [] then "", "" 718 - else {|<figcaption>|}, {|</figcaption>|} 713 + let caption_html = 714 + if caption = "" then "" 715 + else Printf.sprintf {|<figcaption>%s</figcaption>|} (escape caption) 719 716 in 720 - let blocks = 721 - [ raw_block (open_tag ^ img_html ^ caption_opening) ] 722 - @ (if caption_blocks = [] 723 - then [] 724 - else Api.blocks_of_nestable_elements caption_blocks) 725 - @ [ raw_block (caption_closing ^ "</figure>") ] 717 + let full_html = 718 + Printf.sprintf {|<figure class="%s">%s%s</figure>|} 719 + (escape cls) img_html caption_html 726 720 in 727 721 { 728 - Api.content = blocks; 722 + Api.content = [ raw_block full_html ]; 729 723 overrides = []; 730 724 resources = [ Api.Css_inline figure_css ]; 731 725 assets = [];