Rendering a page

How a Markdown file becomes the HTML page a reader sees: comrak turns it into HTML with highlighted code, the title and sidebar are worked out, and the pieces go into the page frame. It is a mechanism page under the viewer, beside Serving pages, for someone about to change src/render.rs or src/highlight.rs.

flowchart LR
  md["page.md"] --> comrak["Markdown to HTML<br/>comrak"]
  comrak --> code["Code highlighted<br/>syntect"]
  code --> frame["The page frame"]
  title["Title"] --> frame
  side["Sidebar"] --> frame
  click comrak href "#markdown-to-html" "Markdown to HTML"
  click code href "#highlighted-code" "Highlighted code"
  click title href "#the-title-and-the-sidebar" "The title and the sidebar"
  click side href "#the-title-and-the-sidebar" "The title and the sidebar"
  click frame href "#the-page-frame" "The page frame"

A file ending in .md is read as text and passed to render::page, which does the four steps below.

Markdown to HTML

render::markdown runs comrak with these options (options() in src/render.rs):

Option Effect
extension.table GFM tables
extension.strikethrough ~~text~~
extension.autolink bare URLs become links
extension.tasklist - [ ] / - [x] items
extension.footnotes [^1] footnotes
extension.header_id_prefix = "" every heading gets an id from its text, with no prefix
render.unsafe raw HTML passes through
render.github_pre_lang a fence's language is passed as a lang attribute — which the highlighter below then drops for every block except mermaid

Last, every Markdown table is wrapped in <div class="table-scroll">, so a table wider than the page scrolls inside its own box instead of widening the page.

An image of a .design file — ![Checkout](checkout.design), or a raw <img src="checkout.design"> however its attributes are quoted, spaced or capitalised — becomes the design's embed (embed_designs): a <canvas class="design"> keeping the link in src and the image's text as its label, which the page script has the design engine draw. Any other image is left as it is.

Highlighted code

render::markdown also plugs in a code-fence highlighter, highlight::Highlighter in src/highlight.rs, through comrak's Plugins (SyntaxHighlighterAdapter). For each fenced block it:

The title and the sidebar

Title. render::title takes the first line starting with # , or the file name without its extension.

Sidebar. The navigation tree is built from the root page and rendered to nested lists, with the current page marked.

The page frame

The pieces go into one HTML page. A site's page, with a navbar and a sidebar, has this shape:

<html data-theme="light">
  <head>  <!-- icon, theme script, import map, stylesheet, pele, devpage.js -->
  <body class="site with-navbar">
    <header id="devpage-navbar">  <!-- logo, title, links, switches -->
    <nav id="devpage-nav">        <!-- the sidebar tree -->
    <main id="devpage-page">
      <article>                   <!-- the rendered Markdown -->

In detail:

Every id the frame uses starts with devpage- — devpage-page, devpage-nav, devpage-navbar, devpage-corner, devpage-comments and devpage-comments-toggle — and a heading whose text would give it one of them gets -heading added to its id. So a page can have a heading called Comments, Page or Navigation and it stays an ordinary heading, never styled or replaced as part of the frame.

devpage-navbar, devpage-nav and devpage-page are what live updates replace in place. A doc's and a deck's frames carry the same head — the logo's icon link and the theme script — and the theme corner. Titles and sidebar labels are HTML-escaped; the page body is not, since raw HTML is allowed.

Beyond the index, nothing is cached between requests: each page request re-reads the page, its site's document file and, to build the sidebar, every page the tree reaches.