Commit bd35f9fd34
Unsigned
Layout: unified · split
.gitignore added +1
| @@ -0,0 +1 @@ | ||
| 1 | .orgo-cache.json | |
favicon.svg added +14
| @@ -0,0 +1,14 @@ | ||
| 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> | |
| 2 | <!-- An org outline: three headings, indented. Drawn plainly enough to survive 16px, | |
| 3 | and coloured from the same accent the stylesheet uses, in both schemes. --> | |
| 4 | <style> | |
| 5 | :root { fill: #0b5fa5; } | |
| 6 | @media (prefers-color-scheme: dark) { :root { fill: #79b8ff; } } | |
| 7 | </style> | |
| 8 | <circle cx="6" cy="8" r="2.5"/> | |
| 9 | <rect x="12" y="6.5" width="14" height="3" rx="1.5"/> | |
| 10 | <circle cx="12" cy="16" r="2.5"/> | |
| 11 | <rect x="18" y="14.5" width="8" height="3" rx="1.5"/> | |
| 12 | <circle cx="12" cy="24" r="2.5"/> | |
| 13 | <rect x="18" y="22.5" width="8" height="3" rx="1.5"/> | |
| 14 | </svg> | |
guide/01-cli.html added +115
| @@ -0,0 +1,115 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Command reference · orgo</title> | |
| 7 | <meta name="description" content="Every command and flag, and what each is actually for."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Command reference</h1> | |
| 24 | <p class="lede">Six commands: build, serve, watch, audit, init, clean.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#the-two-paths">The two paths</a></li> | |
| 29 | <li><a href="#build">build</a> | |
| 30 | <ul> | |
| 31 | <li><a href="#strict-is-for-ci">--strict is for CI</a></li> | |
| 32 | </ul></li> | |
| 33 | <li><a href="#serve">serve</a></li> | |
| 34 | <li><a href="#watch">watch</a></li> | |
| 35 | <li><a href="#audit">audit</a></li> | |
| 36 | <li><a href="#init">init</a></li> | |
| 37 | <li><a href="#clean">clean</a></li> | |
| 38 | <li><a href="#exit-codes">Exit codes</a></li> | |
| 39 | </ul> | |
| 40 | </nav> | |
| 41 | <h2 id="the-two-paths">The two paths</h2> | |
| 42 | <p><code class="verbatim">build</code>, <code class="verbatim">serve</code> and <code class="verbatim">watch</code> all take the same pair:</p> | |
| 43 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> <span class="keyword operator assignment redirection shell"><</span>command<span class="keyword operator assignment redirection shell">></span> <span class="keyword operator assignment redirection shell"><</span>SOURCE<span class="keyword operator assignment redirection shell">></span> <span class="punctuation terminator file-descriptor shell">-</span>o <span class="keyword operator assignment redirection shell"><</span>OUTPUT<span class="keyword operator assignment redirection shell">></span></span></span></code></pre> | |
| 44 | <p><strong>SOURCE is the URL root</strong>, not "the project". <code class="verbatim">SOURCE/blog/post.org</code> is published at <code class="verbatim">/blog/post.html</code>, so if your writing lives in a <code class="verbatim">content/</code> subdirectory you point at <code class="verbatim">content/</code> and not at the repository around it. Choosing the directory above the one you meant still builds — it just prefixes every URL with that directory's name and copies your build scripts in as assets. <a href="../quickstart.html">Quick start</a> works through it.</p> | |
| 45 | <p><strong>OUTPUT</strong> may live inside the source; it is recognised and skipped, so a build never consumes its own output.</p> | |
| 46 | <h2 id="build">build</h2> | |
| 47 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build <span class="keyword operator assignment redirection shell"><</span>INPUT<span class="keyword operator assignment redirection shell">></span> <span class="punctuation terminator file-descriptor shell">-</span>o <span class="keyword operator assignment redirection shell"><</span>OUTPUT<span class="keyword operator assignment redirection shell">></span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>no<span class="keyword operator word shell">-</span>cache<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>strict<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>drafts<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>config FILE<span class="keyword control regexp set end shell">]</span></span></span></code></pre> | |
| 48 | <p>If <code class="verbatim">INPUT</code> is a directory, it is walked and built into a linked site at <code class="verbatim">OUTPUT</code>. If it is a single <code class="verbatim">.org</code> file, one HTML file is written — useful for one-off conversions, though with no other documents to resolve against, internal links keep a best-effort URL.</p> | |
| 49 | <table> | |
| 50 | <thead> | |
| 51 | <tr><th>Flag</th><th>Effect</th></tr> | |
| 52 | </thead> | |
| 53 | <tbody> | |
| 54 | <tr><td><code class="verbatim">-o, --output</code></td><td>Output directory (or <code class="verbatim">.html</code> file for single-file input). Required for a site.</td></tr> | |
| 55 | <tr><td><code class="verbatim">--no-cache</code></td><td>Ignore the incremental cache and re-render every page.</td></tr> | |
| 56 | <tr><td><code class="verbatim">--strict</code></td><td>Broken internal links and parse diagnostics become a non-zero exit.</td></tr> | |
| 57 | <tr><td><code class="verbatim">--drafts</code></td><td>Include pages marked <code class="verbatim">#+DRAFT:</code>.</td></tr> | |
| 58 | <tr><td><code class="verbatim">--config FILE</code></td><td>Use this config instead of <code class="verbatim">orgo.toml</code> in the source directory.</td></tr> | |
| 59 | </tbody> | |
| 60 | </table> | |
| 61 | <p>The summary line reports what happened:</p> | |
| 62 | <pre>built 182 page(s) (4 rendered, 178 cached), copied 3 asset(s) from src -> _site (0 unresolved link(s), 0 diagnostic(s))</pre> | |
| 63 | <p><code class="verbatim">rendered</code> is the invalidation set — the pages that actually needed rewriting. On a second build with nothing changed it is zero.</p> | |
| 64 | <h3 id="strict-is-for-ci">–strict is for CI</h3> | |
| 65 | <p>Without it, a broken link is a warning and the build succeeds. With it, the build fails and names every problem. Use it wherever a bad build should not ship:</p> | |
| 66 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span></span></code></pre> | |
| 67 | <h2 id="serve">serve</h2> | |
| 68 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve <span class="keyword operator assignment redirection shell"><</span>INPUT<span class="keyword operator assignment redirection shell">></span> <span class="punctuation terminator file-descriptor shell">-</span>o <span class="keyword operator assignment redirection shell"><</span>OUTPUT<span class="keyword operator assignment redirection shell">></span> <span class="keyword control regexp set begin shell">[</span>-p PORT<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>host HOST<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>drafts<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>config FILE<span class="keyword control regexp set end shell">]</span></span></span></code></pre> | |
| 69 | <p>Builds, watches, serves, and reloads the browser when a rebuild lands. This is the command to use while writing.</p> | |
| 70 | <table> | |
| 71 | <thead> | |
| 72 | <tr><th>Flag</th><th>Default</th><th>Effect</th></tr> | |
| 73 | </thead> | |
| 74 | <tbody> | |
| 75 | <tr><td><code class="verbatim">-p, --port</code></td><td><code class="verbatim">3000</code></td><td>Port to listen on.</td></tr> | |
| 76 | <tr><td><code class="verbatim">--host</code></td><td><code class="verbatim">127.0.0.1</code></td><td>Address to bind.</td></tr> | |
| 77 | <tr><td><code class="verbatim">--drafts</code></td><td>off</td><td>Include <code class="verbatim">#+DRAFT:</code> pages, so you can see what you are writing.</td></tr> | |
| 78 | </tbody> | |
| 79 | </table> | |
| 80 | <p><strong>It binds loopback on purpose.</strong> A development server serves unreviewed drafts off your laptop, so reaching the local network is something you ask for:</p> | |
| 81 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>host</span> 0.0.0.0</span></span></code></pre> | |
| 82 | <p>The live-reload script is injected into responses and never written to disk, so what you deploy stays clean. Details in <a href="08-workflow.html">Watching and serving</a>.</p> | |
| 83 | <h2 id="watch">watch</h2> | |
| 84 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> watch <span class="keyword operator assignment redirection shell"><</span>INPUT<span class="keyword operator assignment redirection shell">></span> <span class="punctuation terminator file-descriptor shell">-</span>o <span class="keyword operator assignment redirection shell"><</span>OUTPUT<span class="keyword operator assignment redirection shell">></span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>no<span class="keyword operator word shell">-</span>cache<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>strict<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>drafts<span class="keyword control regexp set end shell">]</span> <span class="keyword control regexp set begin shell">[</span>-<span class="keyword operator word shell">-</span>config FILE<span class="keyword control regexp set end shell">]</span></span></span></code></pre> | |
| 85 | <p>Rebuilds on filesystem events with no server — for when something else is already serving the output, or you just want the build to keep up as you write.</p> | |
| 86 | <h2 id="audit">audit</h2> | |
| 87 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> audit <span class="keyword operator assignment redirection shell"><</span>INPUT<span class="keyword operator assignment redirection shell">></span></span></span></code></pre> | |
| 88 | <p>Reports which org constructs a corpus uses and how they land against what orgo supports, plus a census of every keyword, block type, drawer and link scheme seen. Point it at your notes before trusting a tool with them. See <a href="09-auditing.html">Auditing a corpus</a>.</p> | |
| 89 | <p>It prints names, counts and <code class="verbatim">file:line</code> locations — never document text — so an audit of private notes is safe to share.</p> | |
| 90 | <h2 id="init">init</h2> | |
| 91 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> init <span class="keyword control regexp set begin shell">[</span>DIRECTORY<span class="keyword control regexp set end shell">]</span></span></span></code></pre> | |
| 92 | <p>Scaffolds a working site: a fully commented config, an editable copy of the built-in layout, listing and tag templates, an RSS template, a home page and a first post. Defaults to the current directory.</p> | |
| 93 | <p>Only files that do not already exist are written, so it is safe to run inside a directory that already has content — it fills in what is missing and leaves the rest alone.</p> | |
| 94 | <h2 id="clean">clean</h2> | |
| 95 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> clean <span class="keyword operator assignment redirection shell"><</span>OUTPUT<span class="keyword operator assignment redirection shell">></span></span></span></code></pre> | |
| 96 | <p>Removes the output directory, including the incremental cache manifest inside it. You rarely need this: the cache is versioned and discards itself when it stops being valid.</p> | |
| 97 | <h2 id="exit-codes">Exit codes</h2> | |
| 98 | <table> | |
| 99 | <thead> | |
| 100 | <tr><th>Code</th><th>Meaning</th></tr> | |
| 101 | </thead> | |
| 102 | <tbody> | |
| 103 | <tr><td><code class="verbatim">0</code></td><td>Success. Warnings may still have been printed.</td></tr> | |
| 104 | <tr><td><code class="verbatim">1</code></td><td>The build failed, or <code class="verbatim">--strict</code> found problems.</td></tr> | |
| 105 | </tbody> | |
| 106 | </table> | |
| 107 | <p>Diagnostics are printed as <code class="verbatim">file:line: message</code>, the form an editor can jump to:</p> | |
| 108 | <pre>warning: blog/post.org:42: unterminated `#+BEGIN_SRC` block (no `#+END_SRC`); everything to the end of the file was read as block content | |
| 109 | warning: index.org: unresolved link [[#setup]]</pre> | |
| 110 | </main> | |
| 111 | <footer class="site"> | |
| 112 | Built with orgo — these docs are an orgo site. | |
| 113 | </footer> | |
| 114 | </body> | |
| 115 | </html> | |
| \ No newline at end of file | ||
guide/02-configuration.html added +265
| @@ -0,0 +1,265 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Configuration · orgo</title> | |
| 7 | <meta name="description" content="Every setting in orgo.toml, what it changes, and what it costs."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Configuration</h1> | |
| 24 | <p class="lede">All of it optional. A missing config is a valid config.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#the-whole-file">The whole file</a></li> | |
| 29 | <li><a href="#site">[site]</a> | |
| 30 | <ul> | |
| 31 | <li><a href="#theme">theme</a></li> | |
| 32 | <li><a href="#base-url">base_url</a></li> | |
| 33 | </ul></li> | |
| 34 | <li><a href="#nav">[nav]</a> | |
| 35 | <ul> | |
| 36 | <li><a href="#explicit">explicit</a></li> | |
| 37 | <li><a href="#section-landing-pages-in-the-nav">Section landing pages in the nav</a></li> | |
| 38 | </ul></li> | |
| 39 | <li><a href="#"></a> | |
| 40 | <ul> | |
| 41 | <li><a href="#which-rule-wins">Which rule wins</a></li> | |
| 42 | </ul></li> | |
| 43 | <li><a href="#templates">[templates]</a> | |
| 44 | <ul> | |
| 45 | <li><a href="#expose-page-list-costs-incremental-precision">expose_page_list costs incremental precision</a></li> | |
| 46 | </ul></li> | |
| 47 | <li><a href="#highlight">[highlight]</a></li> | |
| 48 | <li><a href="#build">[build]</a> | |
| 49 | <ul> | |
| 50 | <li><a href="#sitemap-xml">sitemap.xml</a></li> | |
| 51 | <li><a href="#static-files-that-live-elsewhere">Static files that live elsewhere</a></li> | |
| 52 | </ul></li> | |
| 53 | <li><a href="#html">[html]</a> | |
| 54 | <ul> | |
| 55 | <li><a href="#heading-offset">heading_offset</a></li> | |
| 56 | <li><a href="#section-numbers-differs-from-emacs-on-purpose">section_numbers differs from Emacs on purpose</a></li> | |
| 57 | </ul></li> | |
| 58 | <li><a href="#per-file-overrides">Per-file overrides</a></li> | |
| 59 | <li><a href="#configuration-is-a-cache-input">Configuration is a cache input</a></li> | |
| 60 | </ul> | |
| 61 | </nav> | |
| 62 | <p>orgo looks for <code class="verbatim">orgo.toml</code> in the source directory. Pass a different path with <code class="verbatim">--config</code>. Every field has a default, so a directory of org files with no config still builds a complete site.</p> | |
| 63 | <p>A <strong>missing</strong> config is normal and silent. A <strong>malformed</strong> one is an error, and an unknown key is rejected by name — a misspelled setting that silently does nothing is how people lose an afternoon.</p> | |
| 64 | <h2 id="the-whole-file">The whole file</h2> | |
| 65 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table toml">[</span><span class="entity name section toml">site</span><span class="punctuation definition table toml">]</span> | |
| 66 | <span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>orgo site<span class="punctuation definition string end toml">"</span></span> | |
| 67 | <span class="variable other key toml">base_url</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span><span class="punctuation definition string end toml">"</span></span> | |
| 68 | <span class="variable other key toml">description</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span><span class="punctuation definition string end toml">"</span></span> | |
| 69 | <span class="variable other key toml">language</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>en<span class="punctuation definition string end toml">"</span></span> | |
| 70 | <span class="variable other key toml">theme</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span><span class="punctuation definition string end toml">"</span></span> | |
| 71 | ||
| 72 | <span class="punctuation definition table toml">[</span><span class="entity name section toml">nav</span><span class="punctuation definition table toml">]</span> | |
| 73 | <span class="variable other key toml">mode</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>top-level<span class="punctuation definition string end toml">"</span></span> | |
| 74 | <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> pages = ["index.org", "about.org"] | |
| 75 | </span> | |
| 76 | <span class="punctuation definition table toml">[</span><span class="entity name section toml">templates</span><span class="punctuation definition table toml">]</span> | |
| 77 | <span class="variable other key toml">dir</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>templates<span class="punctuation definition string end toml">"</span></span> | |
| 78 | <span class="variable other key toml">expose_page_list</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">false</span> | |
| 79 | ||
| 80 | <span class="punctuation definition table toml">[</span><span class="entity name section toml">highlight</span><span class="punctuation definition table toml">]</span> | |
| 81 | <span class="variable other key toml">theme</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>InspiredGitHub<span class="punctuation definition string end toml">"</span></span> | |
| 82 | <span class="variable other key toml">theme_dark</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span><span class="punctuation definition string end toml">"</span></span> | |
| 83 | <span class="variable other key toml">syntaxes_dir</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>syntaxes<span class="punctuation definition string end toml">"</span></span> | |
| 84 | ||
| 85 | <span class="punctuation definition table toml">[</span><span class="entity name section toml">build</span><span class="punctuation definition table toml">]</span> | |
| 86 | <span class="variable other key toml">drafts</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">false</span> | |
| 87 | <span class="variable other key toml">assets</span> <span class="keyword operator assignment toml">=</span> [] | |
| 88 | <span class="variable other key toml">sitemap</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span> | |
| 89 | ||
| 90 | <span class="punctuation definition table toml">[</span><span class="entity name section toml">html</span><span class="punctuation definition table toml">]</span> | |
| 91 | <span class="variable other key toml">heading_offset</span> <span class="keyword operator assignment toml">=</span> <span class="constant numeric toml">1</span> | |
| 92 | <span class="variable other key toml">toc</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span> | |
| 93 | <span class="variable other key toml">section_numbers</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">false</span></span></code></pre> | |
| 94 | <p>Plus any number of <code class="verbatim">[[collections]]</code> blocks, documented in <a href="03-collections.html">Collections</a>.</p> | |
| 95 | <h2 id="site">[site]</h2> | |
| 96 | <table> | |
| 97 | <thead> | |
| 98 | <tr><th>Key</th><th>Default</th><th>Meaning</th></tr> | |
| 99 | </thead> | |
| 100 | <tbody> | |
| 101 | <tr><td><code class="verbatim">title</code></td><td><code class="verbatim">"orgo site"</code></td><td>Site name. Available as <code class="verbatim">{{ site.title }}</code>.</td></tr> | |
| 102 | <tr><td><code class="verbatim">base_url</code></td><td>=""</td><td>Absolute origin, <strong>no trailing slash</strong>.</td></tr> | |
| 103 | <tr><td><code class="verbatim">description</code></td><td>=""</td><td>Available as <code class="verbatim">{{ site.description }}</code>.</td></tr> | |
| 104 | <tr><td><code class="verbatim">language</code></td><td><code class="verbatim">"en"</code></td><td>Goes in <code class="verbatim"><html lang></code> in the built-in layout.</td></tr> | |
| 105 | <tr><td><code class="verbatim">theme</code></td><td>=""</td><td>A built-in stylesheet, written to the output as <code class="verbatim">theme.css</code>.</td></tr> | |
| 106 | </tbody> | |
| 107 | </table> | |
| 108 | <h3 id="theme">theme</h3> | |
| 109 | <p>Four themes are compiled into the binary. Name one and each build writes it to the output root as <code class="verbatim">theme.css</code>, which the built-in layout and the templates <code class="verbatim">orgo init</code> writes both link.</p> | |
| 110 | <table> | |
| 111 | <thead> | |
| 112 | <tr><th>Theme</th><th>Shape</th><th>For</th></tr> | |
| 113 | </thead> | |
| 114 | <tbody> | |
| 115 | <tr><td><code class="verbatim">"plain"</code></td><td>Narrow, system fonts, hairline rules.</td><td>Readable defaults to build your own CSS on.</td></tr> | |
| 116 | <tr><td><code class="verbatim">"blog"</code></td><td>Serif prose, a centred masthead, styled post lists.</td><td>Dated writing.</td></tr> | |
| 117 | <tr><td><code class="verbatim">"wiki"</code></td><td>Wide and dense, contents in the margin, TODO states as badges.</td><td>Notes, a reference site.</td></tr> | |
| 118 | <tr><td><code class="verbatim">"docs"</code></td><td>Narrow, a contents card, quote blocks as notes, <code class="verbatim">#+LEDE:</code>.</td><td>A guide read in order.</td></tr> | |
| 119 | </tbody> | |
| 120 | </table> | |
| 121 | <p>All four follow <code class="verbatim">prefers-color-scheme</code>, so a site gets a dark mode without a toggle, a setting or a line of JavaScript — and all four reflow from a 320px phone up, with tables and code blocks scrolling inside their own box rather than widening the page.</p> | |
| 122 | <p>The default is empty: no stylesheet is written and no page links one, so the output is unstyled HTML. That is deliberate — a site that already ships CSS of its own should not find a second stylesheet competing with it, and upgrading orgo should never restyle a site. An unknown name is an error listing the four.</p> | |
| 123 | <p>A theme styles the markup orgo already emits — headings, tags, TODO keywords, checkbox lists, footnotes, tables — plus the chrome the built-in layout puts around it. There is no theme-specific HTML, so switching or removing one touches no template.</p> | |
| 124 | <p>Every colour is a custom property on <code class="verbatim">:root</code>, named <code class="verbatim">--orgo-*</code>. To adjust rather than replace a theme, ship a stylesheet of your own as an asset, link it after <code class="verbatim">theme.css</code>, and redefine the handful you care about:</p> | |
| 125 | <pre><code class="language-css highlight"><span class="source css"><span class="meta selector css"><span class="entity other pseudo-class css"><span class="punctuation definition entity css">:</span>root</span> </span><span class="meta property-list css"><span class="punctuation section property-list css">{</span> | |
| 126 | <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">orgo-accent</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant other color rgb-value css"><span class="punctuation definition constant css">#</span>7a1fa2</span></span><span class="punctuation terminator rule css">;</span> | |
| 127 | <span class="meta property-name css"><span class="support type custom-property css"><span class="punctuation definition custom-property css">--</span><span class="support type custom-property name css">orgo-measure</span></span></span><span class="punctuation separator key-value css">:</span><span class="meta property-value css"> </span><span class="meta property-value css"><span class="constant numeric css">46<span class="keyword other unit css">rem</span></span></span><span class="punctuation terminator rule css">;</span> | |
| 128 | </span><span class="punctuation section property-list css">}</span></span></code></pre> | |
| 129 | <p>Code <em>blocks</em> are the one part a built-in theme leaves light in dark mode: <code class="verbatim">syntax.css</code> is coloured by <code class="verbatim">highlight.theme</code>, and that default is a light theme. Two pieces make a block follow <code class="verbatim">prefers-color-scheme</code> — <code class="verbatim">highlight.theme_dark</code> for the tokens, and <code class="verbatim">--orgo-code-bg</code>, <code class="verbatim">--orgo-code-fg</code> and <code class="verbatim">--orgo-code-rule</code> for the surface under them. Set both, or neither and blocks stay light in both schemes. Those three properties colour blocks only — inline <code class="verbatim">~code~</code> follows the page's own scheme, so it stays legible whichever highlight theme you use. The documentation site keeps a dark surface in both schemes instead; its <code class="verbatim">style.css</code> is those three lines and nothing else.</p> | |
| 130 | <p>When you outgrow a theme, drop <code class="verbatim">theme</code> from the config and write <code class="verbatim">templates/base.html</code> against your own CSS. Nothing else changes.</p> | |
| 131 | <h3 id="base-url">base<sub>url</sub></h3> | |
| 132 | <p>Leave it empty and the site is built entirely with relative URLs, which means it works from a subdirectory, from a filesystem path, and from any origin. That portability is why it is the default.</p> | |
| 133 | <p>Set it when you need absolute URLs, which two things require: <strong>feeds</strong>, because a feed is read away from the site that served it, and <strong>canonical links</strong>. The <code class="verbatim">absolute</code> template filter turns a site-root-relative path into a full URL, and errors if there is no base URL to build one from — rather than quietly emitting a relative URL that would make the feed invalid everywhere while looking fine.</p> | |
| 134 | <p>A trailing slash is rejected, because <code class="verbatim">https://example.com/</code> plus <code class="verbatim">blog/x.html</code> is <code class="verbatim">https://example.com//blog/x.html</code>.</p> | |
| 135 | <h2 id="nav">[nav]</h2> | |
| 136 | <p>The navigation shared by every page.</p> | |
| 137 | <table> | |
| 138 | <thead> | |
| 139 | <tr><th><code class="verbatim">mode</code></th><th>Includes</th></tr> | |
| 140 | </thead> | |
| 141 | <tbody> | |
| 142 | <tr><td><code class="verbatim">"top-level"</code> (default)</td><td>Pages at the site root.</td></tr> | |
| 143 | <tr><td><code class="verbatim">"all"</code></td><td>Every page.</td></tr> | |
| 144 | <tr><td><code class="verbatim">"explicit"</code></td><td>Only <code class="verbatim">nav.pages</code>, in the order listed.</td></tr> | |
| 145 | <tr><td><code class="verbatim">"none"</code></td><td>Nothing.</td></tr> | |
| 146 | </tbody> | |
| 147 | </table> | |
| 148 | <p><strong>"all" makes output quadratic.</strong> Each of <em>n</em> pages carries <em>n</em> links, so total output grows with the square of the site. On a 1,790-page site that was 284 MB of mostly navigation. It is fine for a handful of pages and a trap beyond that.</p> | |
| 149 | <p><code class="verbatim">"top-level"</code> keeps the nav a map of the site's top level rather than an index of its contents, so nav size does not depend on how much you write.</p> | |
| 150 | <h3 id="explicit">explicit</h3> | |
| 151 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table toml">[</span><span class="entity name section toml">nav</span><span class="punctuation definition table toml">]</span> | |
| 152 | <span class="variable other key toml">mode</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>explicit<span class="punctuation definition string end toml">"</span></span> | |
| 153 | <span class="variable other key toml">pages</span> <span class="keyword operator assignment toml">=</span> [<span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>index.org<span class="punctuation definition string end toml">"</span></span>, <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>about.org<span class="punctuation definition string end toml">"</span></span>, <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>uses.org<span class="punctuation definition string end toml">"</span></span>]</span></code></pre> | |
| 154 | <p>Paths are <strong>source</strong> paths relative to the source root, and the order given is the order rendered — a hand-written nav is a designed sequence, not an alphabetical one. Naming a page that does not exist is an error, because a silently shorter nav is a poor way to learn about a typo.</p> | |
| 155 | <h3 id="section-landing-pages-in-the-nav">Section landing pages in the nav</h3> | |
| 156 | <p>If your sections live in subdirectories, none of them are top-level pages. Put the section's <strong>generated</strong> index in the nav instead, with <code class="verbatim">nav = true</code> on its collection — that is the page a nav entry should point at anyway.</p> | |
| 157 | <p>A generated page has no source file, so name it in <code class="verbatim">pages</code> by its <strong>output</strong> path:</p> | |
| 158 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table toml">[</span><span class="entity name section toml">nav</span><span class="punctuation definition table toml">]</span> | |
| 159 | <span class="variable other key toml">mode</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>explicit<span class="punctuation definition string end toml">"</span></span> | |
| 160 | <span class="variable other key toml">pages</span> <span class="keyword operator assignment toml">=</span> [<span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog/index.html<span class="punctuation definition string end toml">"</span></span>, <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>garden/index.html<span class="punctuation definition string end toml">"</span></span>, <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>about.org<span class="punctuation definition string end toml">"</span></span>]</span></code></pre> | |
| 161 | <p>That is the only way to interleave the two: a collection that sets <code class="verbatim">nav = true</code> without being listed is appended after everything you did list, so <code class="verbatim">"about.org"</code> alone would put <code class="verbatim">About</code> first and the sections after it. Listing all of them puts each exactly where you said. Either spelling works for an authored page too — its source path or its output path — though the source path is the one that survives a <code class="verbatim">#+SLUG:</code>.</p> | |
| 162 | <h2><a href="pages">pages</a></h2> | |
| 163 | <p>Which layout a page renders through. Without any of these, every authored page uses <code class="verbatim">base.html</code>.</p> | |
| 164 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">pages</span><span class="punctuation definition table array toml">]]</span> | |
| 165 | <span class="variable other key toml">match</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> | |
| 166 | <span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>post.html<span class="punctuation definition string end toml">"</span></span></span></code></pre> | |
| 167 | <p><code class="verbatim">match</code> is a <strong>source</strong> path relative to the source root — a directory, covering every page beneath it however deep, or one <code class="verbatim">.org</code> file. It is matched by path component, so <code class="verbatim">blog</code> covers <code class="verbatim">blog/2026/post.org</code> and does not touch <code class="verbatim">blogroll.org</code>.</p> | |
| 168 | <p>A section's layout is a property of the section, which is why this is a rule and not something you write in each file: a blog post carries the same byline and reply footer as every other one, and repeating that in 200 files means maintaining one fact 200 times.</p> | |
| 169 | <h3 id="which-rule-wins">Which rule wins</h3> | |
| 170 | <p>Most specific, by path depth — <code class="verbatim">blog/notes</code> beats <code class="verbatim">blog</code>, whatever order they appear in. An empty <code class="verbatim">match</code> covers the whole site, which is how you rename the default layout.</p> | |
| 171 | <p>A page that differs from its section says so itself, and that wins over any rule:</p> | |
| 172 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+TITLE:</span><span class="string unquoted org"> Colophon</span> | |
| 173 | <span class="keyword other keyword org">#+TEMPLATE:</span><span class="string unquoted org"> wide.html</span></span></code></pre> | |
| 174 | <p>Naming a template that is not in the templates directory is an error that names the page, the template and what does exist — a layout typo should not be a hunt.</p> | |
| 175 | <h2 id="templates">[templates]</h2> | |
| 176 | <table> | |
| 177 | <thead> | |
| 178 | <tr><th>Key</th><th>Default</th><th>Meaning</th></tr> | |
| 179 | </thead> | |
| 180 | <tbody> | |
| 181 | <tr><td><code class="verbatim">dir</code></td><td><code class="verbatim">"templates"</code></td><td>Directory of templates, relative to the source root.</td></tr> | |
| 182 | <tr><td><code class="verbatim">expose_page_list</code></td><td><code class="verbatim">false</code></td><td>Give every template a <code class="verbatim">pages</code> list of all page metadata.</td></tr> | |
| 183 | </tbody> | |
| 184 | </table> | |
| 185 | <h3 id="expose-page-list-costs-incremental-precision">expose<sub>page</sub><sub>list</sub> costs incremental precision</h3> | |
| 186 | <p>With it on, any page can read every page's metadata — so adding one page can change any page's output, and the whole site must re-render on every add, rename or retitle. That is the trade for building an index by hand in a template. Most people want a <a href="03-collections.html">collection</a> instead, which gets the same result while keeping adding a post a one-page rebuild.</p> | |
| 187 | <h2 id="highlight">[highlight]</h2> | |
| 188 | <table> | |
| 189 | <thead> | |
| 190 | <tr><th>Key</th><th>Default</th><th>Meaning</th></tr> | |
| 191 | </thead> | |
| 192 | <tbody> | |
| 193 | <tr><td><code class="verbatim">theme</code></td><td><code class="verbatim">"InspiredGitHub"</code></td><td>A syntect theme name.</td></tr> | |
| 194 | <tr><td><code class="verbatim">theme_dark</code></td><td><code class="verbatim">""</code></td><td>A second theme for readers in dark mode.</td></tr> | |
| 195 | <tr><td><code class="verbatim">syntaxes_dir</code></td><td><code class="verbatim">"syntaxes"</code></td><td>Extra <code class="verbatim">.sublime-syntax</code> files.</td></tr> | |
| 196 | </tbody> | |
| 197 | </table> | |
| 198 | <p>Any theme syntect ships: <code class="verbatim">InspiredGitHub</code>, <code class="verbatim">Solarized (dark)</code>, <code class="verbatim">Solarized (light)</code>, <code class="verbatim">base16-ocean.dark</code>, <code class="verbatim">base16-ocean.light</code>, <code class="verbatim">base16-eighties.dark</code>, <code class="verbatim">base16-mocha.dark</code>. An unknown name is an error listing the valid ones.</p> | |
| 199 | <p><code class="verbatim">theme_dark</code> is off by default, and one theme colours every reader. Name a second one and <code class="verbatim">syntax.css</code> carries both, each behind the <code class="verbatim">prefers-color-scheme</code> query it belongs to, so a reader's system picks the colours — one stylesheet, no JavaScript, nothing extra for a layout to link:</p> | |
| 200 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table toml">[</span><span class="entity name section toml">highlight</span><span class="punctuation definition table toml">]</span> | |
| 201 | <span class="variable other key toml">theme</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>InspiredGitHub<span class="punctuation definition string end toml">"</span></span> | |
| 202 | <span class="variable other key toml">theme_dark</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>base16-ocean.dark<span class="punctuation definition string end toml">"</span></span></span></code></pre> | |
| 203 | <p>Only the token colours change with the scheme. The surface a block sits on is the page's, so give your dark mode a dark <code class="verbatim">pre</code> background — a dark theme's colours are chosen for one — with <code class="verbatim">--orgo-code-bg</code> under a built-in theme, or your own CSS.</p> | |
| 204 | <p>The two themes are separated rather than stacked because they name different scopes: a light theme's <code class="verbatim">.source.python .keyword</code> outranks a dark theme's <code class="verbatim">.keyword</code>, so appending one to the other would leave light colours on some tokens. The cost of the separation is that a browser too old to know <code class="verbatim">prefers-color-scheme</code> matches neither query and shows code unhighlighted. Leaving <code class="verbatim">theme_dark</code> empty keeps the unconditional rules of before.</p> | |
| 205 | <p>Highlighting emits <strong>CSS classes</strong>, never inline styles, so themes live in a stylesheet. Each build writes <code class="verbatim">syntax.css</code> into the output and every page links it.</p> | |
| 206 | <p>orgo bundles TOML and Org on top of syntect's built-in languages. Anything else missing is a file away: put a <code class="verbatim">.sublime-syntax</code> definition in <code class="verbatim">syntaxes_dir</code> and it is loaded. A definition that fails to parse is reported and skipped, because one bad file should not stop a site from building.</p> | |
| 207 | <h2 id="build">[build]</h2> | |
| 208 | <table> | |
| 209 | <thead> | |
| 210 | <tr><th>Key</th><th>Default</th><th>Meaning</th></tr> | |
| 211 | </thead> | |
| 212 | <tbody> | |
| 213 | <tr><td><code class="verbatim">drafts</code></td><td><code class="verbatim">false</code></td><td>Include pages marked <code class="verbatim">#+DRAFT:</code>.</td></tr> | |
| 214 | <tr><td><code class="verbatim">assets</code></td><td><code class="verbatim">[]</code></td><td>Extra directories copied to the <strong>site root</strong>.</td></tr> | |
| 215 | <tr><td><code class="verbatim">sitemap</code></td><td><code class="verbatim">true</code></td><td>Write <code class="verbatim">sitemap.xml</code>. Needs <code class="verbatim">site.base_url</code>.</td></tr> | |
| 216 | </tbody> | |
| 217 | </table> | |
| 218 | <p><code class="verbatim">--drafts</code> on the command line turns this on for one run. The flag can only turn drafts on; it never turns off a config that asked for them.</p> | |
| 219 | <h3 id="sitemap-xml">sitemap.xml</h3> | |
| 220 | <p>Every page the build emits, generated ones included — a crawler has no other way to learn that <code class="verbatim">/blog/</code> exists. <code class="verbatim">lastmod</code> is the page's own <code class="verbatim">#+DATE:</code> where it has one, and absent where it does not: a filesystem timestamp would say the day you cloned the repository.</p> | |
| 221 | <p><strong>Nothing is written until <code class="verbatim">site.base_url</code> is set.</strong> A sitemap has nowhere to put a relative URL, so a zero-config build produces no sitemap rather than an invalid one. Set a base URL and it appears; set <code class="verbatim">sitemap = false</code> and it does not.</p> | |
| 222 | <h3 id="static-files-that-live-elsewhere">Static files that live elsewhere</h3> | |
| 223 | <p>A site's static files do not always sit where its writing does. weblorg publishes <code class="verbatim">theme/static/</code> at <code class="verbatim">/</code>, and a repository migrating from it should not have to move <code class="verbatim">robots.txt</code> next to its blog posts to keep the URL:</p> | |
| 224 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table toml">[</span><span class="entity name section toml">build</span><span class="punctuation definition table toml">]</span> | |
| 225 | <span class="variable other key toml">assets</span> <span class="keyword operator assignment toml">=</span> [<span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>../theme/static<span class="punctuation definition string end toml">"</span></span>]</span></code></pre> | |
| 226 | <p>Paths are relative to the source root and may point outside it. Each directory's <strong>contents</strong> land at the site root — <code class="verbatim">theme/static/img/logo.svg</code> publishes at <code class="verbatim">/img/logo.svg</code>, not <code class="verbatim">/static/img/logo.svg</code>.</p> | |
| 227 | <p>Two files claiming one URL is a build error naming both, rather than a coin flip decided by directory order. A path that is not a directory is an error too, since it is a typo.</p> | |
| 228 | <p>Under <code class="verbatim">watch</code> and <code class="verbatim">serve</code> these directories are watched as well, so editing a stylesheet outside the source tree still reloads the page.</p> | |
| 229 | <h2 id="html">[html]</h2> | |
| 230 | <table> | |
| 231 | <thead> | |
| 232 | <tr><th>Key</th><th>Default</th><th>Meaning</th></tr> | |
| 233 | </thead> | |
| 234 | <tbody> | |
| 235 | <tr><td><code class="verbatim">heading_offset</code></td><td><code class="verbatim">1</code></td><td>Added to every org heading level.</td></tr> | |
| 236 | <tr><td><code class="verbatim">toc</code></td><td><code class="verbatim">true</code></td><td>Make <code class="verbatim">page.toc</code> available to templates.</td></tr> | |
| 237 | <tr><td><code class="verbatim">section_numbers</code></td><td><code class="verbatim">false</code></td><td>Number headings <code class="verbatim">1.</code>, <code class="verbatim">1.1.</code>, …</td></tr> | |
| 238 | </tbody> | |
| 239 | </table> | |
| 240 | <h3 id="heading-offset">heading<sub>offset</sub></h3> | |
| 241 | <p>A level-1 org heading renders as <code class="verbatim"><h2></code> by default, because the layout supplies the page title as the <code class="verbatim"><h1></code>. This matches Emacs, whose <code class="verbatim">org-html-toplevel-hlevel</code> is 2 for the same reason.</p> | |
| 242 | <p>Set it to <code class="verbatim">0</code> if your template renders no title of its own — otherwise the document starts at <code class="verbatim"><h2></code> with nothing above it.</p> | |
| 243 | <h3 id="section-numbers-differs-from-emacs-on-purpose">section<sub>numbers</sub> differs from Emacs on purpose</h3> | |
| 244 | <p><code class="verbatim">org-export-with-section-numbers</code> is on in Emacs, so an org-published site inherits numbered headings whether or not anyone chose them. Most sites do not want them, so the default here is the taste rather than the inheritance. Turning it on emits Emacs' own <code class="verbatim">section-number-N</code> classes.</p> | |
| 245 | <h2 id="per-file-overrides">Per-file overrides</h2> | |
| 246 | <p>Org's own <code class="verbatim">#+OPTIONS:</code> switches override the site setting for one document:</p> | |
| 247 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+OPTIONS:</span><span class="string unquoted org"> toc:nil num:t</span></span></code></pre> | |
| 248 | <table> | |
| 249 | <thead> | |
| 250 | <tr><th>Switch</th><th>Overrides</th></tr> | |
| 251 | </thead> | |
| 252 | <tbody> | |
| 253 | <tr><td><code class="verbatim">toc:nil</code> / <code class="verbatim">toc:t</code></td><td><code class="verbatim">[html] toc</code></td></tr> | |
| 254 | <tr><td><code class="verbatim">num:t</code> / <code class="verbatim">num:nil</code></td><td><code class="verbatim">[html] section_numbers</code></td></tr> | |
| 255 | </tbody> | |
| 256 | </table> | |
| 257 | <p>Off is spelled <code class="verbatim">nil</code>, <code class="verbatim">false</code>, <code class="verbatim">no</code>, <code class="verbatim">0</code> or <code class="verbatim">off</code>; anything else is on.</p> | |
| 258 | <h2 id="configuration-is-a-cache-input">Configuration is a cache input</h2> | |
| 259 | <p>The resolved config is hashed into every page's render key, so editing <code class="verbatim">orgo.toml</code> re-renders exactly the pages it affects — which for most settings is all of them. You never need <code class="verbatim">--no-cache</code> after a config change.</p> | |
| 260 | </main> | |
| 261 | <footer class="site"> | |
| 262 | Built with orgo — these docs are an orgo site. | |
| 263 | </footer> | |
| 264 | </body> | |
| 265 | </html> | |
| \ No newline at end of file | ||
guide/03-collections.html added +212
| @@ -0,0 +1,212 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Collections · orgo</title> | |
| 7 | <meta name="description" content="Generated pages — blog indexes, tag pages, pagination and RSS feeds."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Collections</h1> | |
| 24 | <p class="lede">The one kind of output that is not a translation of some input.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#a-blog-index">A blog index</a> | |
| 29 | <ul> | |
| 30 | <li><a href="#sorting">Sorting</a></li> | |
| 31 | <li><a href="#grouping-a-listing-by-year">Grouping a listing by year</a></li> | |
| 32 | <li><a href="#full-content-feeds">Full-content feeds</a></li> | |
| 33 | <li><a href="#nav-true">nav = true</a></li> | |
| 34 | </ul></li> | |
| 35 | <li><a href="#tag-pages">Tag pages</a> | |
| 36 | <ul> | |
| 37 | <li><a href="#grouping-by-anything">Grouping by anything</a></li> | |
| 38 | <li><a href="#two-tags-that-would-collide-are-an-error">Two tags that would collide are an error</a></li> | |
| 39 | </ul></li> | |
| 40 | <li><a href="#pagination">Pagination</a></li> | |
| 41 | <li><a href="#an-rss-feed">An RSS feed</a></li> | |
| 42 | <li><a href="#every-setting">Every setting</a></li> | |
| 43 | <li><a href="#incremental-behaviour">Incremental behaviour</a></li> | |
| 44 | </ul> | |
| 45 | </nav> | |
| 46 | <p>A blog index exists because a set of posts exists, not because someone wrote <code class="verbatim">index.org</code>. A <code class="verbatim">[[collections]]</code> block declares one: a source directory in, an output file out, through a template.</p> | |
| 47 | <p>Keeping it declarative means an RSS feed is the same mechanism with an XML template rather than a second feature.</p> | |
| 48 | <h2 id="a-blog-index">A blog index</h2> | |
| 49 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span> | |
| 50 | <span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> directory to list; empty means every page | |
| 51 | </span><span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog/index.html<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> where to write it | |
| 52 | </span><span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>list.html<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> template file name | |
| 53 | </span><span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>Blog<span class="punctuation definition string end toml">"</span></span> | |
| 54 | <span class="variable other key toml">sort</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>date<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> date | title | path | |
| 55 | </span><span class="variable other key toml">order</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>desc<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> desc | asc | |
| 56 | </span><span class="variable other key toml">nav</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> put this page in the site nav</span></span></code></pre> | |
| 57 | <p>The template receives the collection's entries as <code class="verbatim">pages</code>, already sorted, plus the usual <code class="verbatim">site</code>, <code class="verbatim">nav</code> and <code class="verbatim">root</code>:</p> | |
| 58 | <pre><code class="language-html highlight"><span class="text html basic">{% extends "base.html" %} | |
| 59 | {% block content %} | |
| 60 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">></span></span> | |
| 61 | {% for post in pages %} | |
| 62 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span> | |
| 63 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">time</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">datetime</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ post.date_iso }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ post.date_iso }}<span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">time</span><span class="punctuation definition tag end html">></span></span> | |
| 64 | <span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}{{ post.url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ post.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span> | |
| 65 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">></span></span>{{ post.excerpt | truncate(180) }}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">></span></span> | |
| 66 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span> | |
| 67 | {% endfor %} | |
| 68 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">></span></span> | |
| 69 | {% endblock %}</span></code></pre> | |
| 70 | <h3 id="sorting">Sorting</h3> | |
| 71 | <p><code class="verbatim">sort</code> is <code class="verbatim">date</code> (default), <code class="verbatim">title</code> or <code class="verbatim">path</code>; <code class="verbatim">order</code> is <code class="verbatim">desc</code> (default) or <code class="verbatim">asc</code>.</p> | |
| 72 | <p>Date sorting uses <code class="verbatim">page.date_iso</code>, the <code class="verbatim">YYYY-MM-DD</code> extracted from <code class="verbatim">#+DATE:</code> whatever org syntax it was written in — <code class="verbatim">[2025-09-05 Fri 10:21:00]</code>, <code class="verbatim"><2024-05-01 Wed></code> or a bare <code class="verbatim">2024-05-01</code> all work.</p> | |
| 73 | <p><strong>Pages with no parseable date sort last in either direction</strong>, so an undated draft never leads a dated archive.</p> | |
| 74 | <h3 id="grouping-a-listing-by-year">Grouping a listing by year</h3> | |
| 75 | <p>An archive usually wants year headings, and that is a <strong>template</strong> decision rather than a config one — the entries are already in the right order, they just need breaking up. <code class="verbatim">page.year</code> exists for exactly this, because minijinja's <code class="verbatim">groupby</code> takes an attribute name and cannot slice a date itself:</p> | |
| 76 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">ul</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">post-list</span><span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 77 | {% for year, posts in pages | groupby("year") | reverse %} | |
| 78 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">li</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">post-list-year</span><span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ year if year else "undated" }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span> | |
| 79 | {% for entry in posts %} | |
| 80 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span><span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">time</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">datetime</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ entry.date_iso }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ entry.date_iso }}<span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">time</span><span class="punctuation definition tag end html">></span></span> | |
| 81 | <span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}{{ entry.url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ entry.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span><span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span> | |
| 82 | {% endfor %} | |
| 83 | {% endfor %} | |
| 84 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 85 | <p><code class="verbatim">groupby</code> sorts its groups ascending, so <code class="verbatim">| reverse</code> puts the newest year first — matching the <code class="verbatim">order = "desc"</code> the entries themselves already use, and leaving undated pages in a group of their own at the end.</p> | |
| 86 | <p>Name that group in the template rather than with <code class="verbatim">groupby</code>'s <code class="verbatim">default=</code> argument, which covers an attribute that is <strong>missing</strong> and not one that is null — an undated page has a <code class="verbatim">year</code>, and it is <code class="verbatim">none</code>.</p> | |
| 87 | <h3 id="full-content-feeds">Full-content feeds</h3> | |
| 88 | <p>A feed usually carries whole posts, and a subscriber handed excerpts instead has lost something. <code class="verbatim">include_content</code> gives the template each entry's rendered HTML as <code class="verbatim">entry.content</code>:</p> | |
| 89 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span> | |
| 90 | <span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> | |
| 91 | <span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>feed.xml<span class="punctuation definition string end toml">"</span></span> | |
| 92 | <span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>feed.xml<span class="punctuation definition string end toml">"</span></span> | |
| 93 | <span class="variable other key toml">include_content</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span></span></code></pre> | |
| 94 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">description</span><span class="punctuation definition tag end html">></span></span><span class="meta tag sgml html"><span class="punctuation definition tag html"><!</span><span class="constant other inline-data html">[CDATA[{{ post.content | safe }}]]</span><span class="punctuation definition tag html">></span></span><span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">description</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 95 | <p>Off by default, because it costs a render of every listed page each time the listing is rebuilt. That cost is only paid when the listing is <strong>not</strong> cached, and the listing's cache key covers its entries' content — so a body edit reaches the feed, and an unchanged site pays nothing.</p> | |
| 96 | <p>Everywhere else <code class="verbatim">entry.content</code> is <code class="verbatim">none</code>, since carrying every page's body in every listing context would be most of a site's memory for nothing.</p> | |
| 97 | <h3 id="nav-true">nav = true</h3> | |
| 98 | <p>The listing page joins the site navigation. This is how a section landing page — <code class="verbatim">/blog/</code>, <code class="verbatim">/notes/</code> — gets into a nav built from top-level pages, and it points at the right thing: the section, not any one post in it.</p> | |
| 99 | <h2 id="tag-pages">Tag pages</h2> | |
| 100 | <p>Add <code class="verbatim">group_by</code> and the collection emits one page <em>per group</em> instead of one page total, plus an optional index of the groups:</p> | |
| 101 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span> | |
| 102 | <span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> | |
| 103 | <span class="variable other key toml">group_by</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>tags<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> "tags", or any #+KEYWORD: name | |
| 104 | </span><span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>tags/{tag}.html<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> {tag} becomes each group's slug | |
| 105 | </span><span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>tag.html<span class="punctuation definition string end toml">"</span></span> | |
| 106 | <span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>Tagged: {tag}<span class="punctuation definition string end toml">"</span></span> | |
| 107 | <span class="variable other key toml">index_output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>tags/index.html<span class="punctuation definition string end toml">"</span></span> | |
| 108 | <span class="variable other key toml">index_template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>tags.html<span class="punctuation definition string end toml">"</span></span> | |
| 109 | <span class="variable other key toml">index_title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>Tags<span class="punctuation definition string end toml">"</span></span> | |
| 110 | <span class="variable other key toml">nav</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> adds the *index*, not every tag</span></span></code></pre> | |
| 111 | <p>A group page receives its own posts as <code class="verbatim">pages</code> and itself as <code class="verbatim">group</code>:</p> | |
| 112 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">></span></span>{{ group.name }} ({{ group.count }})<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">></span></span> | |
| 113 | {% for post in pages %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}{{ post.url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ post.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span>{% endfor %}</span></code></pre> | |
| 114 | <p>The index receives <code class="verbatim">groups</code>, sorted by name:</p> | |
| 115 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">></span></span>{% for tag in groups %} | |
| 116 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span><span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}{{ tag.url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ tag.name }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span> ({{ tag.count }})<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span> | |
| 117 | {% endfor %}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 118 | <h3 id="grouping-by-anything">Grouping by anything</h3> | |
| 119 | <p><code class="verbatim">group_by = "tags"</code> is multi-valued: a post appears under every tag it carries. Any other value names a single-valued <code class="verbatim">#+KEYWORD:</code>, so <code class="verbatim">group_by = "category"</code> buckets pages by <code class="verbatim">#+CATEGORY:</code> with no extra machinery.</p> | |
| 120 | <h3 id="two-tags-that-would-collide-are-an-error">Two tags that would collide are an error</h3> | |
| 121 | <p><code class="verbatim">web_dev</code> and <code class="verbatim">web@dev</code> both slugify to <code class="verbatim">web-dev</code>, so one page would silently overwrite the other. That is a build error naming both values.</p> | |
| 122 | <h2 id="pagination">Pagination</h2> | |
| 123 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span> | |
| 124 | <span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> | |
| 125 | <span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog/index.html<span class="punctuation definition string end toml">"</span></span> | |
| 126 | <span class="variable other key toml">paginate</span> <span class="keyword operator assignment toml">=</span> <span class="constant numeric toml">10</span> | |
| 127 | <span class="variable other key toml">paginate_output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog/page/{n}.html<span class="punctuation definition string end toml">"</span></span> <span class="comment line number-sign toml"><span class="punctuation definition comment toml">#</span> {n} is the 1-based page number</span></span></code></pre> | |
| 128 | <p><strong>Page 1 stays at <code class="verbatim">output</code></strong>, so a section's canonical URL never moves as its page count changes. Only pages 2..N are named by <code class="verbatim">paginate_output</code>.</p> | |
| 129 | <p>The template gets a <code class="verbatim">paginator</code>:</p> | |
| 130 | <pre><code class="language-html highlight"><span class="text html basic">{% if paginator and paginator.total > 1 %} | |
| 131 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">></span></span> | |
| 132 | {% if paginator.prev_url %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ paginator.prev_url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>Newer<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span>{% endif %} | |
| 133 | {% for pg in paginator.pages %} | |
| 134 | <span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ pg.url }}<span class="punctuation definition string end html">"</span></span></span>{% <span class="entity other attribute-name html">if</span> <span class="entity other attribute-name html">pg.current</span> %} <span class="meta attribute-with-value html"><span class="entity other attribute-name html">aria-current</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>page<span class="punctuation definition string end html">"</span></span></span>{% <span class="entity other attribute-name html">endif</span> %}<span class="punctuation definition tag end html">></span></span>{{ pg.number }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span> | |
| 135 | {% endfor %} | |
| 136 | {% if paginator.next_url %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ paginator.next_url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>Older<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span>{% endif %} | |
| 137 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">></span></span> | |
| 138 | {% endif %}</span></code></pre> | |
| 139 | <table> | |
| 140 | <thead> | |
| 141 | <tr><th>Field</th><th>Meaning</th></tr> | |
| 142 | </thead> | |
| 143 | <tbody> | |
| 144 | <tr><td><code class="verbatim">current</code>, <code class="verbatim">total</code></td><td>This page's number, and how many there are.</td></tr> | |
| 145 | <tr><td><code class="verbatim">per_page</code>, <code class="verbatim">total_entries</code></td><td>As configured, and across the whole listing.</td></tr> | |
| 146 | <tr><td><code class="verbatim">prev_url</code>, <code class="verbatim">next_url</code></td><td><code class="verbatim">none</code> at the ends.</td></tr> | |
| 147 | <tr><td><code class="verbatim">first_url</code>, <code class="verbatim">last_url</code></td><td>Always present.</td></tr> | |
| 148 | <tr><td><code class="verbatim">pages</code></td><td><code class="verbatim">[{number, url, current}]</code> for a numbered strip.</td></tr> | |
| 149 | </tbody> | |
| 150 | </table> | |
| 151 | <p>Every URL is relative to the page carrying it, so links work from page 1 (<code class="verbatim">page/2.html</code>) and from page 5 (<code class="verbatim">../index.html</code>, <code class="verbatim">6.html</code>) without the template knowing where it sits. An unpaginated collection has no <code class="verbatim">paginator</code> at all, so <code class="verbatim">{% if paginator %}</code> is a reliable test in a shared template.</p> | |
| 152 | <p>Grouping and pagination compose: each group paginates independently, which is why <code class="verbatim">paginate_output</code> needs <code class="verbatim">{tag}</code> as well as <code class="verbatim">{n}</code> on a grouped collection.</p> | |
| 153 | <h2 id="an-rss-feed">An RSS feed</h2> | |
| 154 | <p>A feed is a listing page with an XML template. Templates load by full filename and any extension, so:</p> | |
| 155 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span> | |
| 156 | <span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> | |
| 157 | <span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>feed.xml<span class="punctuation definition string end toml">"</span></span> | |
| 158 | <span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>feed.xml<span class="punctuation definition string end toml">"</span></span> | |
| 159 | <span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>Feed<span class="punctuation definition string end toml">"</span></span></span></code></pre> | |
| 160 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag preprocessor xml html"><span class="punctuation definition tag begin html"><?</span><span class="entity name tag xml html">xml</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">version</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>1.0<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">encoding</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>utf-8<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">?></span></span> | |
| 161 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">rss</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">version</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>2.0<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">xmlns:atom</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>http://www.w3.org/2005/Atom<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 162 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">channel</span><span class="punctuation definition tag end html">></span></span> | |
| 163 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span>{{ site.title }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span> | |
| 164 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">></span></span>{{ "index.html" | absolute }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">></span></span> | |
| 165 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">atom:link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ page.url | absolute }}<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>self<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">type</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>application/rss+xml<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">/></span></span> | |
| 166 | {% for post in pages %} | |
| 167 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">item</span><span class="punctuation definition tag end html">></span></span> | |
| 168 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span>{{ post.title }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span> | |
| 169 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">></span></span>{{ post.url | absolute }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">></span></span> | |
| 170 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">guid</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">isPermaLink</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>true<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ post.url | absolute }}<span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">guid</span><span class="punctuation definition tag end html">></span></span> | |
| 171 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">pubDate</span><span class="punctuation definition tag end html">></span></span>{{ post.date_iso | rfc822 }}<span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">pubDate</span><span class="punctuation definition tag end html">></span></span> | |
| 172 | <span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">item</span><span class="punctuation definition tag end html">></span></span> | |
| 173 | {% endfor %} | |
| 174 | <span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">channel</span><span class="punctuation definition tag end html">></span></span> | |
| 175 | <span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">rss</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 176 | <p>This needs <code class="verbatim">site.base_url</code>, because a feed with relative links is invalid everywhere it is read. <code class="verbatim">orgo init</code> writes this template and leaves the collection commented out until there is a base URL to make absolute links from.</p> | |
| 177 | <h2 id="every-setting">Every setting</h2> | |
| 178 | <table> | |
| 179 | <thead> | |
| 180 | <tr><th>Key</th><th>Default</th><th>Meaning</th></tr> | |
| 181 | </thead> | |
| 182 | <tbody> | |
| 183 | <tr><td><code class="verbatim">source</code></td><td>=""</td><td>Directory to list. Empty means every page.</td></tr> | |
| 184 | <tr><td><code class="verbatim">output</code></td><td><code class="verbatim">"index.html"</code></td><td>Where to write. Needs <code class="verbatim">{tag}</code> when grouped.</td></tr> | |
| 185 | <tr><td><code class="verbatim">template</code></td><td><code class="verbatim">"list.html"</code></td><td>Template file name.</td></tr> | |
| 186 | <tr><td><code class="verbatim">title</code></td><td><code class="verbatim">"Index"</code></td><td><code class="verbatim">{{ page.title }}</code>. <code class="verbatim">{tag}</code> is substituted when grouped.</td></tr> | |
| 187 | <tr><td><code class="verbatim">group_by</code></td><td>=""</td><td><code class="verbatim">"tags"</code>, or a <code class="verbatim">#+KEYWORD:</code> name. Empty means one page.</td></tr> | |
| 188 | <tr><td><code class="verbatim">index_output</code></td><td>=""</td><td>Where to write the group index. Empty means none.</td></tr> | |
| 189 | <tr><td><code class="verbatim">index_template</code></td><td><code class="verbatim">"tags.html"</code></td><td>Template for the group index.</td></tr> | |
| 190 | <tr><td><code class="verbatim">index_title</code></td><td><code class="verbatim">"Tags"</code></td><td>Title for the group index.</td></tr> | |
| 191 | <tr><td><code class="verbatim">sort</code></td><td><code class="verbatim">"date"</code></td><td><code class="verbatim">date</code>, <code class="verbatim">title</code> or <code class="verbatim">path</code>.</td></tr> | |
| 192 | <tr><td><code class="verbatim">order</code></td><td><code class="verbatim">"desc"</code></td><td><code class="verbatim">desc</code> or <code class="verbatim">asc</code>.</td></tr> | |
| 193 | <tr><td><code class="verbatim">paginate</code></td><td><code class="verbatim">0</code></td><td>Entries per page. <code class="verbatim">0</code> means no pagination.</td></tr> | |
| 194 | <tr><td><code class="verbatim">paginate_output</code></td><td>=""</td><td>Where pages 2..N go. Needs <code class="verbatim">{n}</code>.</td></tr> | |
| 195 | <tr><td><code class="verbatim">nav</code></td><td><code class="verbatim">false</code></td><td>Add this page — or its index, when grouped — to the nav.</td></tr> | |
| 196 | </tbody> | |
| 197 | </table> | |
| 198 | <h2 id="incremental-behaviour">Incremental behaviour</h2> | |
| 199 | <p>A listing page is cached on the entries it lists, so:</p> | |
| 200 | <ul> | |
| 201 | <li>Adding a post re-renders that post, its section index, its tag pages and the tag index whose counts changed. Nothing else.</li> | |
| 202 | <li>Editing a post's <strong>body</strong> changes no listing metadata, so the index is not touched at all.</li> | |
| 203 | <li>Retitling a post does re-render the listings that display the title.</li> | |
| 204 | </ul> | |
| 205 | <p>A tag page depends on its own posts and not on the other groups, which is why <code class="verbatim">groups</code> is given to the index and not to every group page: a page that can see every group would depend on every group, and one new post would re-render every tag page.</p> | |
| 206 | <p>When a collection shrinks below a page boundary, the pages that no longer exist are deleted rather than left serving stale content.</p> | |
| 207 | </main> | |
| 208 | <footer class="site"> | |
| 209 | Built with orgo — these docs are an orgo site. | |
| 210 | </footer> | |
| 211 | </body> | |
| 212 | </html> | |
| \ No newline at end of file | ||
guide/04-templates.html added +185
| @@ -0,0 +1,185 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Templates · orgo</title> | |
| 7 | <meta name="description" content="Layouts, inheritance, every variable and filter available to a template."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Templates</h1> | |
| 24 | <p class="lede">minijinja layouts loaded from disk, hashed into the cache, replaceable entirely.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#base-html-replaces-the-layout">base.html replaces the layout</a></li> | |
| 29 | <li><a href="#pages-can-render-through-a-different-layout">Pages can render through a different layout</a></li> | |
| 30 | <li><a href="#names-are-full-filenames">Names are full filenames</a> | |
| 31 | <ul> | |
| 32 | <li><a href="#partials-keep-a-snippet-out-of-a-layout">Partials keep a snippet out of a layout</a></li> | |
| 33 | </ul></li> | |
| 34 | <li><a href="#variables">Variables</a> | |
| 35 | <ul> | |
| 36 | <li><a href="#body">body</a></li> | |
| 37 | <li><a href="#page">page</a></li> | |
| 38 | <li><a href="#site">site</a></li> | |
| 39 | <li><a href="#nav">nav</a></li> | |
| 40 | <li><a href="#root">root</a></li> | |
| 41 | <li><a href="#stylesheet">stylesheet</a></li> | |
| 42 | <li><a href="#theme">theme</a></li> | |
| 43 | <li><a href="#pages-group-groups-paginator">pages, group, groups, paginator</a></li> | |
| 44 | <li><a href="#page-toc">page.toc</a></li> | |
| 45 | </ul></li> | |
| 46 | <li><a href="#filters">Filters</a> | |
| 47 | <ul> | |
| 48 | <li><a href="#absolute">absolute</a></li> | |
| 49 | <li><a href="#truncate">truncate</a></li> | |
| 50 | </ul></li> | |
| 51 | <li><a href="#escaping">Escaping</a></li> | |
| 52 | <li><a href="#templates-are-a-cache-input">Templates are a cache input</a></li> | |
| 53 | </ul> | |
| 54 | </nav> | |
| 55 | <p>Templates live in the directory named by <code class="verbatim">[templates] dir</code>, default <code class="verbatim">templates/</code>. They are <a href="https://docs.rs/minijinja">minijinja</a> templates — Jinja2 syntax — loaded at build time, so editing one and rebuilding is the whole edit cycle.</p> | |
| 56 | <h2 id="base-html-replaces-the-layout">base.html replaces the layout</h2> | |
| 57 | <p>A file called <code class="verbatim">base.html</code> becomes the page layout. Without one, a built-in layout is used — which is what makes a bare directory of org files build into a real site.</p> | |
| 58 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag sgml html"><span class="punctuation definition tag html"><!</span><span class="meta tag sgml doctype html"><span class="entity name tag doctype html">DOCTYPE</span> html</span><span class="punctuation definition tag html">></span></span> | |
| 59 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag structure any html">html</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">lang</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ site.language }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 60 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag structure any html">head</span><span class="punctuation definition tag end html">></span></span> | |
| 61 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">meta</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">charset</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>utf-8<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 62 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">meta</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">name</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>viewport<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">content</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>width=device-width, initial-scale=1<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 63 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span>{{ page.title }} — {{ site.title }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span> | |
| 64 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>stylesheet<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}style.css<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 65 | {% if stylesheet %}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>stylesheet<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ stylesheet }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{% endif %} | |
| 66 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag structure any html">head</span><span class="punctuation definition tag end html">></span></span> | |
| 67 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag structure any html">body</span><span class="punctuation definition tag end html">></span></span> | |
| 68 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">></span></span>{% for item in nav %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ item.url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ item.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span>{% endfor %}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">></span></span> | |
| 69 | <span class="meta tag other html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag other html">main</span><span class="punctuation definition tag end html">></span></span> | |
| 70 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">></span></span>{{ page.title }}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">></span></span> | |
| 71 | {{ body | safe }} | |
| 72 | <span class="meta tag other html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag other html">main</span><span class="punctuation definition tag end html">></span></span> | |
| 73 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag structure any html">body</span><span class="punctuation definition tag end html">></span></span> | |
| 74 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag structure any html">html</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 75 | <p>A template that does not compile is a <strong>build error</strong>, not a fallback to the default — someone editing a layout should see the mistake, not output that looks like their edit did nothing.</p> | |
| 76 | <h2 id="pages-can-render-through-a-different-layout">Pages can render through a different layout</h2> | |
| 77 | <p><code class="verbatim">base.html</code> is the default, not the only option. A <code class="verbatim">[[pages]]</code> rule gives a section its own layout, and <code class="verbatim">#+TEMPLATE:</code> gives one page its own:</p> | |
| 78 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">pages</span><span class="punctuation definition table array toml">]]</span> | |
| 79 | <span class="variable other key toml">match</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> | |
| 80 | <span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>post.html<span class="punctuation definition string end toml">"</span></span></span></code></pre> | |
| 81 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+TEMPLATE:</span><span class="string unquoted org"> wide.html</span></span></code></pre> | |
| 82 | <p>The page's own keyword wins over any rule, and the most specific rule wins over a broader one. A second layout almost always wants the first one's chrome, so it extends it:</p> | |
| 83 | <pre><code class="language-html highlight"><span class="text html basic">{% extends "base.html" %} | |
| 84 | {% block content %} | |
| 85 | {{ body | safe }} | |
| 86 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">></span></span><span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>mailto:you@example.com<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>Reply by email <span class="constant character entity html"><span class="punctuation definition entity html">&</span>rarr<span class="punctuation definition entity html">;</span></span><span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span><span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">></span></span> | |
| 87 | {% endblock %}</span></code></pre> | |
| 88 | <p>Full rules in <a href="02-configuration.html">Configuration</a>.</p> | |
| 89 | <h2 id="names-are-full-filenames">Names are full filenames</h2> | |
| 90 | <p>Templates are registered under their full relative filename: <code class="verbatim">base.html</code>, <code class="verbatim">partials/head.html</code>, <code class="verbatim">feed.xml</code>. That is what <code class="verbatim">{% extends "base.html" %}</code> names, and it is why a template can have any extension — which is how an RSS feed is just a listing page.</p> | |
| 91 | <pre><code class="language-html highlight"><span class="text html basic">{% extends "base.html" %} | |
| 92 | {% block content %}<span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">></span></span>Only this part differs.<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">></span></span>{% endblock %}</span></code></pre> | |
| 93 | <p>Subdirectories work, so <code class="verbatim">{% include "partials/header.html" %}</code> does what you expect.</p> | |
| 94 | <h3 id="partials-keep-a-snippet-out-of-a-layout">Partials keep a snippet out of a layout</h3> | |
| 95 | <p>A block of content that is not really layout — an invitation to reply, a licence line, a donation ask — is better as its own file than as a line inside <code class="verbatim">base.html</code>:</p> | |
| 96 | <pre><code class="language-html highlight"><span class="text html basic">{% extends "base.html" %} | |
| 97 | {% block content %} | |
| 98 | {{ body | safe }} | |
| 99 | {% include "reply.html" %} | |
| 100 | {% endblock %}</span></code></pre> | |
| 101 | <p>Emptying <code class="verbatim">reply.html</code> removes it everywhere; editing it re-renders exactly the pages that include it, because the render key follows includes. And because the <strong>page</strong> chooses its layout, an individual page opts in with <code class="verbatim">#+TEMPLATE: post.html</code> or out with <code class="verbatim">#+TEMPLATE: base.html</code>, without a rule deciding for a whole directory.</p> | |
| 102 | <h2 id="variables">Variables</h2> | |
| 103 | <h3 id="body">body</h3> | |
| 104 | <p>The rendered page HTML. Always use <code class="verbatim">{{ body | safe }}</code> — it is already HTML, and escaping it would print tags at the reader.</p> | |
| 105 | <p>Empty on generated pages, which build their content from <code class="verbatim">pages</code> or <code class="verbatim">groups</code> instead.</p> | |
| 106 | <h3 id="page">page</h3> | |
| 107 | <table> | |
| 108 | <thead> | |
| 109 | <tr><th>Field</th><th>Meaning</th></tr> | |
| 110 | </thead> | |
| 111 | <tbody> | |
| 112 | <tr><td><code class="verbatim">title</code></td><td><code class="verbatim">#+TITLE:</code>, or the filename stem.</td></tr> | |
| 113 | <tr><td><code class="verbatim">url</code></td><td>Output path relative to the site root, e.g. <code class="verbatim">blog/post.html</code>.</td></tr> | |
| 114 | <tr><td><code class="verbatim">source</code></td><td>Source path relative to the source root, e.g. <code class="verbatim">blog/post.org</code>.</td></tr> | |
| 115 | <tr><td><code class="verbatim">date</code></td><td><code class="verbatim">#+DATE:</code> verbatim, in whatever org syntax was written.</td></tr> | |
| 116 | <tr><td><code class="verbatim">date_iso</code></td><td>The <code class="verbatim">YYYY-MM-DD</code> inside it, or <code class="verbatim">none</code>.</td></tr> | |
| 117 | <tr><td><code class="verbatim">year</code></td><td>The year from that date, for grouping a listing.</td></tr> | |
| 118 | <tr><td><code class="verbatim">tags</code></td><td><code class="verbatim">#+FILETAGS:</code>, split.</td></tr> | |
| 119 | <tr><td><code class="verbatim">excerpt</code></td><td><code class="verbatim">#+DESCRIPTION:</code>, or the first paragraph.</td></tr> | |
| 120 | <tr><td><code class="verbatim">word_count</code></td><td>Words of prose, excluding code blocks.</td></tr> | |
| 121 | <tr><td><code class="verbatim">reading_time</code></td><td>Minutes at 200 wpm, rounded up.</td></tr> | |
| 122 | <tr><td><code class="verbatim">toc</code></td><td>The heading tree. See below.</td></tr> | |
| 123 | <tr><td><code class="verbatim">keywords</code></td><td><strong>Every</strong> <code class="verbatim">#+KEYWORD:</code>, by lowercased name.</td></tr> | |
| 124 | </tbody> | |
| 125 | </table> | |
| 126 | <p><code class="verbatim">page.keywords</code> is the escape hatch: <code class="verbatim">#+CUSTOM_THING: x</code> is <code class="verbatim">{{ page.keywords.custom_thing }}</code>, so your own metadata works without orgo knowing it exists.</p> | |
| 127 | <h3 id="site">site</h3> | |
| 128 | <p><code class="verbatim">site.title</code>, <code class="verbatim">site.base_url</code>, <code class="verbatim">site.description</code>, <code class="verbatim">site.language</code> — straight from <code class="verbatim">[site]</code> in the config.</p> | |
| 129 | <h3 id="nav">nav</h3> | |
| 130 | <p>A list of <code class="verbatim">{title, url}</code>, with URLs relative to the current page.</p> | |
| 131 | <h3 id="root">root</h3> | |
| 132 | <p>The <code class="verbatim">../</code> prefix back to the site root from this page: empty at the top level, <code class="verbatim">../</code> one level down. Prefix it to any site-root-relative path so the same template works at any depth:</p> | |
| 133 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>stylesheet<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}style.css<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 134 | <span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}{{ post.url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ post.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 135 | <h3 id="stylesheet">stylesheet</h3> | |
| 136 | <p>URL of the generated <code class="verbatim">syntax.css</code>, relative to this page. Link it or code blocks are unstyled.</p> | |
| 137 | <h3 id="theme">theme</h3> | |
| 138 | <p>URL of <code class="verbatim">theme.css</code>, relative to this page — the <a href="02-configuration.html">built-in theme</a> named by <code class="verbatim">site.theme</code>. Empty when there is none, which is the default, so guard it and link it <strong>before</strong> <code class="verbatim">stylesheet</code> or the theme's code colours would override the highlighter's:</p> | |
| 139 | <pre><code class="language-html highlight"><span class="text html basic">{% if theme %}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>stylesheet<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ theme }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{% endif %} | |
| 140 | {% if stylesheet %}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>stylesheet<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ stylesheet }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{% endif %}</span></code></pre> | |
| 141 | <p>A layout that ignores it is a layout with its own CSS, which is the point at which you have outgrown the setting.</p> | |
| 142 | <h3 id="pages-group-groups-paginator">pages, group, groups, paginator</h3> | |
| 143 | <p>Present on generated pages; see <a href="03-collections.html">Collections</a>. <code class="verbatim">pages</code> is also available on every page when <code class="verbatim">[templates] expose_page_list = true</code>.</p> | |
| 144 | <h3 id="page-toc">page.toc</h3> | |
| 145 | <p>The page's headings as a <strong>tree</strong> — a table of contents is one, and rebuilding a tree from a flat list of levels inside a template is what Jinja is worst at.</p> | |
| 146 | <p>Each entry has <code class="verbatim">title</code>, <code class="verbatim">anchor</code>, <code class="verbatim">level</code>, <code class="verbatim">number</code> and <code class="verbatim">children</code>:</p> | |
| 147 | <pre><code class="language-html highlight"><span class="text html basic">{% macro toc_list(entries) %} | |
| 148 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">></span></span>{% for e in entries %} | |
| 149 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span><span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>#{{ e.anchor }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ e.number }} {{ e.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span> | |
| 150 | {%- if e.children %}{{ toc_list(e.children) }}{% endif %}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">li</span><span class="punctuation definition tag end html">></span></span> | |
| 151 | {% endfor %}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">ul</span><span class="punctuation definition tag end html">></span></span> | |
| 152 | {% endmacro %} | |
| 153 | ||
| 154 | {% if page.toc | length > 1 %}{{ toc_list(page.toc) }}{% endif %}</span></code></pre> | |
| 155 | <p><code class="verbatim">number</code> is the section number — <code class="verbatim">1.</code>, <code class="verbatim">3.1.</code> — always computed and printed only if you ask for it. Print it when <code class="verbatim">[html] section_numbers</code> is on, or the contents will number what the headings do not.</p> | |
| 156 | <p>Anchors come from the same function that emits heading <code class="verbatim">id</code> attributes, so a TOC link cannot drift from the heading it points at. The tree is empty when the page has no headings, when <code class="verbatim">[html] toc = false</code>, or when the document says <code class="verbatim">#+OPTIONS: toc:nil</code>.</p> | |
| 157 | <h2 id="filters">Filters</h2> | |
| 158 | <p>Beyond minijinja's built-ins:</p> | |
| 159 | <table> | |
| 160 | <thead> | |
| 161 | <tr><th>Filter</th><th>Does</th></tr> | |
| 162 | </thead> | |
| 163 | <tbody> | |
| 164 | <tr><td><code class="verbatim">absolute</code></td><td>Site-root-relative path → absolute URL, using <code class="verbatim">site.base_url</code>.</td></tr> | |
| 165 | <tr><td><code class="verbatim">rfc822</code></td><td>Any org or ISO date → the format RSS <code class="verbatim">pubDate</code> requires.</td></tr> | |
| 166 | <tr><td><code class="verbatim">truncate(n)</code></td><td>Shorten to at most <em>n</em> characters on a word boundary, with an ellipsis.</td></tr> | |
| 167 | </tbody> | |
| 168 | </table> | |
| 169 | <h3 id="absolute">absolute</h3> | |
| 170 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">></span></span>{{ post.url | absolute }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">link</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 171 | <p>Apply it to the <strong>site-root-relative</strong> values — <code class="verbatim">page.url</code>, <code class="verbatim">pages[].url</code>, <code class="verbatim">group.url</code> — and not to <code class="verbatim">nav[].url</code>, <code class="verbatim">paginator.*_url</code>, <code class="verbatim">stylesheet</code> or <code class="verbatim">root</code>, which are relative to the page carrying them and already correct there.</p> | |
| 172 | <p>An already-absolute URL passes through, so a template can apply it uniformly to internal paths and external links. With no <code class="verbatim">base_url</code> it is an <strong>error</strong> naming the setting, rather than a relative URL that would make a feed invalid.</p> | |
| 173 | <h3 id="truncate">truncate</h3> | |
| 174 | <p>minijinja ships no truncate, and an excerpt is usually a whole paragraph — so without one a listing's only options are the full paragraph or nothing.</p> | |
| 175 | <h2 id="escaping">Escaping</h2> | |
| 176 | <p>Output is HTML-escaped by default, because titles and text are author content. <code class="verbatim">{{ body | safe }}</code> is the deliberate exception.</p> | |
| 177 | <p>Unlike stock minijinja, <code class="verbatim">/</code> is <strong>not</strong> escaped. Escaping it is a defence for values interpolated into JavaScript, and since <code class="verbatim"><</code> is escaped anyway it buys nothing in an HTML document — while making every URL read <code class="verbatim">..&#x2f;index.html</code>. Templates emit a lot of URLs.</p> | |
| 178 | <h2 id="templates-are-a-cache-input">Templates are a cache input</h2> | |
| 179 | <p>Every template's source is hashed, so editing a layout re-renders the pages that use it. A design change never leaves a site half-updated.</p> | |
| 180 | </main> | |
| 181 | <footer class="site"> | |
| 182 | Built with orgo — these docs are an orgo site. | |
| 183 | </footer> | |
| 184 | </body> | |
| 185 | </html> | |
| \ No newline at end of file | ||
guide/05-org-support.html added +182
| @@ -0,0 +1,182 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Org support · orgo</title> | |
| 7 | <meta name="description" content="Exactly which org syntax is handled, which is not, and how the rest degrades."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Org support</h1> | |
| 24 | <p class="lede">A deliberate subset, with the boundary enforced by tests rather than by hope.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#supported">Supported</a> | |
| 29 | <ul> | |
| 30 | <li><a href="#headings">Headings</a></li> | |
| 31 | <li><a href="#text-and-inline-markup">Text and inline markup</a> | |
| 32 | <ul> | |
| 33 | <li><a href="#text-conversions">Text conversions</a></li> | |
| 34 | <li><a href="#heading-levels-are-relative">Heading levels are relative</a></li> | |
| 35 | </ul></li> | |
| 36 | <li><a href="#lists">Lists</a></li> | |
| 37 | <li><a href="#blocks">Blocks</a> | |
| 38 | <ul> | |
| 39 | <li><a href="#which-languages-highlight">Which languages highlight</a></li> | |
| 40 | <li><a href="#the-comma-escape">The comma escape</a></li> | |
| 41 | </ul></li> | |
| 42 | <li><a href="#tables-and-footnotes">Tables and footnotes</a></li> | |
| 43 | <li><a href="#images">Images</a></li> | |
| 44 | </ul></li> | |
| 45 | <li><a href="#keywords-with-meaning">Keywords with meaning</a></li> | |
| 46 | <li><a href="#not-supported-and-what-happens-instead">Not supported, and what happens instead</a> | |
| 47 | <ul> | |
| 48 | <li><a href="#why-results-is-dropped-rather-than-rendered">Why #+RESULTS: is dropped rather than rendered</a></li> | |
| 49 | </ul></li> | |
| 50 | <li><a href="#diagnostics">Diagnostics</a></li> | |
| 51 | <li><a href="#measured-against-emacs">Measured against Emacs</a></li> | |
| 52 | </ul> | |
| 53 | </nav> | |
| 54 | <p>orgo parses a defined slice of org. The boundary is not aspirational: every supported construct has a golden-file test, and every excluded one has a test asserting how it degrades. That is what stops the parser drifting toward all-of-org.</p> | |
| 55 | <h2 id="supported">Supported</h2> | |
| 56 | <h3 id="headings">Headings</h3> | |
| 57 | <p>Nesting by star count, with TODO keywords, priority cookies and tags:</p> | |
| 58 | <pre><code class="language-org highlight"><span class="text org"><span class="markup heading org"><span class="punctuation definition heading org">*</span> <span class="keyword other todo org">TODO</span> <span class="constant other priority org">[#A]</span> Write the parser <span class="entity name tag org">:work:rust: | |
| 59 | </span></span>,:PROPERTIES: | |
| 60 | ,:CUSTOM_ID: write-parser | |
| 61 | ,:END:</span></code></pre> | |
| 62 | <p>The keyword set is Emacs' default — <code class="verbatim">TODO</code> and <code class="verbatim">DONE</code> — matched on a word boundary, so a heading beginning "TODOs are great" is a plain title. Keyword and priority markup uses Emacs' own export classes.</p> | |
| 63 | <p>Every heading gets an <code class="verbatim">id</code>: its <code class="verbatim">:CUSTOM_ID:</code> if it has one, else its <code class="verbatim">:ID:</code>, else a slug of its text.</p> | |
| 64 | <h3 id="text-and-inline-markup">Text and inline markup</h3> | |
| 65 | <p><code class="verbatim">*bold*</code>, <code class="verbatim">/italic/</code>, <code class="verbatim">_underline_</code>, <code class="verbatim">+strike+</code>, <code>=verbatim=</code> and <code class="verbatim">~code~</code>. Links in every org form — external, <code class="verbatim">[[*Heading]]</code>, <code class="verbatim">[[#custom-id]]</code>, <code class="verbatim">[[id:...]]</code>, <code class="verbatim">[[file:other.org]]</code> — plus bare URLs in running text.</p> | |
| 66 | <p>Timestamps, active and inactive, with times and ranges, render as <code class="verbatim"><time></code> with a machine-readable <code class="verbatim">datetime</code>.</p> | |
| 67 | <h4 id="text-conversions">Text conversions</h4> | |
| 68 | <p>Org rewrites some prose on export, and so does orgo:</p> | |
| 69 | <table> | |
| 70 | <thead> | |
| 71 | <tr><th>Written</th><th>Published</th></tr> | |
| 72 | </thead> | |
| 73 | <tbody> | |
| 74 | <tr><td><code class="verbatim">--</code></td><td>–</td></tr> | |
| 75 | <tr><td><code class="verbatim">---</code></td><td>—</td></tr> | |
| 76 | <tr><td><code class="verbatim">...</code></td><td>…</td></tr> | |
| 77 | <tr><td><code class="verbatim">x^2</code></td><td>x superscript 2</td></tr> | |
| 78 | <tr><td><code class="verbatim">H_{2}O</code></td><td>H subscript 2 O</td></tr> | |
| 79 | <tr><td><code class="verbatim">\alpha</code>, <code class="verbatim">\rarr</code>, <code class="verbatim">20\deg</code></td><td>α, →, 20°</td></tr> | |
| 80 | </tbody> | |
| 81 | </table> | |
| 82 | <p>The entity table is org's own, generated from Emacs' <code class="verbatim">org-entities</code> rather than transcribed, so all 412 names behave as they do in Emacs. A name org does not know — <code class="verbatim">\notanentity</code> — stays as the literal text you typed, and <code class="verbatim">\alphabet</code> is a word rather than α followed by "bet". <code class="verbatim">#+OPTIONS: e:nil</code> turns the whole table off.</p> | |
| 83 | <p>Neither reaches inside verbatim, code, a source block or a LaTeX fragment — <code class="verbatim">--verbose</code> in a shell transcript stays a flag, and <code class="verbatim">$x^2$</code> stays mathematics.</p> | |
| 84 | <p><strong>Braceless subscripts catch people out.</strong> Org's default converts <code class="verbatim">a_b</code>, so <code class="verbatim">snake_case</code> in prose publishes as snake with a subscript. That is what Emacs does with the same file. Turn it off per document with <code class="verbatim">#+OPTIONS: ^:nil</code>, restrict it to the braced form with <code class="verbatim">^:{}</code>, or set <code class="verbatim">[html] sub_superscript</code> for the site. <code class="verbatim">#+OPTIONS: -:nil</code> turns off the dashes and ellipsis.</p> | |
| 85 | <h4 id="heading-levels-are-relative">Heading levels are relative</h4> | |
| 86 | <p>A file whose shallowest heading is <code class="verbatim">**</code> is a file of top-level sections that happen to be indented, not a file of subsections — org exports levels relative to the document, so that subtree exports the same whether it was cut from a larger file or written on its own.</p> | |
| 87 | <h3 id="lists">Lists</h3> | |
| 88 | <p>Unordered, ordered and description lists, nested by indentation, with checkboxes and multi-paragraph items:</p> | |
| 89 | <pre><code class="language-org highlight"><span class="text org"><span class="punctuation definition list org">- </span>outer item | |
| 90 | <span class="punctuation definition list org"> - </span>inner item | |
| 91 | <span class="punctuation definition list org">- </span><span class="constant language checkbox org">[X]</span> a checked item | |
| 92 | <span class="punctuation definition list org">- </span><span class="constant language checkbox org">[-]</span> a partly-done item | |
| 93 | <span class="punctuation definition list org">- </span>term :: definition | |
| 94 | <span class="punctuation definition list org">1. </span>[@4] an item numbered from 4</span></code></pre> | |
| 95 | <p>Checkboxes render as org writes them — <code class="verbatim"><code>[X]</code></code> with the state as a class on the item — rather than as a disabled <code class="verbatim"><input></code>, which has no way to say "partly done".</p> | |
| 96 | <h3 id="blocks">Blocks</h3> | |
| 97 | <p><code class="verbatim">SRC</code> (syntax highlighted), <code class="verbatim">EXAMPLE</code>, <code class="verbatim">QUOTE</code>, <code class="verbatim">CENTER</code>, <code class="verbatim">VERSE</code> and <code class="verbatim">EXPORT</code>. A source block inside a quote block works, because block ends match their own kind.</p> | |
| 98 | <p>An <code class="verbatim">html</code> export block passes through verbatim; every other backend is dropped, because emitting LaTeX into an HTML page is worse than emitting nothing.</p> | |
| 99 | <p><strong>Any other name is a special block</strong>: <code class="verbatim">#+BEGIN_NOTE</code> becomes <code class="verbatim"><div class</code>"note">= holding <strong>parsed org</strong>, which is what makes the convention usable without orgo knowing the word "note". A <code class="verbatim">COMMENT</code> block is not published.</p> | |
| 100 | <h4 id="which-languages-highlight">Which languages highlight</h4> | |
| 101 | <p>Highlighting uses the syntax definitions <a href="https://docs.rs/syntect">syntect</a> bundles. A language it does not know is not an error — the block renders as escaped <code class="verbatim"><pre><code class</code>"language-…">= with its content intact, just uncoloured.</p> | |
| 102 | <p>Recognised, among others: <code class="verbatim">bash</code> / <code class="verbatim">sh</code>, <code class="verbatim">c</code>, <code class="verbatim">c++</code>, <code class="verbatim">css</code>, <code class="verbatim">clojure</code>, <code class="verbatim">diff</code>, <code class="verbatim">erlang</code>, <code class="verbatim">go</code>, <code class="verbatim">haskell</code>, <code class="verbatim">html</code>, <code class="verbatim">java</code>, <code class="verbatim">javascript</code>, <code class="verbatim">json</code>, <code class="verbatim">latex</code>, <code class="verbatim">lisp</code>, <code class="verbatim">lua</code>, <code class="verbatim">makefile</code>, <code class="verbatim">markdown</code>, <code class="verbatim">matlab</code>, <code class="verbatim">objective-c</code>, <code class="verbatim">ocaml</code>, <code class="verbatim">perl</code>, <code class="verbatim">php</code>, <code class="verbatim">python</code>, <code class="verbatim">r</code>, <code class="verbatim">ruby</code>, <code class="verbatim">rust</code>, <code class="verbatim">scala</code>, <code class="verbatim">sql</code>, <code class="verbatim">tcl</code>, <code class="verbatim">xml</code>, <code class="verbatim">yaml</code>.</p> | |
| 103 | <p>orgo adds two syntect does not ship: <strong>TOML</strong> and <strong>Org</strong>. Both are what this project's own documentation needed on its first page — every config example is TOML, and a tool for org users gets written about in org — so they are compiled into the binary and work with no setup.</p> | |
| 104 | <p>Still missing, and worth knowing before you write a page full of them: <strong>INI</strong> and <strong>Emacs Lisp</strong>. For those, drop a <code class="verbatim">.sublime-syntax</code> file into the directory named by <code class="verbatim">[highlight] syntaxes_dir</code> (default <code class="verbatim">syntaxes/</code>) and it is picked up. A file that fails to parse is reported and skipped rather than failing the build.</p> | |
| 105 | <h4 id="the-comma-escape">The comma escape</h4> | |
| 106 | <p>A line inside a block that would otherwise look like document structure is written with a leading comma — <code class="verbatim">,* heading</code>, <code class="verbatim">,#+KEYWORD:</code> — and orgo removes exactly one comma on output, as Emacs does. Every org example in this documentation relies on it.</p> | |
| 107 | <p>The escape is not optional politeness: an unescaped <code class="verbatim">*</code> at column zero <strong>ends the block</strong>, in Emacs as much as here. If a code block seems to stop early, that is why.</p> | |
| 108 | <h3 id="tables-and-footnotes">Tables and footnotes</h3> | |
| 109 | <p>Pipe tables, with the rule row establishing a header band and an affiliated <code class="verbatim">#+CAPTION:</code> becoming a numbered <code class="verbatim"><caption></code>. Org's <strong>special column</strong> is honoured: a first column holding only export markers (<code class="verbatim">/</code>, <code class="verbatim">#</code>, <code class="verbatim">!</code>, <code class="verbatim">^</code>, <code class="verbatim">_</code>, <code class="verbatim">$</code>) is dropped, and rows marked <code class="verbatim">/</code>, <code class="verbatim">!</code>, <code class="verbatim">^</code>, <code class="verbatim">_</code> or <code class="verbatim">$</code> are instructions to org rather than content, so they never reach the page.</p> | |
| 110 | <p>Footnotes in all three forms — <code class="verbatim">[fn:1]</code> references, <code class="verbatim">[fn:1]</code> definitions and <code class="verbatim">[fn:1:inline text]</code> — rendered as a numbered, back-linked notes section.</p> | |
| 111 | <h3 id="images">Images</h3> | |
| 112 | <p>A description-less link to an image file renders as <code class="verbatim"><img></code>. With an affiliated <code class="verbatim">#+CAPTION:</code> or <code class="verbatim">#+ATTR_HTML:</code> it becomes a <code class="verbatim"><figure></code> with the caption as both <code class="verbatim"><figcaption></code> and alt text:</p> | |
| 113 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+CAPTION:</span><span class="string unquoted org"> The pipeline, end to end</span> | |
| 114 | <span class="keyword other keyword org">#+ATTR_HTML:</span><span class="string unquoted org"> :width 640 :class diagram</span> | |
| 115 | <span class="punctuation definition link org">[[</span><span class="markup underline link org">file:pipeline.svg</span><span class="punctuation definition link org">]</span><span class="punctuation definition link org">]</span></span></code></pre> | |
| 116 | <p>Links to non-<code class="verbatim">.org</code> files are understood as asset links: neither resolved nor reported as broken.</p> | |
| 117 | <h2 id="keywords-with-meaning">Keywords with meaning</h2> | |
| 118 | <table> | |
| 119 | <thead> | |
| 120 | <tr><th>Keyword</th><th>Effect</th></tr> | |
| 121 | </thead> | |
| 122 | <tbody> | |
| 123 | <tr><td><code class="verbatim">#+TITLE:</code></td><td>Page title. Falls back to the filename stem.</td></tr> | |
| 124 | <tr><td><code class="verbatim">#+DATE:</code></td><td>Sorts listings. Any org date syntax.</td></tr> | |
| 125 | <tr><td><code class="verbatim">#+DESCRIPTION:</code></td><td>The excerpt shown in listings.</td></tr> | |
| 126 | <tr><td><code class="verbatim">#+FILETAGS:</code></td><td>Tags, for grouping and <code class="verbatim">page.tags</code>.</td></tr> | |
| 127 | <tr><td><code class="verbatim">#+SLUG:</code></td><td>Sets the output filename.</td></tr> | |
| 128 | <tr><td><code class="verbatim">#+DRAFT:</code></td><td>Keeps the page out of the build.</td></tr> | |
| 129 | <tr><td><code class="verbatim">#+TEMPLATE:</code></td><td>The layout this page renders through.</td></tr> | |
| 130 | <tr><td><code class="verbatim">#+OPTIONS:</code></td><td>Per-file export switches.</td></tr> | |
| 131 | <tr><td><code class="verbatim">#+CAPTION:</code>, <code class="verbatim">#+ATTR_HTML:</code></td><td>Attach to the image <strong>directly</strong> below them — a blank line in between attaches to nothing, as in org. A captioned image is numbered <code class="verbatim">Figure N:</code>.</td></tr> | |
| 132 | <tr><td><code class="verbatim">#+TBLFM:</code></td><td>Kept inert, and that matches org: the HTML exporter does not recalculate formulas either, so both emit the cells as written. Recalculate in Emacs (<code class="verbatim">C-c C-c</code>) to change them.</td></tr> | |
| 133 | </tbody> | |
| 134 | </table> | |
| 135 | <p>Every other <code class="verbatim">#+KEYWORD:</code> is available to templates as <code class="verbatim">{{ page.keywords.that_keyword }}</code>, so metadata orgo has never heard of still reaches your layout.</p> | |
| 136 | <h2 id="not-supported-and-what-happens-instead">Not supported, and what happens instead</h2> | |
| 137 | <p>The contract is not that these work — it is that they degrade predictably and never crash a build.</p> | |
| 138 | <table> | |
| 139 | <thead> | |
| 140 | <tr><th>Construct</th><th>What happens</th></tr> | |
| 141 | </thead> | |
| 142 | <tbody> | |
| 143 | <tr><td>Babel execution, <code class="verbatim">:results</code></td><td>The source block renders as code. A checked-in <code class="verbatim">#+RESULTS:</code> block is <strong>dropped</strong>.</td></tr> | |
| 144 | <tr><td><code class="verbatim">#+INCLUDE:</code></td><td>Never expanded, and <strong>reported</strong>: the build prints <code class="verbatim">file:line: `#+INCLUDE: …` is not expanded</code>, so a page is never quietly missing content. <code class="verbatim">--strict</code> makes it a failure.</td></tr> | |
| 145 | <tr><td>LaTeX, MathJax</td><td>Survives as the literal text you typed.</td></tr> | |
| 146 | <tr><td>Macros <code class="verbatim">{{{name}}}</code>, radio targets</td><td>Literal text.</td></tr> | |
| 147 | <tr><td>Drawers other than <code class="verbatim">PROPERTIES</code></td><td>Captured and dropped, including <code class="verbatim">LOGBOOK</code>.</td></tr> | |
| 148 | <tr><td>Non-HTML export blocks</td><td>Dropped entirely.</td></tr> | |
| 149 | <tr><td><code class="verbatim">#+TODO:</code> sequences</td><td>Not read; the default keyword set is used.</td></tr> | |
| 150 | <tr><td>Planning lines, =: = fixed-width</td><td>Render as ordinary paragraphs.</td></tr> | |
| 151 | </tbody> | |
| 152 | </table> | |
| 153 | <h3 id="why-results-is-dropped-rather-than-rendered">Why #+RESULTS: is dropped rather than rendered</h3> | |
| 154 | <p>Babel is never executed, so a checked-in results block is output from someone else's Emacs session at some other time. Emitting it would put unverifiable content on the page dressed as real content. The source block renders; its stale output does not.</p> | |
| 155 | <h2 id="diagnostics">Diagnostics</h2> | |
| 156 | <p>Malformed input degrades rather than failing — but not <strong>silently</strong>, because the worst cases are severe. An unterminated <code class="verbatim">#+BEGIN_SRC</code> reads the rest of the file as block content, and an unterminated drawer does the same but renders to nothing, so one missing line can delete most of a page.</p> | |
| 157 | <pre>warning: post.org:42: unterminated `#+BEGIN_SRC` block (no `#+END_SRC`); everything to | |
| 158 | the end of the file was read as block content</pre> | |
| 159 | <p>Diagnostics carry exact line numbers through arbitrarily nested constructs, and <code class="verbatim">--strict</code> turns them into a non-zero exit.</p> | |
| 160 | <h2 id="measured-against-emacs">Measured against Emacs</h2> | |
| 161 | <p><code class="verbatim">cargo test --test oracle</code> exports each fixture with org's own exporter via <code class="verbatim">emacs --batch</code> and snapshots the disagreement. Heading structure, list nesting and source-block text are asserted to match exactly.</p> | |
| 162 | <p>The rest differs deliberately:</p> | |
| 163 | <table> | |
| 164 | <thead> | |
| 165 | <tr><th></th><th>orgo</th><th>Emacs</th></tr> | |
| 166 | </thead> | |
| 167 | <tbody> | |
| 168 | <tr><td>emphasis</td><td><code class="verbatim"><em></code> / <code class="verbatim"><strong></code></td><td><code class="verbatim"><i></code> / <code class="verbatim"><b></code></td></tr> | |
| 169 | <tr><td>captioned image</td><td><code class="verbatim"><figure></code> / <code class="verbatim"><figcaption></code></td><td><code class="verbatim"><p></code> + "Figure 1: …"</td></tr> | |
| 170 | <tr><td>timestamp</td><td><code class="verbatim"><time datetime</code>"…">=</td><td>literal <code class="verbatim"><2024-01-15 Mon></code></td></tr> | |
| 171 | <tr><td>footnotes</td><td><code class="verbatim"><section><ol></code></td><td><code class="verbatim"><h2>Footnotes:</h2></code></td></tr> | |
| 172 | <tr><td>heading anchor</td><td>slug of the text</td><td><code class="verbatim">org1a2b3c4</code></td></tr> | |
| 173 | <tr><td>code</td><td><code class="verbatim"><pre><code></code></td><td><code class="verbatim"><pre></code></td></tr> | |
| 174 | </tbody> | |
| 175 | </table> | |
| 176 | <p>One genuine semantic difference: org treats a single blank line between a <code class="verbatim">1.</code> list and a following <code class="verbatim">-</code> list as <strong>one</strong> list, keeping the first item's bullet type. orgo starts a second list. That was kept on measurement — the pattern occurred zero times across a 179-file reference corpus — rather than on taste.</p> | |
| 177 | </main> | |
| 178 | <footer class="site"> | |
| 179 | Built with orgo — these docs are an orgo site. | |
| 180 | </footer> | |
| 181 | </body> | |
| 182 | </html> | |
| \ No newline at end of file | ||
guide/06-authoring.html added +98
| @@ -0,0 +1,98 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Authoring · orgo</title> | |
| 7 | <meta name="description" content="URLs, drafts, excerpts, tables of contents — the metadata that shapes a page."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Authoring</h1> | |
| 24 | <p class="lede">What to put at the top of a file, and what each keyword buys you.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#urls">URLs</a></li> | |
| 29 | <li><a href="#drafts">Drafts</a></li> | |
| 30 | <li><a href="#dates">Dates</a></li> | |
| 31 | <li><a href="#excerpts">Excerpts</a></li> | |
| 32 | <li><a href="#reading-time">Reading time</a></li> | |
| 33 | <li><a href="#tags">Tags</a></li> | |
| 34 | <li><a href="#table-of-contents">Table of contents</a></li> | |
| 35 | <li><a href="#section-numbers">Section numbers</a></li> | |
| 36 | <li><a href="#your-own-metadata">Your own metadata</a></li> | |
| 37 | <li><a href="#assets">Assets</a></li> | |
| 38 | </ul> | |
| 39 | </nav> | |
| 40 | <h2 id="urls">URLs</h2> | |
| 41 | <p>By default a source path becomes the matching output path: <code class="verbatim">blog/post.org</code> → <code class="verbatim">blog/post.html</code>.</p> | |
| 42 | <p><code class="verbatim">#+SLUG:</code> overrides the <strong>filename</strong>, never the directory:</p> | |
| 43 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+TITLE:</span><span class="string unquoted org"> AES Encryption</span> | |
| 44 | <span class="keyword other keyword org">#+SLUG:</span><span class="string unquoted org"> aes-encryption</span></span></code></pre> | |
| 45 | <p><code class="verbatim">blog/2018-11-28-aes-encryption.org</code> now publishes at <code class="verbatim">blog/aes-encryption.html</code>. This is how a date-prefixed filename — useful for sorting in a file manager — becomes a clean address.</p> | |
| 46 | <p>Slugs are reduced to a single safe path component, so a slug cannot escape the output directory however it was written. Two pages claiming one URL is a build error rather than one silently overwriting the other.</p> | |
| 47 | <p>Links follow slugs automatically: <code class="verbatim">[[file:blog/2018-11-28-aes-encryption.org]]</code> resolves to <code class="verbatim">blog/aes-encryption.html</code>.</p> | |
| 48 | <h2 id="drafts">Drafts</h2> | |
| 49 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+DRAFT:</span><span class="string unquoted org"> t</span></span></code></pre> | |
| 50 | <p>The page is not written at all, and is absent from listings, tag pages and navigation — not merely unlinked.</p> | |
| 51 | <p>It is also out of the symbol table, so a link <strong>to</strong> a draft is reported as a broken link. That is deliberate: it is what that link would be on the published site, and better found now than by a reader.</p> | |
| 52 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>drafts</span></span></span></code></pre> | |
| 53 | <p>The keyword is read forgivingly. <code class="verbatim">t</code>, <code class="verbatim">yes</code>, <code class="verbatim">1</code> and a bare <code class="verbatim">#+DRAFT:</code> all mean draft, because writing the keyword at all is the signal. Only an explicit <code class="verbatim">nil</code>, <code class="verbatim">false</code>, <code class="verbatim">no</code>, <code class="verbatim">0</code> or <code class="verbatim">off</code> means published — publishing someone's unfinished post because they typed <code class="verbatim">yes</code> instead of <code class="verbatim">t</code> is the wrong way to be strict.</p> | |
| 54 | <h2 id="dates">Dates</h2> | |
| 55 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+DATE:</span><span class="string unquoted org"> <2026-02-02 Mon></span> | |
| 56 | <span class="keyword other keyword org">#+DATE:</span><span class="string unquoted org"> [2025-09-05 Fri 10:21:00]</span> | |
| 57 | <span class="keyword other keyword org">#+DATE:</span><span class="string unquoted org"> 2024-05-01</span></span></code></pre> | |
| 58 | <p>All three work. <code class="verbatim">page.date</code> keeps what you wrote, and <code class="verbatim">page.date_iso</code> is the <code class="verbatim">YYYY-MM-DD</code> inside it — the value listings sort on and templates usually print.</p> | |
| 59 | <p>A page with no parseable date sorts <strong>last</strong> in a dated listing, in either direction, so a draft with no date never leads an archive.</p> | |
| 60 | <h2 id="excerpts">Excerpts</h2> | |
| 61 | <p><code class="verbatim">page.excerpt</code> is <code class="verbatim">#+DESCRIPTION:</code> when the page sets one, and its first paragraph otherwise:</p> | |
| 62 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+DESCRIPTION:</span><span class="string unquoted org"> How the borrow checker thinks about lifetimes.</span></span></code></pre> | |
| 63 | <p>The fallback matters more than the keyword: it means a listing has something to show whether or not the author ever thought about summaries. Use <code class="verbatim">truncate</code> in the template to cut a long paragraph to size.</p> | |
| 64 | <h2 id="reading-time">Reading time</h2> | |
| 65 | <p><code class="verbatim">page.word_count</code> and <code class="verbatim">page.reading_time</code> (minutes at 200 wpm, rounded up) count <strong>prose only</strong>. Source and example blocks are excluded, because a post that is mostly a shell transcript should not read as an hour's work. <code class="verbatim">#+TITLE:</code> is metadata rendered as chrome, so it is not counted either.</p> | |
| 66 | <h2 id="tags">Tags</h2> | |
| 67 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+FILETAGS:</span><span class="string unquoted org"> :rust:web:</span></span></code></pre> | |
| 68 | <p>Available as <code class="verbatim">page.tags</code>, and the input to tag pages — see <a href="03-collections.html">Collections</a>.</p> | |
| 69 | <h2 id="table-of-contents">Table of contents</h2> | |
| 70 | <p>Every page's heading tree is available as <code class="verbatim">page.toc</code> without any markup in the file. Turn it off for one document the way org already does:</p> | |
| 71 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+OPTIONS:</span><span class="string unquoted org"> toc:nil</span></span></code></pre> | |
| 72 | <p>Or site-wide with <code class="verbatim">[html] toc = false</code>. Rendering it is the template's business; see <a href="04-templates.html">Templates</a>.</p> | |
| 73 | <h2 id="section-numbers">Section numbers</h2> | |
| 74 | <p>Off by default, unlike Emacs. Turn them on for one document:</p> | |
| 75 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+OPTIONS:</span><span class="string unquoted org"> num:t</span></span></code></pre> | |
| 76 | <p>Or site-wide with <code class="verbatim">[html] section_numbers = true</code>.</p> | |
| 77 | <h2 id="your-own-metadata">Your own metadata</h2> | |
| 78 | <p>Every <code class="verbatim">#+KEYWORD:</code> reaches templates under its lowercased name:</p> | |
| 79 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+SUBTITLE:</span><span class="string unquoted org"> A closer look</span> | |
| 80 | <span class="keyword other keyword org">#+REVIEWED_BY:</span><span class="string unquoted org"> someone</span></span></code></pre> | |
| 81 | <pre><code class="language-html highlight"><span class="text html basic">{% if page.keywords.subtitle %}<span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">p</span> <span class="meta attribute-with-value class html"><span class="entity other attribute-name class html">class</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span></span></span><span class="meta attribute-with-value class html"><span class="string quoted double html"><span class="meta class-name html">subtitle</span><span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ page.keywords.subtitle }}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">p</span><span class="punctuation definition tag end html">></span></span>{% endif %}</span></code></pre> | |
| 82 | <p>Nothing needs to be registered, and orgo needs no release to support a keyword you invented.</p> | |
| 83 | <h2 id="assets">Assets</h2> | |
| 84 | <p>Any non-<code class="verbatim">.org</code> file in the source directory is copied to the output, preserving layout: <code class="verbatim">content/img/diagram.png</code> → <code class="verbatim">_site/img/diagram.png</code>. Reference it from a page with an ordinary relative link, and from a template with <code class="verbatim">{{ root }}img/diagram.png</code>.</p> | |
| 85 | <p>Four things are <strong>never</strong> published:</p> | |
| 86 | <ul> | |
| 87 | <li>Dot-entries such as <code class="verbatim">.git</code> and <code class="verbatim">.env</code>. A source directory is often a repository, and publishing its history next to the homepage is a real way to leak a project.</li> | |
| 88 | <li><code class="verbatim">orgo.toml</code>, which is a build input.</li> | |
| 89 | <li>The templates directory, likewise.</li> | |
| 90 | <li>The output directory, when it lives inside the source — so <code class="verbatim">orgo build . -o _site</code> does the obvious thing rather than copying its own output back into itself.</li> | |
| 91 | </ul> | |
| 92 | <p>Note that excluding dot-entries also means <code class="verbatim">.well-known/</code> cannot be published.</p> | |
| 93 | </main> | |
| 94 | <footer class="site"> | |
| 95 | Built with orgo — these docs are an orgo site. | |
| 96 | </footer> | |
| 97 | </body> | |
| 98 | </html> | |
| \ No newline at end of file | ||
guide/07-incremental.html added +104
| @@ -0,0 +1,104 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Incremental builds · orgo</title> | |
| 7 | <meta name="description" content="How the cache decides what to re-render, and why that shape is the architecture."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Incremental builds</h1> | |
| 24 | <p class="lede">Editing one post rebuilds four pages, whatever the size of the site.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#what-you-observe">What you observe</a></li> | |
| 29 | <li><a href="#the-render-key">The render key</a> | |
| 30 | <ul> | |
| 31 | <li><a href="#template-scope">Template scope</a></li> | |
| 32 | </ul></li> | |
| 33 | <li><a href="#link-dependencies">Link dependencies</a></li> | |
| 34 | <li><a href="#global-chrome">Global chrome</a></li> | |
| 35 | <li><a href="#generated-pages">Generated pages</a></li> | |
| 36 | <li><a href="#byte-equivalence">Byte equivalence</a></li> | |
| 37 | <li><a href="#parallelism">Parallelism</a></li> | |
| 38 | <li><a href="#when-to-reach-for-no-cache">When to reach for --no-cache</a></li> | |
| 39 | </ul> | |
| 40 | </nav> | |
| 41 | <p>Incremental rebuilding is not an optimisation bolted on to orgo; it is the constraint the data model was built around. Parsing is a pure function of one file's bytes, link resolution reports the edges it used, and rendering is a pure function of a resolved document. Those properties are what make caching sound — and they are also what make the build parallel.</p> | |
| 42 | <p>You do not have to configure any of this. It is described here because knowing what invalidates what explains the behaviour you will see.</p> | |
| 43 | <h2 id="what-you-observe">What you observe</h2> | |
| 44 | <pre>$ orgo build content -o _site | |
| 45 | built 182 page(s) (182 rendered, 0 cached) ... | |
| 46 | ||
| 47 | $ orgo build content -o _site | |
| 48 | built 182 page(s) (0 rendered, 182 cached) ... | |
| 49 | ||
| 50 | $ vim content/blog/post.org && orgo build content -o _site | |
| 51 | built 182 page(s) (4 rendered, 178 cached) ...</pre> | |
| 52 | <p>The four are the post itself, its section index, its tag page, and the tag index whose counts changed.</p> | |
| 53 | <h2 id="the-render-key">The render key</h2> | |
| 54 | <p>Every page has a key composed from four hashes:</p> | |
| 55 | <table> | |
| 56 | <thead> | |
| 57 | <tr><th>Component</th><th>Changes when</th></tr> | |
| 58 | </thead> | |
| 59 | <tbody> | |
| 60 | <tr><td>content</td><td>The source file's bytes change.</td></tr> | |
| 61 | <tr><td>resolved links</td><td>A link's target moves, is renamed, or disappears.</td></tr> | |
| 62 | <tr><td>config</td><td><code class="verbatim">orgo.toml</code> changes, or the shared chrome does.</td></tr> | |
| 63 | <tr><td>templates</td><td><strong>This page's</strong> layout changes, or something that layout extends or includes.</td></tr> | |
| 64 | </tbody> | |
| 65 | </table> | |
| 66 | <p>If a page's key matches the cached one and its output file still exists, the file on disk is already correct and is left untouched.</p> | |
| 67 | <h3 id="template-scope">Template scope</h3> | |
| 68 | <p>The template component covers the layout a page actually renders through, plus everything that layout pulls in — followed through <code class="verbatim">{% extends %}</code>, <code class="verbatim">{% include %}</code>, <code class="verbatim">{% import %}</code> and <code class="verbatim">{% from %}</code>. Editing <code class="verbatim">feed.xml</code> on a 196-page site re-renders one page; editing a <code class="verbatim">post.html</code> that only blog posts use re-renders the posts. <code class="verbatim">base.html</code> is extended by almost everything, so editing it still re-renders almost everything — which is correct, and is why the win shows up on the <strong>other</strong> edits.</p> | |
| 69 | <p>A template whose include is computed at render time — <code class="verbatim">{% include chooser %}</code> — cannot be followed, so it is treated as depending on every template. Over-invalidating costs time; under-invalidating publishes a stale page.</p> | |
| 70 | <p>The cache lives in <code class="verbatim"><output>/.orgo-cache.json</code> and is tagged with a format version. A version mismatch, a missing file or a corrupt file all fall back to a full rebuild — the cache is an optimisation, never a correctness dependency. There is a test for each of those three fallbacks.</p> | |
| 71 | <h2 id="link-dependencies">Link dependencies</h2> | |
| 72 | <p>Resolution records which targets each page consumed, which gives the build a dependency graph. That is what makes renaming a heading work:</p> | |
| 73 | <pre>a.org: * Target Heading | |
| 74 | b.org: Jump to [[*Target Heading][there]].</pre> | |
| 75 | <p>Rename the heading in <code class="verbatim">a.org</code> and <strong>both</strong> pages re-render — <code class="verbatim">b.org</code> because the URL it emits has changed. Without the graph, <code class="verbatim">b.html</code> would keep a link to an anchor that no longer exists. On a rebuild the graph is merged with the previous build's, so a target that was <strong>removed</strong> still pulls in the pages that linked to it.</p> | |
| 76 | <h2 id="global-chrome">Global chrome</h2> | |
| 77 | <p>The navigation appears on every page, so a change to it must re-render every page. The site-structure hash covers exactly the pages that can appear in the nav — which is why the default <code class="verbatim">nav.mode = "top-level"</code> matters for more than aesthetics:</p> | |
| 78 | <ul> | |
| 79 | <li>Retitling a <strong>top-level</strong> page changes the nav everywhere, and re-renders the site.</li> | |
| 80 | <li>Adding a <strong>nested</strong> page cannot change anyone's nav, and re-renders one page.</li> | |
| 81 | </ul> | |
| 82 | <p>Turning on <code class="verbatim">[templates] expose_page_list</code> widens that hash to every page, because then any template can read any page's metadata. That is the documented cost of building an index by hand instead of with a collection.</p> | |
| 83 | <h2 id="generated-pages">Generated pages</h2> | |
| 84 | <p>A listing page has no source file, so it is cached on the thing it actually depends on: the entries it lists — their URLs, titles, dates and tags.</p> | |
| 85 | <ul> | |
| 86 | <li>Adding a post re-renders the indexes that list it.</li> | |
| 87 | <li>Editing a post's <strong>body</strong> changes no listing metadata, so no index is touched.</li> | |
| 88 | <li>Retitling a post re-renders the listings that display the title.</li> | |
| 89 | </ul> | |
| 90 | <p>A tag page depends on its own posts and not on the other groups. That is why the group list is given to the tag <strong>index</strong> and not to every tag page: a page that could see every group would depend on every group, and one new post would re-render every tag page.</p> | |
| 91 | <h2 id="byte-equivalence">Byte equivalence</h2> | |
| 92 | <p>A full build (<code class="verbatim">--no-cache</code>) and an incremental rebuild produce <strong>byte-identical</strong> output. This is the property everything else rests on, and it is a test rather than an intention: the suite builds a site both ways and compares every emitted file.</p> | |
| 93 | <h2 id="parallelism">Parallelism</h2> | |
| 94 | <p>Parsing, resolution and rendering run across cores. Measured on a 1,790-page corpus, a full build went from 3.98s to 0.82s on 12 cores; the 179-page reference corpus builds in 0.07s.</p> | |
| 95 | <p>Parallelism is not observable in the result. Emitted bytes are unaffected, and the build <strong>report</strong> — the order of <code class="verbatim">rendered</code> and <code class="verbatim">skipped</code> — is assembled sequentially afterwards, so a build is reproducible run to run. There is a test for that ordering, because a non-deterministic report over a deterministic site would be a confusing thing to debug.</p> | |
| 96 | <h2 id="when-to-reach-for-no-cache">When to reach for –no-cache</h2> | |
| 97 | <p>Almost never. Config changes, template edits and cache-format upgrades all invalidate correctly on their own. It exists to answer "is the cache lying to me?" — and if it ever is, that is a bug worth reporting, with the two builds' output to compare.</p> | |
| 98 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>no-cache</span></span></span></code></pre> | |
| 99 | </main> | |
| 100 | <footer class="site"> | |
| 101 | Built with orgo — these docs are an orgo site. | |
| 102 | </footer> | |
| 103 | </body> | |
| 104 | </html> | |
| \ No newline at end of file | ||
guide/08-workflow.html added +96
| @@ -0,0 +1,96 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Watching and serving · orgo</title> | |
| 7 | <meta name="description" content="The write-save-see loop, and what the development server does and does not do."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Watching and serving</h1> | |
| 24 | <p class="lede">Filesystem events, debounced rebuilds, and a browser that reloads itself.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#serve">serve</a> | |
| 29 | <ul> | |
| 30 | <li><a href="#it-binds-loopback-deliberately">It binds loopback deliberately</a></li> | |
| 31 | <li><a href="#the-reload-script-never-reaches-disk">The reload script never reaches disk</a></li> | |
| 32 | <li><a href="#how-reload-works">How reload works</a></li> | |
| 33 | </ul></li> | |
| 34 | <li><a href="#watch">watch</a></li> | |
| 35 | <li><a href="#what-counts-as-a-change">What counts as a change</a></li> | |
| 36 | <li><a href="#debouncing">Debouncing</a></li> | |
| 37 | <li><a href="#rebuild-failures-do-not-stop-the-session">Rebuild failures do not stop the session</a></li> | |
| 38 | <li><a href="#where-native-watching-is-unavailable">Where native watching is unavailable</a></li> | |
| 39 | <li><a href="#serving-details">Serving details</a></li> | |
| 40 | <li><a href="#a-typical-session">A typical session</a></li> | |
| 41 | </ul> | |
| 42 | </nav> | |
| 43 | <h2 id="serve">serve</h2> | |
| 44 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site</span></span></code></pre> | |
| 45 | <p>Builds, watches, serves at <a href="http://127.0.0.1:3000">127.0.0.1:3000</a>, and reloads the browser when a rebuild lands. This is the command to leave running while you write.</p> | |
| 46 | <p>Add <code class="verbatim">--drafts</code> to see work in progress, <code class="verbatim">--port</code> to move it, and <code class="verbatim">--host 0.0.0.0</code> to reach it from another device.</p> | |
| 47 | <h3 id="it-binds-loopback-deliberately">It binds loopback deliberately</h3> | |
| 48 | <p>A development server serves unreviewed drafts off your laptop. Exposing that to whatever network you are on — a café, a conference, an office — should be something you ask for, so the default is <code class="verbatim">127.0.0.1</code> and <code class="verbatim">--host</code> is the way out.</p> | |
| 49 | <h3 id="the-reload-script-never-reaches-disk">The reload script never reaches disk</h3> | |
| 50 | <p>The script is injected into HTML <strong>responses</strong>, not into the built files. What you deploy is the site as built, with no development machinery in it. If you are curious, compare a served page with the file in your output directory.</p> | |
| 51 | <h3 id="how-reload-works">How reload works</h3> | |
| 52 | <p>The page carries the build generation it was rendered from, and asks the server "anything newer than N?". The server holds that request open until there is, then answers — so a reload is immediate rather than polled, but the mechanism is ordinary HTTP with no WebSocket.</p> | |
| 53 | <p>Baking the generation into the page closes a race: if a rebuild lands between a page being served and its first request going out, the server answers at once instead of the tab sitting on stale content until your <strong>next</strong> edit.</p> | |
| 54 | <p>A reload only follows a <strong>successful</strong> rebuild. Reloading onto an unchanged page because the build just failed tells you nothing — the error is already on your terminal.</p> | |
| 55 | <h2 id="watch">watch</h2> | |
| 56 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> watch content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site</span></span></code></pre> | |
| 57 | <p>The same rebuilding without the server, for when something else already serves the output.</p> | |
| 58 | <h2 id="what-counts-as-a-change">What counts as a change</h2> | |
| 59 | <p>Rebuilds are driven by OS filesystem events, so nothing happens while nothing happens. The rule for what triggers one is deliberately <strong>not</strong> the rule the build uses to find content — the question is "would this change the site?", not "is this a page?".</p> | |
| 60 | <p><strong>Triggers a rebuild:</strong> any <code class="verbatim">.org</code> file, any asset, <code class="verbatim">orgo.toml</code>, and anything in the templates directory. The last two are skipped by the build when looking for content, but both change the output.</p> | |
| 61 | <p><strong>Does not:</strong></p> | |
| 62 | <ul> | |
| 63 | <li>The output directory. Without this the build's own writes would raise events that trigger a rebuild, forever.</li> | |
| 64 | <li>Dot-directories. <code class="verbatim">.git</code> churns on every command, and rebuilding a site because git wrote an index lock would make watching useless in a repository.</li> | |
| 65 | <li>Editor scratch files: <code class="verbatim">file.org~</code>, <code class="verbatim">#file.org#</code>, <code class="verbatim">.#file.org</code>, <code class="verbatim">*.swp</code>, <code class="verbatim">*.tmp</code>. Emacs' backup files matter here — they do not start with a dot, so they would otherwise look exactly like content.</li> | |
| 66 | </ul> | |
| 67 | <h2 id="debouncing">Debouncing</h2> | |
| 68 | <p>Saving a file is rarely one event: an editor writes a temp file, renames it over the original, and touches the directory. Events are collected for 120ms of quiet before a rebuild starts, so one save is one rebuild.</p> | |
| 69 | <h2 id="rebuild-failures-do-not-stop-the-session">Rebuild failures do not stop the session</h2> | |
| 70 | <p>A build that fails prints the error and keeps watching. The usual cause is a half-saved file, and the next keystroke fixes it. Nothing needs restarting.</p> | |
| 71 | <pre>blog/post.org changed: build failed: parsing blog/post.org: ... | |
| 72 | blog/post.org changed: 2 rendered, 180 cached</pre> | |
| 73 | <h2 id="where-native-watching-is-unavailable">Where native watching is unavailable</h2> | |
| 74 | <p>Some network and container filesystems have no event API. orgo falls back to polling every two seconds and says so, rather than failing:</p> | |
| 75 | <pre>note: native file watching unavailable (...); polling every 2s</pre> | |
| 76 | <h2 id="serving-details">Serving details</h2> | |
| 77 | <ul> | |
| 78 | <li><code class="verbatim">/</code> and any directory URL serve <code class="verbatim">index.html</code>.</li> | |
| 79 | <li>Content types are set by extension; unknown extensions are served as binary.</li> | |
| 80 | <li>Everything is sent <code class="verbatim">Cache-Control: no-store</code>, because a cached dev response makes an edit look like it did not land.</li> | |
| 81 | <li>URL resolution refuses to leave the output directory. <code class="verbatim">..</code>, percent-encoded <code class="verbatim">..</code>, backslashes, absolute paths and embedded NULs all resolve to nothing.</li> | |
| 82 | </ul> | |
| 83 | <h2 id="a-typical-session">A typical session</h2> | |
| 84 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> One terminal, left running.</span><span class="comment line number-sign shell"> | |
| 85 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>drafts</span></span> | |
| 86 | ||
| 87 | <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> Write. The browser keeps up.</span><span class="comment line number-sign shell"> | |
| 88 | </span> | |
| 89 | <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> Before publishing, check what a real build says.</span><span class="comment line number-sign shell"> | |
| 90 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span></span></code></pre> | |
| 91 | </main> | |
| 92 | <footer class="site"> | |
| 93 | Built with orgo — these docs are an orgo site. | |
| 94 | </footer> | |
| 95 | </body> | |
| 96 | </html> | |
| \ No newline at end of file | ||
guide/09-auditing.html added +91
| @@ -0,0 +1,91 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Auditing a corpus · orgo</title> | |
| 7 | <meta name="description" content="Find out what a tool will make of your writing before you trust it with it."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Auditing a corpus</h1> | |
| 24 | <p class="lede">Construct frequencies, unknown-name census, and no document text in the output.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#reading-the-output">Reading the output</a></li> | |
| 29 | <li><a href="#it-never-prints-your-writing">It never prints your writing</a></li> | |
| 30 | <li><a href="#why-it-is-a-separate-scanner">Why it is a separate scanner</a></li> | |
| 31 | <li><a href="#comparing-against-emacs">Comparing against Emacs</a></li> | |
| 32 | <li><a href="#using-the-audit-before-a-migration">Using the audit before a migration</a></li> | |
| 33 | </ul> | |
| 34 | </nav> | |
| 35 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> audit <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/notes</span></span></code></pre> | |
| 36 | <p>The audit answers two questions about a body of org files:</p> | |
| 37 | <ol> | |
| 38 | <li><strong>Coverage.</strong> Of the constructs this corpus uses, which are supported? A construct that is common here and unsupported is a problem with the tool's scope, not with your writing.</li> | |
| 39 | <li><strong>Blind spots.</strong> Which names appear that orgo has no opinion about at all? These are the dangerous ones — not "known unsupported" but unknown.</li> | |
| 40 | </ol> | |
| 41 | <h2 id="reading-the-output">Reading the output</h2> | |
| 42 | <pre>corpus: 180 file(s), 29742 line(s) | |
| 43 | ||
| 44 | CONSTRUCTS (by frequency) | |
| 45 | construct uses files first seen | |
| 46 | IN list item 1309 111 blog/2018-11-28-aes-encryption.org:53 | |
| 47 | IN heading 1148 176 blog/2018-11-28-aes-encryption.org:7 | |
| 48 | IN verbatim 1048 130 blog/2018-11-28-aes-encryption.org:79 | |
| 49 | ... | |
| 50 | IN table formula (#+TBLFM:) 4 1 blog/2024-08-11-org-mode-features.org:191 | |
| 51 | IN special block 1 1 blog/2026-03-03-auditing-aws-s3.org:50 | |
| 52 | ||
| 53 | coverage: 9002 in-scope use(s) (100.0%), 0 out-of-scope (0.0%) | |
| 54 | ||
| 55 | KEYWORDS | |
| 56 | SLUG 180 180 blog/2018-11-28-aes-encryption.org:4 | |
| 57 | TITLE 180 180 blog/2018-11-28-aes-encryption.org:2 | |
| 58 | — LEDE 14 14 blog/2018-11-28-aes-encryption.org:3 | |
| 59 | ...</pre> | |
| 60 | <ul> | |
| 61 | <li><code class="verbatim">IN</code> is supported; <code class="verbatim">OUT</code> is excluded by design and degrades as described in <a href="05-org-support.html">Org support</a>.</li> | |
| 62 | <li>The <strong>coverage</strong> line is the number to look at first.</li> | |
| 63 | <li><code class="verbatim">???</code> marks a name orgo does not recognise at all. That is the blind-spot signal — not "known unsupported", but unknown — and this corpus has none. Block names never carry it: an unrecognised one is still a special block, and still renders. Keyword names never carry it either — see below.</li> | |
| 64 | <li><code class="verbatim">—</code> marks a keyword with no dedicated handling. It is not a gap: the keyword reaches your layout as <code class="verbatim">{{ page.keywords.<name> }}</code>, which is the designed behaviour, so the marker tells you which of your keywords orgo reads by name and which rely on that pass-through.</li> | |
| 65 | </ul> | |
| 66 | <p>Four censuses follow the construct table: every distinct <code class="verbatim">#+KEYWORD:</code>, block type, drawer name and link scheme in the corpus. A <code class="verbatim">???</code> in any of them is worth a look.</p> | |
| 67 | <h2 id="it-never-prints-your-writing">It never prints your writing</h2> | |
| 68 | <p>Names, counts and <code class="verbatim">file:line</code> locations only. That is a deliberate constraint so that an audit of private notes — work notes, a journal — is safe to paste into an issue or share with someone helping you.</p> | |
| 69 | <h2 id="why-it-is-a-separate-scanner">Why it is a separate scanner</h2> | |
| 70 | <p>The audit deliberately does <strong>not</strong> reuse the parser. Auditing with the parser could only ever find constructs the parser already knows about, which is exactly the wrong instrument for the second question: it would report a blind spot as clean.</p> | |
| 71 | <h2 id="comparing-against-emacs">Comparing against Emacs</h2> | |
| 72 | <p>The second half of the same idea is a differential test suite. <code class="verbatim">cargo test --test oracle</code> exports each fixture with org's own HTML exporter through <code class="verbatim">emacs --batch</code>, reduces both outputs to a semantic skeleton, and <strong>snapshots the disagreement</strong>.</p> | |
| 73 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> test<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>test</span> oracle</span></span></code></pre> | |
| 74 | <p>Snapshotting rather than asserting agreement is deliberate: a checked-in divergence report gets reviewed and shows up in code review, where a permanently red test gets ignored. Three invariants <em>are</em> asserted outright — heading structure, list nesting and source-block text — and all three hold.</p> | |
| 75 | <p>The suite skips cleanly with no Emacs installed, so a machine without it still gets a green run; it simply measures one thing less.</p> | |
| 76 | <h2 id="using-the-audit-before-a-migration">Using the audit before a migration</h2> | |
| 77 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> What is in there?</span><span class="comment line number-sign shell"> | |
| 78 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> audit <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/notes</span> | |
| 79 | ||
| 80 | <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> Build it and see what the builder itself complains about.</span><span class="comment line number-sign shell"> | |
| 81 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/notes<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> /tmp/preview<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span> | |
| 82 | ||
| 83 | <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> Look at the result.</span><span class="comment line number-sign shell"> | |
| 84 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/notes<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> /tmp/preview</span></span></code></pre> | |
| 85 | <p><code class="verbatim">--strict</code> surfaces broken internal links and malformed constructs as failures rather than warnings, which is the fastest way to find the handful of files that need attention before you commit to anything.</p> | |
| 86 | </main> | |
| 87 | <footer class="site"> | |
| 88 | Built with orgo — these docs are an orgo site. | |
| 89 | </footer> | |
| 90 | </body> | |
| 91 | </html> | |
| \ No newline at end of file | ||
guide/10-deploying.html added +114
| @@ -0,0 +1,114 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Deploying · orgo</title> | |
| 7 | <meta name="description" content="Producing a production build, and putting it somewhere."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Deploying</h1> | |
| 24 | <p class="lede">The output is a directory of files. Everything after that is your host's problem.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#the-production-build">The production build</a></li> | |
| 29 | <li><a href="#set-base-url-for-production">Set base_url for production</a></li> | |
| 30 | <li><a href="#one-thing-to-exclude">One thing to exclude</a></li> | |
| 31 | <li><a href="#continuous-integration">Continuous integration</a> | |
| 32 | <ul> | |
| 33 | <li><a href="#caching-between-runs">Caching between runs</a></li> | |
| 34 | </ul></li> | |
| 35 | <li><a href="#static-hosts">Static hosts</a> | |
| 36 | <ul> | |
| 37 | <li><a href="#urls-end-in-html">URLs end in .html</a></li> | |
| 38 | </ul></li> | |
| 39 | <li><a href="#checking-a-build-before-shipping">Checking a build before shipping</a></li> | |
| 40 | <li><a href="#what-a-clean-build-looks-like">What a clean build looks like</a></li> | |
| 41 | <li><a href="#do-not-publish-the-cache">Do not publish the cache</a></li> | |
| 42 | <li><a href="#telling-a-search-engine-where-things-are">Telling a search engine where things are</a></li> | |
| 43 | <li><a href="#after-an-upgrade">After an upgrade</a></li> | |
| 44 | </ul> | |
| 45 | </nav> | |
| 46 | <h2 id="the-production-build">The production build</h2> | |
| 47 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span></span></code></pre> | |
| 48 | <p>Two differences from the build you run while writing:</p> | |
| 49 | <ul> | |
| 50 | <li><code class="verbatim">--strict</code> turns broken internal links and parse diagnostics into a non-zero exit, so a bad build fails rather than shipping.</li> | |
| 51 | <li>No <code class="verbatim">--drafts</code>, so pages marked <code class="verbatim">#+DRAFT:</code> stay out.</li> | |
| 52 | </ul> | |
| 53 | <p>Everything in <code class="verbatim">_site</code> is the site: HTML, the generated <code class="verbatim">syntax.css</code>, <code class="verbatim">theme.css</code> if the config names a <a href="02-configuration.html">theme</a>, and every asset copied from the source. There is no runtime, no server requirement and no build step downstream.</p> | |
| 54 | <h2 id="set-base-url-for-production">Set base<sub>url</sub> for production</h2> | |
| 55 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table toml">[</span><span class="entity name section toml">site</span><span class="punctuation definition table toml">]</span> | |
| 56 | <span class="variable other key toml">base_url</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>https://example.com<span class="punctuation definition string end toml">"</span></span></span></code></pre> | |
| 57 | <p>Relative URLs work anywhere, which is why the default is empty — but two things need absolute ones: <strong>feeds</strong>, because a feed is read away from the site that served it, and <strong>canonical links</strong>. Without a base URL the <code class="verbatim">absolute</code> filter is an error rather than a quietly relative link, so a feed template will tell you.</p> | |
| 58 | <p>No trailing slash.</p> | |
| 59 | <h2 id="one-thing-to-exclude">One thing to exclude</h2> | |
| 60 | <p>The build writes <code class="verbatim">.orgo-cache.json</code> into the output directory. It is a dot-file, so most static hosts ignore it, but it is not part of the site — exclude it if your host uploads everything:</p> | |
| 61 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">rsync</span></span><span class="meta function-call arguments shell"><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>a</span><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>delete</span><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>exclude</span> <span class="string quoted single shell"><span class="punctuation definition string begin shell">'</span>.orgo-cache.json<span class="punctuation definition string end shell">'</span></span> _site/ user@host:/var/www/site/</span></span></code></pre> | |
| 62 | <p>Keeping the cache <strong>between</strong> deploys, where the CI runner can see it, is what makes CI builds incremental. Keeping it on the <strong>server</strong> achieves nothing.</p> | |
| 63 | <h2 id="continuous-integration">Continuous integration</h2> | |
| 64 | <pre><code class="language-yaml highlight"><span class="source yaml"><span class="string unquoted plain out yaml"><span class="entity name tag yaml">name</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">build</span> | |
| 65 | <span class="constant language boolean yaml">on</span><span class="punctuation separator key-value mapping yaml">:</span> <span class="meta flow-sequence yaml"><span class="punctuation definition sequence begin yaml">[</span><span class="string unquoted plain in yaml">push</span><span class="punctuation definition sequence end yaml">]</span></span> | |
| 66 | <span class="string unquoted plain out yaml"><span class="entity name tag yaml">jobs</span></span><span class="punctuation separator key-value mapping yaml">:</span> | |
| 67 | <span class="string unquoted plain out yaml"><span class="entity name tag yaml">build</span></span><span class="punctuation separator key-value mapping yaml">:</span> | |
| 68 | <span class="string unquoted plain out yaml"><span class="entity name tag yaml">runs-on</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">ubuntu-latest</span> | |
| 69 | <span class="string unquoted plain out yaml"><span class="entity name tag yaml">steps</span></span><span class="punctuation separator key-value mapping yaml">:</span> | |
| 70 | <span class="punctuation definition block sequence item yaml">-</span> <span class="string unquoted plain out yaml"><span class="entity name tag yaml">uses</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">actions/checkout@v4</span> | |
| 71 | <span class="punctuation definition block sequence item yaml">-</span> <span class="string unquoted plain out yaml"><span class="entity name tag yaml">uses</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">dtolnay/rust-toolchain@stable</span> | |
| 72 | <span class="punctuation definition block sequence item yaml">-</span> <span class="string unquoted plain out yaml"><span class="entity name tag yaml">run</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">cargo install --path .</span> | |
| 73 | <span class="punctuation definition block sequence item yaml">-</span> <span class="string unquoted plain out yaml"><span class="entity name tag yaml">run</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">orgo build content -o _site --strict</span> | |
| 74 | <span class="punctuation definition block sequence item yaml">-</span> <span class="string unquoted plain out yaml"><span class="entity name tag yaml">uses</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">actions/upload-artifact@v4</span> | |
| 75 | <span class="string unquoted plain out yaml"><span class="entity name tag yaml">with</span></span><span class="punctuation separator key-value mapping yaml">:</span> | |
| 76 | <span class="string unquoted plain out yaml"><span class="entity name tag yaml">name</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">site</span> | |
| 77 | <span class="string unquoted plain out yaml"><span class="entity name tag yaml">path</span></span><span class="punctuation separator key-value mapping yaml">:</span> <span class="string unquoted plain out yaml">_site</span></span></code></pre> | |
| 78 | <p><code class="verbatim">--strict</code> is the point of running this in CI at all: it turns a broken link into a failed build.</p> | |
| 79 | <h3 id="caching-between-runs">Caching between runs</h3> | |
| 80 | <p>Cache <code class="verbatim">_site/.orgo-cache.json</code> <strong>and</strong> <code class="verbatim">_site</code> together, or not at all. The manifest describes files it expects to find; a cache without its outputs simply triggers a full rebuild, which is correct but pointless.</p> | |
| 81 | <p>Given how fast a full build is — a 179-page site in well under a second — caching CI builds is rarely worth the configuration.</p> | |
| 82 | <h2 id="static-hosts">Static hosts</h2> | |
| 83 | <p>Nothing here is orgo-specific; a built site is ordinary static files.</p> | |
| 84 | <ul> | |
| 85 | <li><strong>Netlify, Vercel, Cloudflare Pages</strong>: publish directory <code class="verbatim">_site</code>, build command <code class="verbatim">cargo install --path . && orgo build content -o _site --strict</code>.</li> | |
| 86 | <li><strong>GitHub Pages</strong>: upload <code class="verbatim">_site</code> as the Pages artifact.</li> | |
| 87 | <li><strong>Any web server</strong>: copy <code class="verbatim">_site</code> to the document root.</li> | |
| 88 | </ul> | |
| 89 | <h3 id="urls-end-in-html">URLs end in .html</h3> | |
| 90 | <p>orgo writes <code class="verbatim">blog/post.html</code> and links to it that way, so the site works with no server configuration at all — including opening it from a filesystem path.</p> | |
| 91 | <p>If you prefer extensionless URLs, that is a server-side rewrite, and you should also set <code class="verbatim">base_url</code> and check that your rewrite rules do not break the relative links in the pages.</p> | |
| 92 | <h2 id="checking-a-build-before-shipping">Checking a build before shipping</h2> | |
| 93 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span> | |
| 94 | <span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site</span></span></code></pre> | |
| 95 | <p>Serving the production build locally is the last check worth doing: it catches a missing asset or a broken relative link in the browser, where you would notice.</p> | |
| 96 | <h2 id="what-a-clean-build-looks-like">What a clean build looks like</h2> | |
| 97 | <pre>built 182 page(s) (182 rendered, 0 cached), copied 3 asset(s) from content -> _site (0 unresolved link(s), 0 diagnostic(s))</pre> | |
| 98 | <p>Both zeros matter. Unresolved links are internal links pointing at nothing; diagnostics are malformed org that degraded rather than failing. With <code class="verbatim">--strict</code> neither can reach this line, because either would have failed the build.</p> | |
| 99 | <h2 id="do-not-publish-the-cache">Do not publish the cache</h2> | |
| 100 | <p><code class="verbatim"><output>/.orgo-cache.json</code> is a build artefact that happens to live in the output directory, because it describes exactly that directory. Nothing breaks if it is served — it holds hashes and paths, not secrets — but it is not part of your site, so leave it behind:</p> | |
| 101 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">rsync</span></span><span class="meta function-call arguments shell"><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>r</span><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>delete-before</span><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>exclude</span> <span class="string quoted single shell"><span class="punctuation definition string begin shell">'</span>.orgo-cache.json<span class="punctuation definition string end shell">'</span></span> _site/ server:/var/www/example.com/</span></span></code></pre> | |
| 102 | <p>Anything that uploads a directory wholesale needs the same exclusion. A deploy that <strong>deletes</strong> it on the far side is worse than one that copies it: the next build then has no cache to reuse and re-renders everything.</p> | |
| 103 | <h2 id="telling-a-search-engine-where-things-are">Telling a search engine where things are</h2> | |
| 104 | <p>A build with <code class="verbatim">site.base_url</code> set writes <code class="verbatim">sitemap.xml</code> at the site root, listing every page. Point a <code class="verbatim">robots.txt</code> at it if you want one:</p> | |
| 105 | <pre>Sitemap: https://example.com/sitemap.xml</pre> | |
| 106 | <p><code class="verbatim">robots.txt</code> is an ordinary file — put it beside your org files, or in a directory named by <code class="verbatim">[build] assets</code>, and it is copied through.</p> | |
| 107 | <h2 id="after-an-upgrade">After an upgrade</h2> | |
| 108 | <p>The first build on a new version is worth running with <code class="verbatim">--no-cache</code>, so you compare the new output to the old rather than to a cache written by both. What a version number promises — and what it does not — is in <a href="11-versioning.html">Versioning and upgrades</a>.</p> | |
| 109 | </main> | |
| 110 | <footer class="site"> | |
| 111 | Built with orgo — these docs are an orgo site. | |
| 112 | </footer> | |
| 113 | </body> | |
| 114 | </html> | |
| \ No newline at end of file | ||
guide/11-versioning.html added +80
| @@ -0,0 +1,80 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Versioning and upgrades · orgo</title> | |
| 7 | <meta name="description" content="What a version number promises, what it does not, and how to upgrade safely."> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Versioning and upgrades</h1> | |
| 24 | <p class="lede">The stable surface is what you build a site against, not what the code happens to do.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#the-stable-surface">The stable surface</a></li> | |
| 29 | <li><a href="#what-is-not-stable">What is not stable</a> | |
| 30 | <ul> | |
| 31 | <li><a href="#the-incremental-cache">The incremental cache</a></li> | |
| 32 | <li><a href="#rendered-html-details">Rendered HTML details</a></li> | |
| 33 | <li><a href="#what-a-built-in-theme-looks-like">What a built-in theme looks like</a></li> | |
| 34 | <li><a href="#the-rust-api">The Rust API</a></li> | |
| 35 | </ul></li> | |
| 36 | <li><a href="#the-compiler-floor">The compiler floor</a></li> | |
| 37 | <li><a href="#upgrading">Upgrading</a></li> | |
| 38 | </ul> | |
| 39 | </nav> | |
| 40 | <p>A generator you point at ten years of writing needs to be boring about compatibility. This page says exactly what is promised.</p> | |
| 41 | <h2 id="the-stable-surface">The stable surface</h2> | |
| 42 | <p>Changing any of this incompatibly requires a major version.</p> | |
| 43 | <table> | |
| 44 | <thead> | |
| 45 | <tr><th>Stable</th><th>What that covers</th></tr> | |
| 46 | </thead> | |
| 47 | <tbody> | |
| 48 | <tr><td><code class="verbatim">orgo.toml</code> keys</td><td>Their names, types and meaning.</td></tr> | |
| 49 | <tr><td>Template context</td><td><code class="verbatim">page</code>, <code class="verbatim">site</code>, <code class="verbatim">nav</code>, <code class="verbatim">root</code>, <code class="verbatim">pages</code>, <code class="verbatim">group</code>, <code class="verbatim">groups</code>, <code class="verbatim">paginator</code>, <code class="verbatim">stylesheet</code>, <code class="verbatim">theme</code>, and the <code class="verbatim">absolute</code>, <code class="verbatim">rfc822</code> and <code class="verbatim">truncate</code> filters.</td></tr> | |
| 50 | <tr><td>The CLI</td><td>Command names, flags and exit codes.</td></tr> | |
| 51 | <tr><td>URLs</td><td>How a source path becomes an output path, <code class="verbatim">#+SLUG:</code> included.</td></tr> | |
| 52 | </tbody> | |
| 53 | </table> | |
| 54 | <p><strong>URLs are on that list deliberately.</strong> A generator that quietly moves your pages breaks every link anyone has ever made to you, and no upgrade note fixes an inbound link.</p> | |
| 55 | <p>Adding things — a new config key, a new template variable — is a minor release. Nothing you already wrote stops working.</p> | |
| 56 | <h2 id="what-is-not-stable">What is not stable</h2> | |
| 57 | <p>Three things move freely, so the list above can hold still.</p> | |
| 58 | <h3 id="the-incremental-cache">The incremental cache</h3> | |
| 59 | <p><code class="verbatim"><output>/.orgo-cache.json</code> is versioned and discards itself on a mismatch. A cache format bump means one full rebuild, and nothing else. It is never a correctness dependency: a missing, stale or corrupt cache produces exactly the same site, more slowly.</p> | |
| 60 | <h3 id="rendered-html-details">Rendered HTML details</h3> | |
| 61 | <p>orgo aims at what Emacs exports from the same file, and closing a gap changes markup. That is the product working rather than a regression — but it is called out in the release notes every time, because your stylesheet is downstream of it.</p> | |
| 62 | <p>The class names the documentation names are the ones to write CSS against: <code class="verbatim">post-list</code>, <code class="verbatim">post-list-item</code>, <code class="verbatim">figure-number</code>, <code class="verbatim">table-number</code>, <code class="verbatim">section-number-N</code>, <code class="verbatim">footnote-ref</code>, <code class="verbatim">verbatim</code>, and the <code class="verbatim">on=/=off=/=trans</code> classes on checkbox items.</p> | |
| 63 | <h3 id="what-a-built-in-theme-looks-like">What a built-in theme looks like</h3> | |
| 64 | <p>The names — <code class="verbatim">plain</code>, <code class="verbatim">blog</code>, <code class="verbatim">wiki</code>, <code class="verbatim">docs</code> — and the fact that the chosen one is written to <code class="verbatim">theme.css</code> are stable. Its CSS is not: a theme is a starting point that improves between releases, and a site that cannot afford that should copy the stylesheet it likes into its own assets and stop naming a theme.</p> | |
| 65 | <h3 id="the-rust-api">The Rust API</h3> | |
| 66 | <p>The crate is on crates.io so the binary can be installed with <code class="verbatim">cargo install</code>. The library exists to serve the binary, and its types move as the tool does.</p> | |
| 67 | <h2 id="the-compiler-floor">The compiler floor</h2> | |
| 68 | <p>The MSRV is <strong>1.88</strong>, measured rather than assumed — which is how it came to be 1.88 rather than the 1.82 orgo's own code needs. The floor is set by dependencies, and a dependency raising its own is invisible until someone on an older compiler tries to build.</p> | |
| 69 | <p>Raising it is a minor version, never a patch.</p> | |
| 70 | <h2 id="upgrading">Upgrading</h2> | |
| 71 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> install orgo <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> or download a release binary</span><span class="comment line number-sign shell"> | |
| 72 | </span></span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>no-cache</span><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span></span></code></pre> | |
| 73 | <p><code class="verbatim">--no-cache</code> makes the first build after an upgrade a full one, so you are comparing the new version's output to the old version's output rather than to a cache written by a mixture of both. <code class="verbatim">--strict</code> turns a link that stopped resolving into a failure.</p> | |
| 74 | <p>If you keep your built site in version control, the diff after that command <strong>is</strong> the upgrade report, and the most useful review a generator can give you.</p> | |
| 75 | </main> | |
| 76 | <footer class="site"> | |
| 77 | Built with orgo — these docs are an orgo site. | |
| 78 | </footer> | |
| 79 | </body> | |
| 80 | </html> | |
| \ No newline at end of file | ||
guide/index.html added +87
| @@ -0,0 +1,87 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Guide · orgo</title> | |
| 7 | <meta name="description" content=""> | |
| 8 | <link rel="icon" href="../favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="../theme.css"> | |
| 10 | <link rel="stylesheet" href="../syntax.css"> | |
| 11 | <link rel="stylesheet" href="../style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="../index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="../install.html">Install</a> | |
| 18 | <a href="../quickstart.html">Quick start</a> | |
| 19 | <a href="#">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Guide</h1> | |
| 24 | ||
| 25 | <ul class="post-list"> | |
| 26 | <li> | |
| 27 | <a href="../guide/01-cli.html">Command reference</a> | |
| 28 | <p class="excerpt">Every command and flag, and what each is actually for.</p> | |
| 29 | <span class="reading-time">3 min read</span> | |
| 30 | </li> | |
| 31 | <li> | |
| 32 | <a href="../guide/02-configuration.html">Configuration</a> | |
| 33 | <p class="excerpt">Every setting in orgo.toml, what it changes, and what it costs.</p> | |
| 34 | <span class="reading-time">10 min read</span> | |
| 35 | </li> | |
| 36 | <li> | |
| 37 | <a href="../guide/03-collections.html">Collections</a> | |
| 38 | <p class="excerpt">Generated pages — blog indexes, tag pages, pagination and RSS feeds.</p> | |
| 39 | <span class="reading-time">5 min read</span> | |
| 40 | </li> | |
| 41 | <li> | |
| 42 | <a href="../guide/04-templates.html">Templates</a> | |
| 43 | <p class="excerpt">Layouts, inheritance, every variable and filter available to a template.</p> | |
| 44 | <span class="reading-time">5 min read</span> | |
| 45 | </li> | |
| 46 | <li> | |
| 47 | <a href="../guide/05-org-support.html">Org support</a> | |
| 48 | <p class="excerpt">Exactly which org syntax is handled, which is not, and how the rest degrades.</p> | |
| 49 | <span class="reading-time">7 min read</span> | |
| 50 | </li> | |
| 51 | <li> | |
| 52 | <a href="../guide/06-authoring.html">Authoring</a> | |
| 53 | <p class="excerpt">URLs, drafts, excerpts, tables of contents — the metadata that shapes a page.</p> | |
| 54 | <span class="reading-time">3 min read</span> | |
| 55 | </li> | |
| 56 | <li> | |
| 57 | <a href="../guide/07-incremental.html">Incremental builds</a> | |
| 58 | <p class="excerpt">How the cache decides what to re-render, and why that shape is the architecture.</p> | |
| 59 | <span class="reading-time">5 min read</span> | |
| 60 | </li> | |
| 61 | <li> | |
| 62 | <a href="../guide/08-workflow.html">Watching and serving</a> | |
| 63 | <p class="excerpt">The write-save-see loop, and what the development server does and does not do.</p> | |
| 64 | <span class="reading-time">3 min read</span> | |
| 65 | </li> | |
| 66 | <li> | |
| 67 | <a href="../guide/09-auditing.html">Auditing a corpus</a> | |
| 68 | <p class="excerpt">Find out what a tool will make of your writing before you trust it with it.</p> | |
| 69 | <span class="reading-time">3 min read</span> | |
| 70 | </li> | |
| 71 | <li> | |
| 72 | <a href="../guide/10-deploying.html">Deploying</a> | |
| 73 | <p class="excerpt">Producing a production build, and putting it somewhere.</p> | |
| 74 | <span class="reading-time">4 min read</span> | |
| 75 | </li> | |
| 76 | <li> | |
| 77 | <a href="../guide/11-versioning.html">Versioning and upgrades</a> | |
| 78 | <p class="excerpt">What a version number promises, what it does not, and how to upgrade safely.</p> | |
| 79 | <span class="reading-time">3 min read</span> | |
| 80 | </li> | |
| 81 | </ul> | |
| 82 | </main> | |
| 83 | <footer class="site"> | |
| 84 | Built with orgo — these docs are an orgo site. | |
| 85 | </footer> | |
| 86 | </body> | |
| 87 | </html> | |
| \ No newline at end of file | ||
index.html added +68
| @@ -0,0 +1,68 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>orgo · orgo</title> | |
| 7 | <meta name="description" content="An org-mode static site generator in Rust, where the org element tree is the document model."> | |
| 8 | <link rel="icon" href="favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="theme.css"> | |
| 10 | <link rel="stylesheet" href="syntax.css"> | |
| 11 | <link rel="stylesheet" href="style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="install.html">Install</a> | |
| 18 | <a href="quickstart.html">Quick start</a> | |
| 19 | <a href="guide/index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>orgo</h1> | |
| 24 | <p class="lede">Org is the source language, not an inconvenient input to be normalised into markdown.</p> | |
| 25 | <p>orgo turns a directory of <code class="verbatim">.org</code> files into a static website. It treats org as the <strong>source language</strong>: the org element tree — headings, drawers, blocks, links with their org-specific semantics — <em>is</em> the document model, and that tree is rendered straight to HTML. There is no markdown-shaped intermediate representation, because the point is to preserve what markdown cannot express.</p> | |
| 26 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> run<span class="keyword operator end-of-options shell"> --</span></span><span class="meta function-call arguments shell"> init my-site</span> | |
| 27 | <span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> run<span class="keyword operator end-of-options shell"> --</span></span><span class="meta function-call arguments shell"> serve my-site -o _site</span></span></code></pre> | |
| 28 | <p>Open <a href="http://127.0.0.1:3000">127.0.0.1:3000</a>, edit any <code class="verbatim">.org</code> file, and the browser reloads itself.</p> | |
| 29 | <h2 id="start-here">Start here</h2> | |
| 30 | <ul> | |
| 31 | <li><a href="install.html">Install</a> — get the binary built and on your PATH.</li> | |
| 32 | <li><a href="quickstart.html">Quick start</a> — a working site in two commands, then your own content.</li> | |
| 33 | <li><a href="guide/01-cli.html">The guide</a> — every command, setting, template variable and org construct.</li> | |
| 34 | </ul> | |
| 35 | <h2 id="what-you-get-with-no-configuration-at-all">What you get with no configuration at all</h2> | |
| 36 | <p>Point it at a directory of org files and you get a complete site: pages, navigation, syntax-highlighted code, and the stylesheet that colours it. Nothing about your files has to change, and no <code class="verbatim">orgo.toml</code> is required.</p> | |
| 37 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/notes<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site</span></span></code></pre> | |
| 38 | <p>Configuration changes what you get. It is never what makes it work.</p> | |
| 39 | <h2 id="what-it-does-that-is-unusual">What it does that is unusual</h2> | |
| 40 | <h3 id="incremental-builds-are-the-architecture">Incremental builds are the architecture</h3> | |
| 41 | <p>Every page has a render key composed from its content, its resolved links, the site config and the templates. Editing one post re-renders that post, its section index, its tag pages, and the tag index whose counts changed — four pages, whatever the size of the site. A full build and an incremental build produce byte-identical output, and a test proves it.</p> | |
| 42 | <h3 id="it-is-measured-against-emacs">It is measured against Emacs</h3> | |
| 43 | <p><code class="verbatim">cargo test --test oracle</code> exports each test fixture with org's own HTML exporter through <code class="verbatim">emacs --batch</code> and records the disagreement. Heading structure, list nesting and source-block text match exactly. Everything that still differs is a deliberate choice, listed in <a href="guide/05-org-support.html">Org support</a>.</p> | |
| 44 | <h3 id="it-tells-you-what-your-corpus-actually-uses">It tells you what your corpus actually uses</h3> | |
| 45 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> audit <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/notes</span></span></code></pre> | |
| 46 | <p>The audit reports which org constructs appear in a corpus, how often, and whether each is supported — so you can find out before you trust a tool with your writing. It reports names, counts and <code class="verbatim">file:line</code> locations only, never document text, so auditing private notes stays safe to paste into an issue.</p> | |
| 47 | <h2 id="feature-summary">Feature summary</h2> | |
| 48 | <table> | |
| 49 | <thead> | |
| 50 | <tr><th>Area</th><th>What is there</th></tr> | |
| 51 | </thead> | |
| 52 | <tbody> | |
| 53 | <tr><td>Org syntax</td><td>headings with TODO/priority/tags, lists (nested, description, checkboxes), tables, source blocks, quote/center/example/export blocks, footnotes, timestamps, links, images with captions</td></tr> | |
| 54 | <tr><td>Output</td><td>syntax highlighting via syntect, table of contents, section numbers, heading anchors</td></tr> | |
| 55 | <tr><td>Structure</td><td><code class="verbatim">#+SLUG:</code> URLs, drafts, generated listing pages, tag pages and tag indexes, pagination, RSS feeds</td></tr> | |
| 56 | <tr><td>Templates</td><td>minijinja layouts with inheritance, rich page metadata, custom filters</td></tr> | |
| 57 | <tr><td>Workflow</td><td>incremental rebuilds, <code class="verbatim">watch</code> on filesystem events, <code class="verbatim">serve</code> with live reload</td></tr> | |
| 58 | <tr><td>Confidence</td><td>152 tests, an <code class="verbatim">emacs --batch</code> differential oracle, a corpus audit tool</td></tr> | |
| 59 | </tbody> | |
| 60 | </table> | |
| 61 | <h2 id="status">Status</h2> | |
| 62 | <p>This documentation site is itself an orgo site — the sources are in <code class="verbatim">docs/</code> and it is built with the command in <a href="quickstart.html">Quick start</a>. If a feature is described here, it is being used to render the page describing it.</p> | |
| 63 | </main> | |
| 64 | <footer class="site"> | |
| 65 | Built with orgo — these docs are an orgo site. | |
| 66 | </footer> | |
| 67 | </body> | |
| 68 | </html> | |
| \ No newline at end of file | ||
install.html added +82
| @@ -0,0 +1,82 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Install · orgo</title> | |
| 7 | <meta name="description" content="Build orgo from source, put it on your PATH, and check that it works."> | |
| 8 | <link rel="icon" href="favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="theme.css"> | |
| 10 | <link rel="stylesheet" href="syntax.css"> | |
| 11 | <link rel="stylesheet" href="style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="#">Install</a> | |
| 18 | <a href="quickstart.html">Quick start</a> | |
| 19 | <a href="guide/index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Install</h1> | |
| 24 | <p class="lede">One Rust toolchain, one command, no runtime dependencies.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#requirements">Requirements</a></li> | |
| 29 | <li><a href="#from-crates-io">From crates.io</a></li> | |
| 30 | <li><a href="#from-source">From source</a></li> | |
| 31 | <li><a href="#running-without-installing">Running without installing</a></li> | |
| 32 | <li><a href="#check-that-it-works">Check that it works</a></li> | |
| 33 | <li><a href="#running-the-test-suite">Running the test suite</a></li> | |
| 34 | <li><a href="#upgrading">Upgrading</a></li> | |
| 35 | <li><a href="#next">Next</a></li> | |
| 36 | </ul> | |
| 37 | </nav> | |
| 38 | <h2 id="requirements">Requirements</h2> | |
| 39 | <ul> | |
| 40 | <li><strong>Rust 1.88 or newer.</strong> Install from <a href="https://rustup.rs">rustup.rs</a> if you do not have it. There is no other runtime requirement: the binary is self-contained, with syntax definitions and highlighting themes compiled in.</li> | |
| 41 | <li><strong>Emacs (optional).</strong> Only the differential test suite uses it, to compare output against org's own exporter. Nothing about building a site needs Emacs.</li> | |
| 42 | </ul> | |
| 43 | <h2 id="from-crates-io">From crates.io</h2> | |
| 44 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> install orgo</span></span></code></pre> | |
| 45 | <p>That is the whole thing: cargo builds it and puts <code class="verbatim">orgo</code> in <code class="verbatim">~/.cargo/bin</code>.</p> | |
| 46 | <h2 id="from-source">From source</h2> | |
| 47 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">git</span></span><span class="meta function-call arguments shell"> clone https://gitbay.org/krz/orgo</span> | |
| 48 | <span class="meta function-call shell"><span class="support function cd shell">cd</span></span><span class="meta function-call arguments shell"> orgo</span> | |
| 49 | <span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> build<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>release</span></span></span></code></pre> | |
| 50 | <p>The binary lands at <code class="verbatim">target/release/orgo</code>. Copy it somewhere on your <code class="verbatim">PATH</code>:</p> | |
| 51 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cp</span></span><span class="meta function-call arguments shell"> target/release/orgo <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/.local/bin/</span></span></code></pre> | |
| 52 | <p>Or let cargo do it, which puts it in <code class="verbatim">~/.cargo/bin</code>:</p> | |
| 53 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> install<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>path</span> .</span></span></code></pre> | |
| 54 | <h2 id="running-without-installing">Running without installing</h2> | |
| 55 | <p>Every command in this documentation works through cargo if you would rather not install anything. Replace <code class="verbatim">orgo</code> with <code class="verbatim">cargo run --</code> and add <code class="verbatim">--release</code> for a fast build:</p> | |
| 56 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> run<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>release</span><span class="keyword operator end-of-options shell"> --</span></span><span class="meta function-call arguments shell"> build my-site -o _site</span></span></code></pre> | |
| 57 | <p>The debug build is fine for small sites and noticeably slower on large ones, because syntax highlighting dominates and is not optimised in a debug profile.</p> | |
| 58 | <h2 id="check-that-it-works">Check that it works</h2> | |
| 59 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"><span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>version</span></span> | |
| 60 | <span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> init /tmp/orgo-check</span> | |
| 61 | <span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build /tmp/orgo-check<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> /tmp/orgo-check/_site</span></span></code></pre> | |
| 62 | <p>You should see a line reporting the pages built:</p> | |
| 63 | <pre>built 5 page(s) (5 rendered, 0 cached), copied 0 asset(s) ... (0 unresolved link(s), 0 diagnostic(s))</pre> | |
| 64 | <p>Open <code class="verbatim">/tmp/orgo-check/_site/index.html</code> in a browser, or serve it properly:</p> | |
| 65 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve /tmp/orgo-check<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> /tmp/orgo-check/_site</span></span></code></pre> | |
| 66 | <h2 id="running-the-test-suite">Running the test suite</h2> | |
| 67 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> test</span></span></code></pre> | |
| 68 | <p>152 tests, covering the parser, the renderer, configuration, generated pages, the incremental cache, the watcher and the development server.</p> | |
| 69 | <p>The oracle suite is part of that run and compares output against Emacs:</p> | |
| 70 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">cargo</span></span><span class="meta function-call arguments shell"> test<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>test</span> oracle</span></span></code></pre> | |
| 71 | <p>It <strong>skips cleanly</strong> when there is no <code class="verbatim">emacs</code> on your <code class="verbatim">PATH</code>, so a machine without Emacs still gets a green test run — it simply measures one thing less.</p> | |
| 72 | <h2 id="upgrading">Upgrading</h2> | |
| 73 | <p>orgo stores an incremental cache in <code class="verbatim"><output>/.orgo-cache.json</code>, tagged with a format version. A newer binary that changes how output is produced bumps that version, and a version it does not recognise is discarded in favour of a full rebuild. You never need to clear the cache by hand after an upgrade — but if you want to:</p> | |
| 74 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> clean _site</span></span></code></pre> | |
| 75 | <h2 id="next">Next</h2> | |
| 76 | <p><a href="quickstart.html">Quick start</a> builds a real site and puts your own writing into it.</p> | |
| 77 | </main> | |
| 78 | <footer class="site"> | |
| 79 | Built with orgo — these docs are an orgo site. | |
| 80 | </footer> | |
| 81 | </body> | |
| 82 | </html> | |
| \ No newline at end of file | ||
quickstart.html added +177
| @@ -0,0 +1,177 @@ | ||
| 1 | <!DOCTYPE html> | |
| 2 | <html lang="en"> | |
| 3 | <head> | |
| 4 | <meta charset="utf-8"> | |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| 6 | <title>Quick start · orgo</title> | |
| 7 | <meta name="description" content="A working site in two commands, then your own writing, then your own design."> | |
| 8 | <link rel="icon" href="favicon.svg" type="image/svg+xml"> | |
| 9 | <link rel="stylesheet" href="theme.css"> | |
| 10 | <link rel="stylesheet" href="syntax.css"> | |
| 11 | <link rel="stylesheet" href="style.css"> | |
| 12 | </head> | |
| 13 | <body> | |
| 14 | <header class="site"> | |
| 15 | <a class="site-title" href="index.html">orgo</a> | |
| 16 | <nav> | |
| 17 | <a href="install.html">Install</a> | |
| 18 | <a href="#">Quick start</a> | |
| 19 | <a href="guide/index.html">Guide</a> | |
| 20 | </nav> | |
| 21 | </header> | |
| 22 | <main> | |
| 23 | <h1>Quick start</h1> | |
| 24 | <p class="lede">Five minutes from nothing to a site that reloads as you type.</p> | |
| 25 | <nav class="toc" aria-label="On this page"> | |
| 26 | <h2>On this page</h2> | |
| 27 | <ul> | |
| 28 | <li><a href="#two-commands">Two commands</a> | |
| 29 | <ul> | |
| 30 | <li><a href="#what-init-created">What init created</a></li> | |
| 31 | </ul></li> | |
| 32 | <li><a href="#adapting-it-to-org-files-you-already-have">Adapting it to org files you already have</a> | |
| 33 | <ul> | |
| 34 | <li><a href="#source-is-the-url-root">SOURCE is the URL root</a></li> | |
| 35 | <li><a href="#common-layouts">Common layouts</a></li> | |
| 36 | <li><a href="#output-can-live-inside-the-source">OUTPUT can live inside the source</a></li> | |
| 37 | <li><a href="#where-config-and-templates-go">Where config and templates go</a></li> | |
| 38 | <li><a href="#a-worked-example">A worked example</a></li> | |
| 39 | </ul></li> | |
| 40 | <li><a href="#write-a-page">Write a page</a> | |
| 41 | <ul> | |
| 42 | <li><a href="#control-the-url">Control the URL</a></li> | |
| 43 | <li><a href="#keep-something-unfinished-out-of-the-build">Keep something unfinished out of the build</a></li> | |
| 44 | </ul></li> | |
| 45 | <li><a href="#change-the-design">Change the design</a></li> | |
| 46 | <li><a href="#add-a-blog-index">Add a blog index</a></li> | |
| 47 | <li><a href="#build-for-real">Build for real</a></li> | |
| 48 | <li><a href="#next">Next</a></li> | |
| 49 | </ul> | |
| 50 | </nav> | |
| 51 | <h2 id="two-commands">Two commands</h2> | |
| 52 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> init my-site</span> | |
| 53 | <span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve my-site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site</span></span></code></pre> | |
| 54 | <p>Open <a href="http://127.0.0.1:3000">127.0.0.1:3000</a>. Edit <code class="verbatim">my-site/index.org</code> in your editor, save, and the page reloads on its own.</p> | |
| 55 | <p><code class="verbatim">init</code> writes only files that do not already exist, so running it inside a directory that already has content is safe and additive.</p> | |
| 56 | <h3 id="what-init-created">What init created</h3> | |
| 57 | <pre>my-site/ | |
| 58 | orgo.toml every setting, commented — all at their defaults but `theme` | |
| 59 | index.org the home page | |
| 60 | blog/first-post.org a post, to show the collection working | |
| 61 | templates/ | |
| 62 | base.html the page layout — edit this | |
| 63 | list.html the blog index | |
| 64 | tags.html the tag index | |
| 65 | feed.xml an RSS feed</pre> | |
| 66 | <h2 id="adapting-it-to-org-files-you-already-have">Adapting it to org files you already have</h2> | |
| 67 | <p>You do not need <code class="verbatim">init</code>, a config file, or templates. Every command takes the same two paths:</p> | |
| 68 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve <span class="keyword operator assignment redirection shell"><</span>SOURCE<span class="keyword operator assignment redirection shell">></span> <span class="punctuation terminator file-descriptor shell">-</span>o <span class="keyword operator assignment redirection shell"><</span>OUTPUT<span class="keyword operator assignment redirection shell">></span></span></span></code></pre> | |
| 69 | <h3 id="source-is-the-url-root">SOURCE is the URL root</h3> | |
| 70 | <p>This is the one thing worth getting right, and it is not "the project directory" — it is <strong>the directory whose contents should sit at the top of your site</strong>. A file at <code class="verbatim">SOURCE/blog/post.org</code> is published at <code class="verbatim">/blog/post.html</code>.</p> | |
| 71 | <p>So if your writing lives in a <code class="verbatim">content/</code> subdirectory, point at <code class="verbatim">content/</code>, not at the repository around it:</p> | |
| 72 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="support function cd shell">cd</span></span><span class="meta function-call arguments shell"> <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/my-site</span> | |
| 73 | <span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> → /blog/post.html</span></span></span></code></pre> | |
| 74 | <p>Pointing one level too high still builds, which is what makes it worth saying out loud. It just builds the wrong site:</p> | |
| 75 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve .<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> → /content/blog/post.html</span></span></span></code></pre> | |
| 76 | <p>Every URL gains a <code class="verbatim">/content/</code> prefix, and every non-org file in the repository — <code class="verbatim">README.md</code>, build scripts, licence files — is copied into the output as a site asset. If you see either symptom, you picked the directory above the one you meant.</p> | |
| 77 | <h3 id="common-layouts">Common layouts</h3> | |
| 78 | <table> | |
| 79 | <thead> | |
| 80 | <tr><th>Your files</th><th>Command</th></tr> | |
| 81 | </thead> | |
| 82 | <tbody> | |
| 83 | <tr><td><code class="verbatim">~/notes/*.org</code></td><td><code class="verbatim">orgo serve ~/notes -o /tmp/notes-site</code></td></tr> | |
| 84 | <tr><td><code class="verbatim">my-site/content/**/*.org</code></td><td><code class="verbatim">cd my-site && orgo serve content -o _site</code></td></tr> | |
| 85 | <tr><td><code class="verbatim">my-site/*.org</code> at the top level</td><td><code class="verbatim">cd my-site && orgo serve . -o _site</code></td></tr> | |
| 86 | <tr><td>Org files scattered in a code repo</td><td>Do not. Copy or symlink the ones you publish into one directory.</td></tr> | |
| 87 | </tbody> | |
| 88 | </table> | |
| 89 | <h3 id="output-can-live-inside-the-source">OUTPUT can live inside the source</h3> | |
| 90 | <p><code class="verbatim">orgo serve . -o _site</code> is fine: the output directory is recognised and skipped, so the build never copies its own output back into itself. Nothing dot-prefixed is published either, so <code class="verbatim">.git</code> stays out of a site built from a repository root.</p> | |
| 91 | <h3 id="where-config-and-templates-go">Where config and templates go</h3> | |
| 92 | <p>Both live in the <strong>source</strong> directory — <code class="verbatim">SOURCE/orgo.toml</code> and <code class="verbatim">SOURCE/templates/</code> — and neither is published. If you would rather keep the config elsewhere, name it:</p> | |
| 93 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>config</span> config/orgo.toml</span></span></code></pre> | |
| 94 | <h3 id="a-worked-example">A worked example</h3> | |
| 95 | <p>A repository laid out as <code class="verbatim">content/</code> (org files), <code class="verbatim">theme/</code> (unrelated), <code class="verbatim">build.py</code>:</p> | |
| 96 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="support function cd shell">cd</span></span><span class="meta function-call arguments shell"> <span class="meta group expansion tilde"><span class="variable language tilde shell">~</span></span>/my-site</span> | |
| 97 | ||
| 98 | <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> What is actually in there, before trusting anything with it.</span><span class="comment line number-sign shell"> | |
| 99 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> audit content</span> | |
| 100 | ||
| 101 | <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> Build it somewhere disposable and look.</span><span class="comment line number-sign shell"> | |
| 102 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> /tmp/preview</span> | |
| 103 | ||
| 104 | <span class="comment line number-sign shell"><span class="punctuation definition comment begin shell">#</span></span><span class="comment line number-sign shell"> Happy with it? Build for real, failing on broken links.</span><span class="comment line number-sign shell"> | |
| 105 | </span><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build content<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span></span></code></pre> | |
| 106 | <p>The audit reports which org constructs appear, how often, and whether each is supported — names, counts and line numbers only, never your text. See <a href="guide/09-auditing.html">Auditing a corpus</a>.</p> | |
| 107 | <p>Nothing in your files has to change. With no config you get a complete site: a built-in layout, navigation across your top-level pages, and syntax highlighting.</p> | |
| 108 | <h2 id="write-a-page">Write a page</h2> | |
| 109 | <p>Any <code class="verbatim">.org</code> file under the source directory becomes a page at the matching path. <code class="verbatim">notes/rust/borrowing.org</code> becomes <code class="verbatim">notes/rust/borrowing.html</code>.</p> | |
| 110 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+TITLE:</span><span class="string unquoted org"> Borrowing</span> | |
| 111 | <span class="keyword other keyword org">#+DATE:</span><span class="string unquoted org"> <2026-02-02 Mon></span> | |
| 112 | <span class="keyword other keyword org">#+FILETAGS:</span><span class="string unquoted org"> :rust:notes:</span> | |
| 113 | <span class="keyword other keyword org">#+DESCRIPTION:</span><span class="string unquoted org"> How the borrow checker thinks about lifetimes.</span> | |
| 114 | ||
| 115 | An opening paragraph, which becomes the excerpt in listings when there is no | |
| 116 | description. | |
| 117 | ||
| 118 | <span class="markup heading org"><span class="punctuation definition heading org">*</span> A heading | |
| 119 | </span> | |
| 120 | Ordinary org: <span class="markup bold org">*bold*</span>, <span class="markup italic org">/italic/</span>, <span class="markup raw inline org">~code~</span>, <span class="punctuation definition link org">[[</span><span class="markup underline link org">https://orgmode.org</span><span class="punctuation definition link org">]</span><span class="punctuation definition link org">[</span><span class="string other link title org">links</span><span class="punctuation definition link org">]]</span>, and lists. | |
| 121 | ||
| 122 | <span class="markup raw block org"><span class="keyword control block begin org">#+BEGIN_SRC</span><span class="variable parameter org"> rust</span> | |
| 123 | fn main() {} | |
| 124 | <span class="keyword control block end org">#+END_SRC</span></span></span></code></pre> | |
| 125 | <p>The keywords are all optional. <code class="verbatim">#+TITLE:</code> names the page, <code class="verbatim">#+DATE:</code> orders it in listings, <code class="verbatim">#+FILETAGS:</code> groups it on tag pages, and <code class="verbatim">#+DESCRIPTION:</code> is its summary.</p> | |
| 126 | <h3 id="control-the-url">Control the URL</h3> | |
| 127 | <p>By default the filename decides the URL. <code class="verbatim">#+SLUG:</code> overrides it, which is how a date-prefixed filename becomes a clean address:</p> | |
| 128 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+TITLE:</span><span class="string unquoted org"> Borrowing</span> | |
| 129 | <span class="keyword other keyword org">#+SLUG:</span><span class="string unquoted org"> borrowing-explained</span></span></code></pre> | |
| 130 | <p><code class="verbatim">2026-02-02-borrowing.org</code> now publishes as <code class="verbatim">borrowing-explained.html</code>.</p> | |
| 131 | <h3 id="keep-something-unfinished-out-of-the-build">Keep something unfinished out of the build</h3> | |
| 132 | <pre><code class="language-org highlight"><span class="text org"><span class="keyword other keyword org">#+DRAFT:</span><span class="string unquoted org"> t</span></span></code></pre> | |
| 133 | <p>The page is not written, and does not appear in listings or navigation. Preview it while you work with <code class="verbatim">--drafts</code>:</p> | |
| 134 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> serve my-site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>drafts</span></span></span></code></pre> | |
| 135 | <h2 id="change-the-design">Change the design</h2> | |
| 136 | <p>Everything visual lives in <code class="verbatim">templates/base.html</code>. It is an ordinary <a href="https://docs.rs/minijinja">minijinja</a> (Jinja2) template, and replacing it replaces the whole layout:</p> | |
| 137 | <pre><code class="language-html highlight"><span class="text html basic"><span class="meta tag sgml html"><span class="punctuation definition tag html"><!</span><span class="meta tag sgml doctype html"><span class="entity name tag doctype html">DOCTYPE</span> html</span><span class="punctuation definition tag html">></span></span> | |
| 138 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag structure any html">html</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">lang</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ site.language }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 139 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag structure any html">head</span><span class="punctuation definition tag end html">></span></span> | |
| 140 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">meta</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">charset</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>utf-8<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 141 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span>{{ page.title }} — {{ site.title }}<span class="meta tag inline any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline any html">title</span><span class="punctuation definition tag end html">></span></span> | |
| 142 | <span class="meta tag inline any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline any html">link</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">rel</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>stylesheet<span class="punctuation definition string end html">"</span></span></span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ root }}style.css<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span> | |
| 143 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag structure any html">head</span><span class="punctuation definition tag end html">></span></span> | |
| 144 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag structure any html">body</span><span class="punctuation definition tag end html">></span></span> | |
| 145 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">></span></span>{% for item in nav %}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag inline a html">a</span> <span class="meta attribute-with-value html"><span class="entity other attribute-name html">href</span><span class="punctuation separator key-value html">=</span></span><span class="meta attribute-with-value html"><span class="string quoted double html"><span class="punctuation definition string begin html">"</span>{{ item.url }}<span class="punctuation definition string end html">"</span></span></span><span class="punctuation definition tag end html">></span></span>{{ item.title }}<span class="meta tag inline a html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag inline a html">a</span><span class="punctuation definition tag end html">></span></span>{% endfor %}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">nav</span><span class="punctuation definition tag end html">></span></span> | |
| 146 | <span class="meta tag block any html"><span class="punctuation definition tag begin html"><</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">></span></span>{{ page.title }}<span class="meta tag block any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag block any html">h1</span><span class="punctuation definition tag end html">></span></span> | |
| 147 | {{ body | safe }} | |
| 148 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag structure any html">body</span><span class="punctuation definition tag end html">></span></span> | |
| 149 | <span class="meta tag structure any html"><span class="punctuation definition tag begin html"></</span><span class="entity name tag structure any html">html</span><span class="punctuation definition tag end html">></span></span></span></code></pre> | |
| 150 | <p><code class="verbatim">root</code> is the <code class="verbatim">../</code> prefix back to the site root, so the same template works at any depth. Any other file in the source directory — <code class="verbatim">style.css</code>, images, fonts — is copied to the output untouched.</p> | |
| 151 | <p>Editing a template rebuilds every page that uses it, so the browser reloads while you are still looking at it. The full list of variables is in <a href="guide/04-templates.html">Templates</a>.</p> | |
| 152 | <h2 id="add-a-blog-index">Add a blog index</h2> | |
| 153 | <p>Listing pages have no source file; they are declared in <code class="verbatim">orgo.toml</code>:</p> | |
| 154 | <pre><code class="language-toml highlight"><span class="source toml"><span class="punctuation definition table array toml">[[</span><span class="entity name section toml">collections</span><span class="punctuation definition table array toml">]]</span> | |
| 155 | <span class="variable other key toml">source</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog<span class="punctuation definition string end toml">"</span></span> | |
| 156 | <span class="variable other key toml">output</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>blog/index.html<span class="punctuation definition string end toml">"</span></span> | |
| 157 | <span class="variable other key toml">template</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>list.html<span class="punctuation definition string end toml">"</span></span> | |
| 158 | <span class="variable other key toml">title</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>Blog<span class="punctuation definition string end toml">"</span></span> | |
| 159 | <span class="variable other key toml">sort</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>date<span class="punctuation definition string end toml">"</span></span> | |
| 160 | <span class="variable other key toml">order</span> <span class="keyword operator assignment toml">=</span> <span class="string quoted double toml"><span class="punctuation definition string begin toml">"</span>desc<span class="punctuation definition string end toml">"</span></span> | |
| 161 | <span class="variable other key toml">nav</span> <span class="keyword operator assignment toml">=</span> <span class="constant language toml">true</span></span></code></pre> | |
| 162 | <p>That is also how you get tag pages, pagination and an RSS feed — same mechanism, more settings. See <a href="guide/03-collections.html">Collections</a>.</p> | |
| 163 | <h2 id="build-for-real">Build for real</h2> | |
| 164 | <pre><code class="language-sh highlight"><span class="source shell bash"><span class="meta function-call shell"><span class="variable function shell">orgo</span></span><span class="meta function-call arguments shell"> build my-site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> -</span>o</span> _site<span class="variable parameter option shell"><span class="punctuation definition parameter shell"> --</span>strict</span></span></span></code></pre> | |
| 165 | <p><code class="verbatim">--strict</code> turns broken internal links and parse diagnostics into a non-zero exit, which is what you want in CI. Deployment is just copying <code class="verbatim">_site</code> somewhere; see <a href="guide/10-deploying.html">Deploying</a>.</p> | |
| 166 | <h2 id="next">Next</h2> | |
| 167 | <ul> | |
| 168 | <li><a href="guide/01-cli.html">Command reference</a> — every command and flag.</li> | |
| 169 | <li><a href="guide/02-configuration.html">Configuration</a> — every setting in <code class="verbatim">orgo.toml</code>.</li> | |
| 170 | <li><a href="guide/05-org-support.html">Org support</a> — exactly which org syntax is handled.</li> | |
| 171 | </ul> | |
| 172 | </main> | |
| 173 | <footer class="site"> | |
| 174 | Built with orgo — these docs are an orgo site. | |
| 175 | </footer> | |
| 176 | </body> | |
| 177 | </html> | |
| \ No newline at end of file | ||
style.css added +17
| @@ -0,0 +1,17 @@ | ||
| 1 | /* Documentation site styling: the `docs` built-in theme, adjusted rather than replaced. | |
| 2 | * | |
| 3 | * A plain asset, copied through the build untouched — which is also how any other CSS, | |
| 4 | * image or font in a source directory reaches the output. It is linked after theme.css, | |
| 5 | * which is what lets these definitions win. | |
| 6 | * | |
| 7 | * Only the code surface is changed. syntax.css colours tokens, never the surface under | |
| 8 | * them, so a site pairing a dark `highlight.theme` with a theme has to say what colour | |
| 9 | * code sits on — here, dark in both schemes, matching base16-ocean.dark. A site wanting | |
| 10 | * blocks to follow prefers-color-scheme sets `highlight.theme_dark` and gives these | |
| 11 | * three a dark query too. Everything else is the theme's. */ | |
| 12 | ||
| 13 | :root { | |
| 14 | --orgo-code-bg: #2b303b; | |
| 15 | --orgo-code-fg: #c0c5ce; | |
| 16 | --orgo-code-rule: #1f232b; | |
| 17 | } | |
syntax.css added +160
| @@ -0,0 +1,160 @@ | ||
| 1 | /* | |
| 2 | * theme "Base16 Ocean Dark" generated by syntect | |
| 3 | */ | |
| 4 | ||
| 5 | .code { | |
| 6 | color: #c0c5ce; | |
| 7 | background-color: #2b303b; | |
| 8 | } | |
| 9 | ||
| 10 | .variable.parameter.function { | |
| 11 | color: #c0c5ce; | |
| 12 | } | |
| 13 | .comment, .punctuation.definition.comment { | |
| 14 | color: #65737e; | |
| 15 | } | |
| 16 | .punctuation.definition.string, .punctuation.definition.variable, .punctuation.definition.string, .punctuation.definition.parameters, .punctuation.definition.string, .punctuation.definition.array { | |
| 17 | color: #c0c5ce; | |
| 18 | } | |
| 19 | .none { | |
| 20 | color: #c0c5ce; | |
| 21 | } | |
| 22 | .keyword.operator { | |
| 23 | color: #c0c5ce; | |
| 24 | } | |
| 25 | .keyword { | |
| 26 | color: #b48ead; | |
| 27 | } | |
| 28 | .variable, .variable.other.dollar.only.js { | |
| 29 | color: #bf616a; | |
| 30 | } | |
| 31 | .entity.name.function, .meta.require, .support.function.any-method, .variable.function { | |
| 32 | color: #8fa1b3; | |
| 33 | } | |
| 34 | .support.class, .entity.name.class, .entity.name.type.class { | |
| 35 | color: #ebcb8b; | |
| 36 | } | |
| 37 | .meta.class { | |
| 38 | color: #eff1f5; | |
| 39 | } | |
| 40 | .keyword.other.special-method { | |
| 41 | color: #8fa1b3; | |
| 42 | } | |
| 43 | .storage { | |
| 44 | color: #b48ead; | |
| 45 | } | |
| 46 | .support.function { | |
| 47 | color: #96b5b4; | |
| 48 | } | |
| 49 | .string, .constant.other.symbol, .entity.other.inherited-class { | |
| 50 | color: #a3be8c; | |
| 51 | } | |
| 52 | .constant.numeric { | |
| 53 | color: #d08770; | |
| 54 | } | |
| 55 | .none { | |
| 56 | color: #d08770; | |
| 57 | } | |
| 58 | .none { | |
| 59 | color: #d08770; | |
| 60 | } | |
| 61 | .constant { | |
| 62 | color: #d08770; | |
| 63 | } | |
| 64 | .entity.name.tag { | |
| 65 | color: #bf616a; | |
| 66 | } | |
| 67 | .entity.other.attribute-name { | |
| 68 | color: #d08770; | |
| 69 | } | |
| 70 | .entity.other.attribute-name.id, .punctuation.definition.entity { | |
| 71 | color: #8fa1b3; | |
| 72 | } | |
| 73 | .meta.selector { | |
| 74 | color: #b48ead; | |
| 75 | } | |
| 76 | .none { | |
| 77 | color: #d08770; | |
| 78 | } | |
| 79 | .markup.heading .punctuation.definition.heading, .entity.name.section { | |
| 80 | color: #8fa1b3; | |
| 81 | } | |
| 82 | .keyword.other.unit { | |
| 83 | color: #d08770; | |
| 84 | } | |
| 85 | .markup.bold, .punctuation.definition.bold { | |
| 86 | color: #ebcb8b; | |
| 87 | font-weight: bold; | |
| 88 | } | |
| 89 | .markup.italic, .punctuation.definition.italic { | |
| 90 | color: #b48ead; | |
| 91 | font-style: italic; | |
| 92 | } | |
| 93 | .markup.raw.inline { | |
| 94 | color: #a3be8c; | |
| 95 | } | |
| 96 | .string.other.link { | |
| 97 | color: #bf616a; | |
| 98 | } | |
| 99 | .meta.link { | |
| 100 | color: #d08770; | |
| 101 | } | |
| 102 | .meta.image { | |
| 103 | color: #d08770; | |
| 104 | } | |
| 105 | .markup.list { | |
| 106 | color: #bf616a; | |
| 107 | } | |
| 108 | .markup.quote { | |
| 109 | color: #d08770; | |
| 110 | } | |
| 111 | .meta.separator { | |
| 112 | color: #c0c5ce; | |
| 113 | background-color: #4f5b66; | |
| 114 | } | |
| 115 | .markup.inserted, .markup.inserted.git_gutter { | |
| 116 | color: #a3be8c; | |
| 117 | } | |
| 118 | .markup.deleted, .markup.deleted.git_gutter { | |
| 119 | color: #bf616a; | |
| 120 | } | |
| 121 | .markup.changed, .markup.changed.git_gutter { | |
| 122 | color: #b48ead; | |
| 123 | } | |
| 124 | .markup.ignored, .markup.ignored.git_gutter { | |
| 125 | color: #4f5b66; | |
| 126 | } | |
| 127 | .markup.untracked, .markup.untracked.git_gutter { | |
| 128 | color: #4f5b66; | |
| 129 | } | |
| 130 | .constant.other.color { | |
| 131 | color: #96b5b4; | |
| 132 | } | |
| 133 | .string.regexp { | |
| 134 | color: #96b5b4; | |
| 135 | } | |
| 136 | .constant.character.escape { | |
| 137 | color: #96b5b4; | |
| 138 | } | |
| 139 | .punctuation.section.embedded, .variable.interpolation { | |
| 140 | color: #ab7967; | |
| 141 | } | |
| 142 | .invalid.illegal { | |
| 143 | color: #2b303b; | |
| 144 | background-color: #bf616a; | |
| 145 | } | |
| 146 | .markup.deleted.git_gutter { | |
| 147 | color: #f92672; | |
| 148 | } | |
| 149 | .markup.inserted.git_gutter { | |
| 150 | color: #a6e22e; | |
| 151 | } | |
| 152 | .markup.changed.git_gutter { | |
| 153 | color: #967efb; | |
| 154 | } | |
| 155 | .markup.ignored.git_gutter { | |
| 156 | color: #565656; | |
| 157 | } | |
| 158 | .markup.untracked.git_gutter { | |
| 159 | color: #565656; | |
| 160 | } | |
theme.css added +248
| @@ -0,0 +1,248 @@ | ||
| 1 | /* orgo built-in theme: docs | |
| 2 | * | |
| 3 | * A documentation site: a guide read in order, with a contents block that matters, code | |
| 4 | * blocks that carry as much of the meaning as the prose, and a `#+LEDE:` line under the | |
| 5 | * title. Cooler and more technical than `blog`, narrower and more designed than `wiki`. | |
| 6 | * | |
| 7 | * Every colour is a custom property on :root, so a stylesheet of your own loaded after | |
| 8 | * this one can retheme the site by redefining a handful of values. */ | |
| 9 | ||
| 10 | :root { | |
| 11 | --orgo-ink: #1c1f24; | |
| 12 | --orgo-muted: #5b6472; | |
| 13 | --orgo-rule: #dfe3e8; | |
| 14 | --orgo-accent: #0b5fa5; | |
| 15 | --orgo-surface: #f6f8fa; | |
| 16 | --orgo-bg: #ffffff; | |
| 17 | --orgo-measure: 42rem; | |
| 18 | --orgo-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| 19 | --orgo-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; | |
| 20 | /* These three colour code *blocks* only; inline code follows the page. A block keeps | |
| 21 | a light surface in both colour schemes, because syntax.css is coloured by | |
| 22 | `highlight.theme` and that default (InspiredGitHub) is light. To let blocks follow | |
| 23 | prefers-color-scheme, set `highlight.theme_dark` to a dark theme and override these | |
| 24 | three in a dark query of your own. */ | |
| 25 | --orgo-todo: #b02a37; | |
| 26 | --orgo-done: #2c7a4b; | |
| 27 | --orgo-code-bg: #f6f8fa; | |
| 28 | --orgo-code-fg: #323232; | |
| 29 | --orgo-code-rule: #e3e7ec; | |
| 30 | } | |
| 31 | ||
| 32 | @media (prefers-color-scheme: dark) { | |
| 33 | :root { | |
| 34 | --orgo-ink: #dee3ea; | |
| 35 | --orgo-muted: #9aa4b2; | |
| 36 | --orgo-rule: #2b3138; | |
| 37 | --orgo-accent: #79b8ff; | |
| 38 | --orgo-surface: #171a1f; | |
| 39 | --orgo-todo: #f0909a; | |
| 40 | --orgo-done: #74c795; | |
| 41 | --orgo-bg: #0f1216; | |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | * { box-sizing: border-box; } | |
| 46 | ||
| 47 | body { | |
| 48 | margin: 0; | |
| 49 | background: var(--orgo-bg); | |
| 50 | color: var(--orgo-ink); | |
| 51 | font: 16px/1.65 var(--orgo-font); | |
| 52 | /* A bare URL or a long identifier must wrap, not widen the page on a phone. */ | |
| 53 | overflow-wrap: break-word; | |
| 54 | } | |
| 55 | ||
| 56 | /* Header ------------------------------------------------------------------- */ | |
| 57 | ||
| 58 | body > header { | |
| 59 | position: sticky; | |
| 60 | top: 0; | |
| 61 | z-index: 1; | |
| 62 | background: var(--orgo-bg); | |
| 63 | border-bottom: 1px solid var(--orgo-rule); | |
| 64 | padding: 1rem 1.5rem; | |
| 65 | display: flex; | |
| 66 | flex-wrap: wrap; | |
| 67 | gap: .5rem 1.5rem; | |
| 68 | align-items: baseline; | |
| 69 | } | |
| 70 | ||
| 71 | .site-title { | |
| 72 | font-weight: 700; | |
| 73 | font-size: 1.05rem; | |
| 74 | color: var(--orgo-ink); | |
| 75 | text-decoration: none; | |
| 76 | } | |
| 77 | ||
| 78 | body > header nav { display: flex; flex-wrap: wrap; gap: 1.25rem; } | |
| 79 | body > header nav a { | |
| 80 | color: var(--orgo-muted); | |
| 81 | text-decoration: none; | |
| 82 | padding-bottom: .15rem; | |
| 83 | border-bottom: 2px solid transparent; | |
| 84 | } | |
| 85 | body > header nav a:hover { color: var(--orgo-ink); border-bottom-color: var(--orgo-accent); } | |
| 86 | ||
| 87 | /* Page body ---------------------------------------------------------------- */ | |
| 88 | ||
| 89 | main { | |
| 90 | max-width: var(--orgo-measure); | |
| 91 | margin: 0 auto; | |
| 92 | padding: 2.5rem 1.5rem 5rem; | |
| 93 | } | |
| 94 | ||
| 95 | h1 { font-size: 2rem; line-height: 1.2; letter-spacing: -0.02em; margin: 0 0 .5rem; } | |
| 96 | h2 { font-size: 1.35rem; letter-spacing: -0.01em; margin: 2.75rem 0 .75rem; } | |
| 97 | h3 { font-size: 1.1rem; margin: 2rem 0 .5rem; } | |
| 98 | h4, h5, h6 { font-size: 1rem; margin: 1.5rem 0 .5rem; } | |
| 99 | ||
| 100 | [class^="section-number-"] { color: var(--orgo-muted); font-weight: 400; } | |
| 101 | ||
| 102 | a { color: var(--orgo-accent); } | |
| 103 | ||
| 104 | /* `#+LEDE:` reaches the layout as page.keywords.lede; page.date as the byline. */ | |
| 105 | p.lede { font-size: 1.1rem; color: var(--orgo-muted); margin-top: 0; } | |
| 106 | p.page-date { color: var(--orgo-muted); font-size: .9rem; } | |
| 107 | ||
| 108 | img, video { max-width: 100%; height: auto; } | |
| 109 | ||
| 110 | figure { margin: 1.75rem 0; } | |
| 111 | figcaption { color: var(--orgo-muted); font-size: .9rem; margin-top: .4rem; } | |
| 112 | .figure-number, .table-number { font-weight: 600; } | |
| 113 | ||
| 114 | /* A quote block reads as a note or a caution in a documentation site. */ | |
| 115 | blockquote { | |
| 116 | margin: 1.5rem 0; | |
| 117 | padding: .75rem 1rem; | |
| 118 | background: var(--orgo-surface); | |
| 119 | border-left: 3px solid var(--orgo-accent); | |
| 120 | border-radius: 0 4px 4px 0; | |
| 121 | color: var(--orgo-muted); | |
| 122 | } | |
| 123 | blockquote > :first-child { margin-top: 0; } | |
| 124 | blockquote > :last-child { margin-bottom: 0; } | |
| 125 | ||
| 126 | hr { border: 0; border-top: 1px solid var(--orgo-rule); margin: 2.5rem 0; } | |
| 127 | ||
| 128 | .center { text-align: center; } | |
| 129 | .verse { font-family: var(--orgo-mono); white-space: pre-wrap; } | |
| 130 | ||
| 131 | dt { font-weight: 600; margin-top: .75rem; font-family: var(--orgo-mono); font-size: .95rem; } | |
| 132 | dd { margin: 0 0 0 1.5rem; } | |
| 133 | ||
| 134 | /* Code --------------------------------------------------------------------- */ | |
| 135 | ||
| 136 | /* Inline code is prose furniture, so it follows the page rather than the code blocks. */ | |
| 137 | code { | |
| 138 | font: .875em/1.5 var(--orgo-mono); | |
| 139 | background: var(--orgo-surface); | |
| 140 | color: inherit; | |
| 141 | padding: .1em .35em; | |
| 142 | border-radius: 3px; | |
| 143 | } | |
| 144 | ||
| 145 | pre { | |
| 146 | background: var(--orgo-code-bg); | |
| 147 | color: var(--orgo-code-fg); | |
| 148 | border: 1px solid var(--orgo-code-rule); | |
| 149 | border-radius: 6px; | |
| 150 | padding: .9rem 1.1rem; | |
| 151 | font-size: .9rem; | |
| 152 | line-height: 1.55; | |
| 153 | overflow-x: auto; | |
| 154 | } | |
| 155 | ||
| 156 | pre code { background: none; color: inherit; padding: 0; } | |
| 157 | ||
| 158 | /* Tables ------------------------------------------------------------------- */ | |
| 159 | ||
| 160 | table { | |
| 161 | border-collapse: collapse; | |
| 162 | width: 100%; | |
| 163 | margin: 1.5rem 0; | |
| 164 | display: block; | |
| 165 | overflow-x: auto; | |
| 166 | } | |
| 167 | caption { text-align: left; color: var(--orgo-muted); font-size: .9rem; padding-bottom: .4rem; } | |
| 168 | th, td { text-align: left; padding: .5rem .75rem; border-bottom: 1px solid var(--orgo-rule); } | |
| 169 | th { | |
| 170 | font-size: .8rem; | |
| 171 | text-transform: uppercase; | |
| 172 | letter-spacing: .05em; | |
| 173 | color: var(--orgo-muted); | |
| 174 | } | |
| 175 | ||
| 176 | /* Org-specific markup ------------------------------------------------------ */ | |
| 177 | ||
| 178 | .tag { | |
| 179 | font: .72rem/1.6 var(--orgo-mono); | |
| 180 | color: var(--orgo-muted); | |
| 181 | background: var(--orgo-surface); | |
| 182 | border: 1px solid var(--orgo-rule); | |
| 183 | border-radius: 999px; | |
| 184 | padding: .05em .6em; | |
| 185 | vertical-align: middle; | |
| 186 | } | |
| 187 | ||
| 188 | .todo, .done { font: .72rem/1.6 var(--orgo-mono); letter-spacing: .04em; } | |
| 189 | .todo { color: var(--orgo-todo); } | |
| 190 | .done { color: var(--orgo-done); } | |
| 191 | .priority { color: var(--orgo-muted); font-family: var(--orgo-mono); font-size: .8em; } | |
| 192 | ||
| 193 | time.timestamp { color: var(--orgo-muted); font-family: var(--orgo-mono); font-size: .9em; } | |
| 194 | ||
| 195 | li.on, li.trans { color: var(--orgo-muted); } | |
| 196 | li.on { text-decoration: line-through; } | |
| 197 | ||
| 198 | .footnotes { margin-top: 3rem; font-size: .9rem; color: var(--orgo-muted); } | |
| 199 | .footnote-ref a { text-decoration: none; } | |
| 200 | ||
| 201 | /* Table of contents: a card, because in a guide it is navigation ----------- */ | |
| 202 | ||
| 203 | nav.toc { | |
| 204 | background: var(--orgo-surface); | |
| 205 | border: 1px solid var(--orgo-rule); | |
| 206 | border-radius: 6px; | |
| 207 | padding: .75rem 1.25rem 1rem; | |
| 208 | margin: 1.75rem 0 2.5rem; | |
| 209 | } | |
| 210 | nav.toc h2 { | |
| 211 | font-size: .8rem; | |
| 212 | text-transform: uppercase; | |
| 213 | letter-spacing: .06em; | |
| 214 | color: var(--orgo-muted); | |
| 215 | margin: .25rem 0 .5rem; | |
| 216 | } | |
| 217 | nav.toc ul { margin: 0; padding-left: 1.1rem; } | |
| 218 | nav.toc li { margin: .15rem 0; } | |
| 219 | ||
| 220 | /* Listing pages: a guide's contents page, a tag index ---------------------- */ | |
| 221 | ||
| 222 | ul.post-list { list-style: none; padding: 0; } | |
| 223 | ul.post-list > li { padding: 1rem 0; border-bottom: 1px solid var(--orgo-rule); } | |
| 224 | ul.post-list a { font-weight: 600; font-size: 1.05rem; } | |
| 225 | ul.post-list time { color: var(--orgo-muted); font-size: .9rem; } | |
| 226 | p.excerpt { margin: .35rem 0 .2rem; color: var(--orgo-muted); } | |
| 227 | span.reading-time { font-size: .85rem; color: var(--orgo-muted); } | |
| 228 | ||
| 229 | ul.tag-list { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .6rem 1.25rem; } | |
| 230 | ||
| 231 | nav.pagination { | |
| 232 | display: flex; | |
| 233 | gap: 1rem; | |
| 234 | align-items: baseline; | |
| 235 | margin-top: 2.5rem; | |
| 236 | color: var(--orgo-muted); | |
| 237 | font-size: .9rem; | |
| 238 | } | |
| 239 | ||
| 240 | /* Footer ------------------------------------------------------------------- */ | |
| 241 | ||
| 242 | body > footer { | |
| 243 | border-top: 1px solid var(--orgo-rule); | |
| 244 | padding: 1.5rem; | |
| 245 | color: var(--orgo-muted); | |
| 246 | font-size: .9rem; | |
| 247 | text-align: center; | |
| 248 | } | |