Skip to content

Add DiagramRenderer service for inline fenced-diagram rendering#92

Open
ChristineTham wants to merge 2 commits into
nodes-app:mainfrom
ChristineTham:pr/diagram-renderer
Open

Add DiagramRenderer service for inline fenced-diagram rendering#92
ChristineTham wants to merge 2 commits into
nodes-app:mainfrom
ChristineTham:pr/diagram-renderer

Conversation

@ChristineTham

Copy link
Copy Markdown

What

Adds a DiagramRenderer service protocol (mirroring LatexRenderer) plus a diagrams slot in MarkdownEditorServices, and a styleDiagramBlocks pass that intercepts standalone fenced code blocks whose info string a renderer claims (e.g. ```mermaid) and draws the returned image in place of the source via the existing appendRenderedStandaloneBlock machinery.

  • Moving the caret into the block reveals the raw source for editing; leaving re-renders.
  • The code-block background is cleared so no filled box shows behind the diagram.
  • render receives isDarkMode (resolved from the text view's effective appearance, like rendered tables) so renderers can match light/dark.
  • Diagrams wider than the reading column route through the existing .collapsedSourceScrollable overlay instead of overflowing.

Defaults to a NoOpDiagramRenderer, so existing embedders are unaffected. Same structural pattern as block LaTeX — the host supplies the image (e.g. via a Mermaid renderer).

Context: extracted from the ChristineTham/swift-markdown-engine fork used by HelloNotes.

ChristineTham and others added 2 commits July 11, 2026 19:00
Introduces a `DiagramRenderer` protocol (mirroring `LatexRenderer`) plus a
`diagrams` slot in `MarkdownEditorServices`, and a `styleDiagramBlocks` pass
that intercepts standalone fenced code blocks whose info string a renderer
claims (e.g. ```mermaid) and draws the returned image in place of the source
via the existing `appendRenderedStandaloneBlock` machinery. Moving the caret
into the block reveals the raw source for editing; the code background is
cleared so no filled box shows behind the diagram.

Defaults to a NoOpDiagramRenderer, so existing embedders are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`DiagramRenderer.render` now receives `isDarkMode` (resolved from the text
view's effective appearance, like rendered tables) so renderers can match
light/dark. `styleDiagramBlocks` also measures the reading column and routes
diagrams wider than it through the existing `.collapsedSourceScrollable`
overlay (with a stable per-occurrence sourceID) instead of letting them
overflow the text view.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 11, 2026 09:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class inline rendering support for fenced “diagram” code blocks (e.g. mermaid … ) by introducing a DiagramRenderer service and a new styling pass that replaces standalone fenced blocks with rendered images when the caret is outside the block.

Changes:

  • Introduces DiagramRenderer / DiagramRenderResult plus a default NoOpDiagramRenderer.
  • Extends MarkdownEditorServices with a diagrams slot (defaulting to no-op).
  • Adds styleDiagramBlocks to render eligible fenced code blocks as images (including wide-diagram scrollable overlay support).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
Sources/MarkdownEngine/Styling/MarkdownStyler+Diagrams.swift New styling pass that detects standalone fenced code blocks, renders diagrams, and emits collapsed-source image blocks (with scrollable mode for wide diagrams).
Sources/MarkdownEngine/Styling/MarkdownStyler.swift Hooks the diagram styling pass into the overall styling pipeline.
Sources/MarkdownEngine/Services/MarkdownEditorServices.swift Adds the DiagramRenderer API and wires it into editor services with a no-op default.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +72
let mode: RenderedStandaloneBlockMode
if result.size.width > containerWidth + 0.5 {
let occurrence = occurrenceBySource[source, default: 0]
occurrenceBySource[source] = occurrence + 1
mode = .collapsedSourceScrollable(
markerTexts: markerTexts,
displayWidth: containerWidth,
sourceID: diagramSourceID(for: source, occurrence: occurrence)
)
} else {
mode = .collapsedSource(markerTexts: markerTexts)
}
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.

2 participants