Skip to content

feat: preserve and render widget messages in HTML output#817

Draft
alok wants to merge 3 commits intoleanprover:mainfrom
alok:feature/widget-messages
Draft

feat: preserve and render widget messages in HTML output#817
alok wants to merge 3 commits intoleanprover:mainfrom
alok:feature/widget-messages

Conversation

@alok
Copy link
Copy Markdown
Contributor

@alok alok commented Mar 31, 2026

Summary

Addresses #311 — preserves Lean user widget messages (MessageData.ofWidget) through the SubVerso → Verso pipeline instead of discarding them.

Before: (onWidget := fun _wi alt => convert alt) — widget instances thrown away, only alt text kept.
After: Widget javascriptHash + serialized props JSON flow through MessageContents.widget and are emitted as data attributes in HTML output.

Changes

SubVerso (alok/subverso@feature/widget-messages-rc6)

  • Add | widget (javascriptHash : Nat) (props : String) (alt : MessageContents expr) constructor to Highlighted.MessageContents
  • Change onWidget handler in Code.lean to evaluate widget props with an empty RpcObjectStore and store them (serializable widgets produce valid JSON; RPC-dependent widgets degrade to alt text)
  • Update Export types, Quote instance, toString, startAt, stopAt pattern matches

Verso (this PR)

  • Highlighted.lean (MessageContents.toHtml): Render .widget as <span class="widget-message" data-widget-hash="..." data-widget-props="..."> with alt text as visible content
  • HighlightedToTex.lean: Render .widget as its alt text (widgets are interactive-only)
  • External.lean: Add .widget case to findTrace?

How it works

When Lean code in a Verso document emits a widget message (e.g., a LeanPlot chart or ProofWidgets visualization):

  1. SubVerso captures the WidgetInstance during highlighting, evaluates its props to JSON, and stores (hash, props, alt) in MessageContents.widget
  2. Verso HTML renders the alt text as visible content, with the widget hash and props embedded as data-* attributes
  3. Future JS can discover [data-widget-hash] elements, fetch the widget module source by hash, and hydrate them with React

Remaining work for full interactive rendering

Per the discussion in #311, complete widget rendering requires:

  • Bundle React + @leanprover/infoview in generated HTML pages
  • Implement infoview "shim mode" where server-dependent functions fail gracefully
  • JS bootstrap to discover [data-widget-hash] elements, dynamically import widget modules by hash, and render React components with the serialized props
  • Mechanism to retrieve widget module JS source (either bundled at build time or fetched from a known location)
  • Opt-in mechanism for widgets to declare they are useful in non-interactive contexts (per David's suggestion)

Test plan

  • lake build passes for SubVerso (56/56 jobs)
  • lake build passes for Verso (470/470 jobs)
  • Verify widget data flows through by creating a Verso doc with a widget-producing #eval and inspecting the HTML output for data-widget-hash attributes

🤖 Generated with Claude Code

alok and others added 3 commits March 30, 2026 21:16
Adds a new `Block.figure` block extension and `:::figure` directive
to the Manual genre, enabling authors to embed images with optional
captions in Verso documents.

Directive syntax:
  :::figure "path/to/image.png" (alt := "description")
  Optional caption text rendered in <figcaption>.
  :::

- HTML output: <figure class="verso-figure"><img/><figcaption/></figure>
- LaTeX output: figure environment with \includegraphics + \caption{}
- Adds \usepackage{graphicx} to the LaTeX preamble automatically
- Responsive CSS: max-width 100%, centered, styled figcaption
- alt argument optional (defaults to ""), src is positional

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Preserve and render Lean user widget messages (MessageData.ofWidget)
in Verso HTML output instead of discarding them.

SubVerso changes (alok/subverso@feature/widget-messages-rc6):
- Add `widget` constructor to `MessageContents` storing the widget
  module's `javascriptHash`, serialized `props` JSON, and `alt` text
- Change `onWidget` handler to evaluate widget props with an empty
  RPC object store and preserve them (instead of discarding)

Verso changes:
- HTML: render `.widget` as `<span class="widget-message">` with
  `data-widget-hash` and `data-widget-props` attributes, falling
  back to the alt text content. This enables future JS hydration
  with @leanprover/infoview in shim mode.
- TeX: render `.widget` as its alt text (widgets are interactive)
- Update all pattern matches for the new `MessageContents.widget`

Remaining work for full interactive widget rendering:
- Bundle React and @leanprover/infoview JS in generated HTML
- Implement infoview "shim mode" (server calls fail gracefully)
- JS to discover `[data-widget-hash]` elements and hydrate them

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant