<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>tarleb</title>
<link>https://tarleb.com/</link>
<atom:link href="https://tarleb.com/index.xml" rel="self" type="application/rss+xml"/>
<description>tarleb&#39;s blog</description>
<generator>quarto-1.4.554</generator>
<lastBuildDate>Fri, 24 Mar 2023 00:00:00 GMT</lastBuildDate>
<item>
  <title>Typst Musings</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/typst-musings/</link>
  <description><![CDATA[ 




<p><a href="https://typst.app">Typst</a>, the new writing tool, was open sourced a couple of days ago. This is right up my alley of course, and I have a couple of thoughts on it, which I share here.</p>
<section id="what-is-it" class="level2">
<h2 class="anchored" data-anchor-id="what-is-it">What is it?</h2>
<p>Typst is a writing tool that’s described as a LaTeX alternative: it takes plain-text markup as input and can produce nice looking PDFs from that. The open-sourcing of the code created a lot of excitement and interest, with the <a href="https://github.com/typst/typst">GitHub repository</a> getting starred over 9,000 times in just a few days.</p>
<p>The tool comes with fresh and interesting ideas, impressive technology, and a good bit of hype—so let’s take a closer look.</p>
</section>
<section id="how-does-it-work" class="level2">
<h2 class="anchored" data-anchor-id="how-does-it-work">How does it work?</h2>
<p>Typst is written in <a href="https://www.rust-lang.org/">Rust</a>, a comparatively low-level programming language that fixes many shortcomings of other languages operating in the same domain. One interesting feature of Rust that Typst makes use of is compilation to web assembly, which allows us to run Rust programs in the browser. This is how Typst can do the blazing fast PDF generation <em>in the browser!</em></p>
<p>Of course this only works if it is Rust all the way down, which has important consequences. My first thought when I looked at the code was that it suffered from some serious <a href="https://en.wikipedia.org/wiki/Not_invented_here">nih</a> syndrome: basically the whole stack is built on libraries written by the Typst team, even when high-qualitify open source libraries were available and could have been used with Rust.</p>
<p>But, while nih still seems relevant here and there, the majority of libraries make sense when viewed through the lens of wasm-compilation. My understanding is that it’s not always easy to compile C libraries to wasm. And with a complex system like Typst, it is often essential to have full control over the underlying libraries. So I think most choices are quite reasonable.</p>
</section>
<section id="what-makes-it-popular" class="level2">
<h2 class="anchored" data-anchor-id="what-makes-it-popular">What makes it popular?</h2>
<p>The Typst announcements on sites like <a href="https://news.ycombinator.com/item?id=35250210">Hacker News</a> and <a href="https://lobste.rs/s/ko1yjj/typst_new_markup_based_typesetting">lobste.rs</a> ranked № 1, and the tool was mentioned in basically every social media circle and chat that I happen to be part of. There’s clearly <em>a lot</em> of interest in a modernized version of LaTeX. Good ol’ TeX and it’s children have been around for a long while, and have essentially held the monopoly on PDF production for typographically advanced documents (tools like HTML-to-PDF converters like <a href="https://weasyprint.org/">WeasyPrint</a> notwithstanding).</p>
<p>But the need for a nicer PDF generator is probably not the only reason why Typst gained so much traction. I believe that a lot of interest from the programmer community is fueled by the technological choices: Rust has the aura of a new and shiny tool that <a href="https://stackoverflow.blog/2023/01/26/comparing-tag-trends-with-our-most-loved-programming-languages/">everyone would like to use</a>, <em>especially</em> the regulars on the aforementioned sites, who share an interest in the latest tools. An otherwise equivalent project written in a “boring” language like Python would likely have sparked less interest.</p>
<p>I find it also important to note that Typst comes with <em>extensive documentation</em> that makes it easy to dive right in. It is far too common in the programming world to release some cool new tool into the wild, while treating documentation as an unimportant afterthought. Yes, I’m guilty of that, too. Even the best tool can be unusable when its docs are missing or sparse. Typst didn’t make this mistake, and I think it paid off.</p>
</section>
<section id="personal-opinions" class="level2">
<h2 class="anchored" data-anchor-id="personal-opinions">Personal opinions</h2>
<p>This wouldn’t be a proper “old man shakes fist at the clouds” tech blog post if it didn’t come with a number of “I see room for improvements” comments. Here we go.</p>
<section id="scripting" class="level3">
<h3 class="anchored" data-anchor-id="scripting">Scripting</h3>
<p>One of my main concerns is the scripting language: It seems well designed, but I’m not convinced that it was necessary to create a completely new language. I actually believe that something like Lua, which is established<sup>1</sup> but flexlible, would have worked well here. But what’s more is that, if we accept that it was necessary to have a custom language, I would have preferred one that isn’t Turing complete, i.e., one where we can be sure that document rendering will terminate. Something like <a href="https://dhall-lang.org/">Dhall</a>.</p>
<p>As it currently stands we can neither reuse pre-existing code, nor do we have a guarantee that the document will stop evaluating at some point. It feels like a missed opportunity.</p>
</section>
<section id="notebooks" class="level3">
<h3 class="anchored" data-anchor-id="notebooks">Notebooks</h3>
<p>Notebooks are a great tool to improve reproducibility in science writing. The code for analyses is collocated with the descriptive text in a single place. The data is closely linked to the final tables and graphics. It is one of the great features of <a href="https://quarto.org/">Quarto</a>, <a href="https://jupyter.org/">Jupyter</a>, <a href="https://orgmode.org/">Org</a>, <a href="https://stenci.la/">Stencila</a>, Mathematica, and so on, which makes them well suited for scientific writing in fields like medicine, psychology, and the natural sciences.</p>
<p>This could be an <a href="https://github.com/typst/typst/issues/117">issue</a> for Typst, but I believe that it won’t be a problem when Typst is used in combination with other tools. John MacFarlane (of <a href="https://commonmark.org">CommonMark</a> and <a href="https://pandoc.org/">pandoc</a> fame) has <a href="https://github.com/jgm/pandoc/issues/8713">started work</a> on a Typst pandoc writer, which will convert existing Markdown documents to Typst, and could enable the use of Typst as PDF generator while still writing Markdown and Python code in Quarto.</p>
</section>
<section id="accessibility-and-metadata" class="level3">
<h3 class="anchored" data-anchor-id="accessibility-and-metadata">Accessibility and metadata</h3>
<p>It’s good practice to make PDFs accessible, which requires adding semantic information to a PDF instead of “just” placing characters on a page. Accessibility is even a legal requirement for government-issued documents in many countries. There are standards like PDF/A-1a and PDF/UA that ensure people with disabilities can access the information contained in the PDF. This is currently not supperted in Typst. LaTeX is still trying to catch up there, too, while <a href="https://wiki.contextgarden.net/">ConTeXt</a> and <a href="https://speedata.de/">speedata</a> are doing well, for example.</p>
</section>
</section>
<section id="predictions" class="level2">
<h2 class="anchored" data-anchor-id="predictions">Predictions</h2>
<p>I believe Typst will succeed, but not as a full-fledged writing tool. The greatest value I see is in the <strong>responsive, interactive, and even collaborative styling of PDFs</strong>. That feature is truly unique and sets Typst appart from all other software out there. The tool obviously has the potential to reach the critical mass of contributors to become a sustainable open source project, and the tech choices help to attract more developers. Last but not least, the app is shiny, works well, and makes people want to use it.</p>
<p>At the same time, I believe that the Typst writing app won’t take hold in scientific writing. Most of the current enthusiasm is contained to technical circles, and scientists don’t have strong reasons to switch yet. To the contrary, journals expect paper submissions to be done in Word or LaTeX, not PDF. This won’t change anytime soon. Typst will have to insert itself into the current publishing landscape, and that’s not a trivial task.</p>
<p>For example, <a href="https://sciflow.net/">SciFlow</a> and <a href="https://overleaf.com/">Overleaf</a> already exist, cover most of the market needs, have a solid headstart, and – this is the important part – are well aligned with the needs of science publishers. Any new tool has to compete with them. Also, let’s not forget all the other tools that I mentioned above.</p>
<p>Regardless, I’m optimistic that Typst can carve out its own business niche to occupy. For example, hardly any of my points above matter in print publishing. An indie book publisher that allows authors to use Typst for layouting would be amazing.</p>
<p>I hope that the Typst team’s hard work will pay off, and I will continue to follow their progress with great interest.</p>
</section>
<section id="acknowledgements" class="level2">
<h2 class="anchored" data-anchor-id="acknowledgements">Acknowledgements</h2>
<p>Heart-felt thanks to <a href="https://hachyderm.io/@maegul">@maegul@hachyderm.io</a> for the insightful feedback on an earlier version of this post, and to <a href="https://ilonasilverwood.github.io/">Ilona Silverwood</a> for her skillful editing. This post became much better thanks to their input.</p>
</section>
<section id="updates" class="level2">
<h2 class="anchored" data-anchor-id="updates">Updates</h2>
<p>An earlier version listed <a href="https://www.authorea.com/">Authorea</a> as an authoring tool, but the platform has shifted focus since I last looked at it, so I’ve removed it.</p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>I consider <a href="https://lua.org/">Lua</a> to be <em>the</em> language of publishing tools. It fuels <a href="https://pandoc.org/">pandoc</a>, <a href="https://quarto.org/">Quarto</a>, <a href="https://wiki.contextgarden.net/">ConTeXt</a>, <a href="http://luatex.org/">LuaLaTeX</a>, <a href="https://speedata.de/">speedata</a>, <a href="https://sile-typesetter.org/">SILE</a>, and probably a few more.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>PDF</category>
  <guid>https://tarleb.com/posts/typst-musings/</guid>
  <pubDate>Fri, 24 Mar 2023 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Auto-numbered list continuations</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/list-continuation/</link>
  <description><![CDATA[ 




<p>Pandoc’s Markdown allows for “fancy lists”, i.e., lists with different styles used for the marker of ordered list items.</p>
<p>E.g., the list</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb1-1">(I)  primus</span>
<span id="cb1-2">(#)  secundus</span>
<span id="cb1-3">(#)  tertius</span></code></pre></div>
<p>uses uppercase roman numerals and double parentheses for the markers. It gets rendered as</p>
<blockquote class="blockquote">
<ol type="I">
<li>primus</li>
<li>secundus</li>
<li>tertius</li>
</ol>
</blockquote>
<section id="continuations" class="level2">
<h2 class="anchored" data-anchor-id="continuations">Continuations</h2>
<p>The fancy lists feature also allows to continue lists after an intermediate paragraph:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb2-1">i.   one</span>
<span id="cb2-2">#.   another</span>
<span id="cb2-3"></span>
<span id="cb2-4">Interruption; not part of any list.</span>
<span id="cb2-5"></span>
<span id="cb2-6">iii. continue</span>
<span id="cb2-7">#.   keep counting</span></code></pre></div>
<p>This becomes</p>
<blockquote class="blockquote">
<ol type="i">
<li>one</li>
<li>another</li>
</ol>
<p>Interruption; not part of any list.</p>
<ol start="3" type="i">
<li>continue</li>
<li>keep counting</li>
</ol>
</blockquote>
<p>While very convenient, this requires us to carefully keep book of the number of items in previous parts, or risk the item numbering to become inconsistent. Imagine having to find and update all other list parts after adding a single item somewhere. Tedious work, that gets tiresome quickly.</p>
</section>
<section id="convention" class="level2">
<h2 class="anchored" data-anchor-id="convention">Convention</h2>
<p>Wanting none of this, we magicked a method that allows us to mark a list as a continuation. This way, we can search for those lists with a Lua filter and let pandoc do the counting and numbering for us.</p>
<p>Our convention is this: any list that starts with a number of 90 or above is treated as the continuation of a previous list. Why 90? Because it’s large, but still easy to express using roman numerals, should one be inclined to use those.</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb3-1">i.  primus</span>
<span id="cb3-2">ii. secundus</span>
<span id="cb3-3"></span>
<span id="cb3-4">Lorem ipsum.</span>
<span id="cb3-5"></span>
<span id="cb3-6">xc. alius item</span>
<span id="cb3-7">#.  ut custodians iens</span></code></pre></div>
</section>
<section id="lua-doing-the-counting" class="level2">
<h2 class="anchored" data-anchor-id="lua-doing-the-counting">Lua doing the counting</h2>
<p>The next step is to let pandoc do the counting with the help of a Lua filter. In its simplest form, the filter will step through all ordered lists in the document, remember the number of items it has encountered, and renumber any list whose start is above our chosen threshold.</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb4-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> OrderedList <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-4">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">then</span></span>
<span id="cb4-5">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_start</span></span>
<span id="cb4-6">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span></span>
<span id="cb4-7">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">else</span></span>
<span id="cb4-8">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb4-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb4-10">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span></span>
<span id="cb4-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>Applied to the example above, the filter produces the desired result:</p>
<blockquote class="blockquote">
<ol type="i">
<li>primus</li>
<li>secundus</li>
</ol>
<p>Lorem ipsum.</p>
<ol start="3" type="i">
<li>alius item</li>
<li>ut custodians iens</li>
</ol>
</blockquote>
</section>
<section id="refinements" class="level2">
<h2 class="anchored" data-anchor-id="refinements">Refinements</h2>
<p>This is fairly good already. But what happens if there are <em>other</em> lists appearing in the intermediate blocks?</p>
<pre><code>1. First item

- Nested list:

    a. alfa
    b. bravo
    c. charlie

Which list will be continued?

99. ???</code></pre>
<p>With the current state of our filter, the last item will be numbered <code>d.</code>, which is most likely not what we want. So let’s make the filter sensitive to the list style; only a list with the matching style will be continued.</p>
<p>The style and delimiter of ordered list markers can be accessed via the element’s <code>style</code> and <code>delimiter</code> property, respectively. We use those values to construct a string key under which the start number of the next continuation is stored in table <code>next_starts</code>.</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb6-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_starts</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span></span>
<span id="cb6-2"></span>
<span id="cb6-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> OrderedList <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb6-4">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">key</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">style</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'|'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">delimiter</span></span>
<span id="cb6-5">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">90</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">then</span></span>
<span id="cb6-6">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_starts</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">key</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">or</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb6-7">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_starts</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">key</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">start</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span></span>
<span id="cb6-8">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">else</span></span>
<span id="cb6-9">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">next_starts</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">key</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span>
<span id="cb6-10">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb6-11"></span>
<span id="cb6-12">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">ol</span></span>
<span id="cb6-13"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>This way we can keep track of multiple lists, distinguishing between lists by using the style of their markers. The above now gets output as</p>
<blockquote class="blockquote">
<ol type="1">
<li>First item</li>
</ol>
<ul>
<li><p>Nested list:</p>
<ol type="a">
<li>alfa</li>
<li>bravo</li>
<li>charlie</li>
</ol></li>
</ul>
<p>Which list will be continued?</p>
<ol start="2" type="1">
<li>???</li>
</ol>
</blockquote>
<p>Just what we want. Happy list writing!</p>


</section>

 ]]></description>
  <category>Markdown</category>
  <category>pandoc</category>
  <category>filter</category>
  <guid>https://tarleb.com/posts/list-continuation/</guid>
  <pubDate>Mon, 28 Nov 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Semantic line breaks</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/semantic-line-breaks/</link>
  <description><![CDATA[ 




<p>Line breaks usually have no semantic meaning within a Markdown paragraph. However, using line breaks to mark the end of a sentece can help with productivity for various reasons.<sup>1</sup> Documents with one sentence per line are also called “ventilated prose”, and the <a href="https://writetheasciidocs.netlify.app">Write the {Ascii}Docs</a> website has a <a href="https://writetheasciidocs.netlify.app/ventilated-prose">good article on that topic</a>.</p>
<p>A question came up in a Slack channel, asking whether it was possible to convert existing Markdown docs to this style. Naturally, the answer is “pandoc can do that”, but that isn’t obvious here.</p>
<p>The solution that I came up with is centered around pandoc’s <em>SoftBreak</em> AST element. Pandoc uses SoftBreak elements internally to mark the place where line breaks occured in the input, but only if those breaks should be treated like spaces in most situations. The way to make those breaks visible in the output is to call pandoc with <code>--wrap=preserve</code> – only then will a line break in the input result in a break in the output in the same location.</p>
<pre><code>$ printf 'Hello\npandoc' | pandoc --to=markdown
⇒ Hello pandoc

$ printf 'Hello\npandoc' | pandoc --to=markdown --wrap=preserve
⇒ Hello
⇒ pandoc</code></pre>
<p>We are going to use SoftBreak for semantic line breaks, so the first step is to get rid of the SoftBreak elements created during parsing. A Lua filter can do so with</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SoftBreak</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Space<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>Then we check for strings that end with a period and are followed by a space. The space in such a combination is then turned into a SoftBreak.</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> semantic_line_feeds <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">el</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb3-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">inlines</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">el</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span></span>
<span id="cb3-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">inlines</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb3-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">inlines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">].</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">t</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Space'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">and</span></span>
<span id="cb3-5">       <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">inlines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">].</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">t</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Str'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">and</span></span>
<span id="cb3-6">       <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">inlines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">].</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">match</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'%.$'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">then</span></span>
<span id="cb3-7">      <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">inlines</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">i</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>SoftBreak<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb3-8">    <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb3-9">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb3-10">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">el</span></span>
<span id="cb3-11"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb3-12"></span>
<span id="cb3-13"><span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-14">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- remove soft breaks inserted during parsing.</span></span>
<span id="cb3-15">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">SoftBreak</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Space<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb3-16">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- insert semantic soft breaks</span></span>
<span id="cb3-17">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Para</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">semantic_line_feeds</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">Plain</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">semantic_line_feeds</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb3-18"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div>
<p>This filter can then be combined with the <code>--wrap=preserve</code> option to get the desired semantic line breaks.</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">printf</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'This. And that.'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">|</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pandoc</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-L</span> semlf.lua <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--wrap</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>preserve</span>
<span id="cb4-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">⇒</span> This.</span>
<span id="cb4-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">⇒</span> And that.</span></code></pre></div>
<p>There, mission accomplished.<sup>2</sup></p>




<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>It’s not my cup of tea, but I can see why people might like the concept.↩︎</p></li>
<li id="fn2"><p>There are some cases in which the filter does not give the correct result, for example when using American-style punctuation after quotes, or when a full sentence is emphasized. It should be possible to fix the filter for these edge cases, but it doesn’t seem worth the effort: the presented solution should work fine for 95&nbsp;% of all use cases.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>Markdown</category>
  <category>pandoc</category>
  <guid>https://tarleb.com/posts/semantic-line-breaks/</guid>
  <pubDate>Sun, 30 Oct 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Install pandoc in custom Docker images</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/tip-install-in-docker/</link>
  <description><![CDATA[ 




<p>When pandoc is used in larger pipelines, e.g.&nbsp;in combination with <a href="https://sphinx-doc.org">Sphinx</a>, it can be useful to pack everything up into one neat container. One option is to base the container on a pandoc image like <code>pandoc/core</code>, but this may be difficult due to other dependencies. In this case, the easiest option is to do this:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode dockerfile code-with-copy"><code class="sourceCode dockerfile"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">COPY</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">--from=pandoc/minimal:2.19.2</span> /pandoc /usr/bin/pandoc</span></code></pre></div>
<p>The snippet, when added to a Dockerfile, copies a statically compiled executable from an official build to <code>/usr/bin/pandoc</code>. The static pandoc binary can run on all Linux distributions, so it does not matter what distro the custom build is based on.</p>
<p>The documentation for the <a href="https://hub.docker.com/r/pandoc/minimal" class="uri">https://hub.docker.com/r/pandoc/minimal</a> has more info, including a list of supported versions (tags).</p>



 ]]></description>
  <category>pandoc</category>
  <category>tip</category>
  <category>Docker</category>
  <guid>https://tarleb.com/posts/tip-install-in-docker/</guid>
  <pubDate>Wed, 07 Sep 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Haskell usedata objects</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/haskell-lua-objects/</link>
  <description><![CDATA[ 




<p>When extending pandoc (or Quarto) with Lua filters, we interact with so-called Lua userdata objects. These objects are used to wrap document AST elements, making them accessible from Lua scripts. They mostly behave like normal Lua tables. This post is intended as a quick overview, listing interesting properties of userdata objects.</p>
<section id="userdata-objects" class="level2">
<h2 class="anchored" data-anchor-id="userdata-objects">Userdata objects</h2>
<p>Haskell-generated userdata objects have three main components: a type <em>name</em>, <em>properties</em>, and <em>methods</em>:</p>
<section id="type-name" class="level3">
<h3 class="anchored" data-anchor-id="type-name">Type name</h3>
<p>The <em>name</em> can be retrieved with <code>pandoc.utils.type</code>. It should be treated as a read-only constant. Internally, the <em>name</em> is used as a type tag, which is important when retrieving an object from a Lua script back into the main program. It is possible to access the name through the debug interface, e.g.,</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> typename <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">debug.getmetatable</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">).</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">__name</span></span>
<span id="cb1-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>The above <code>typename</code> function is actually a bit faster than <code>pandoc.utils.type</code>. It can improve performance when accessing this info in a tight loop, but its use is not recommended.</p>
</section>
<section id="properties" class="level3">
<h3 class="anchored" data-anchor-id="properties">Properties</h3>
<p><em>Properties</em>, e.g., the <code>content</code> fields of <em>Para</em> elements, are “lazy”: the property value is marshaled to Lua when the property is accessed for the first time. We are usually interested in no more than one or two element properties, so this is a big performance improvement for most scripts. Lazy properties are especially useful with large objects like <em>Pandoc</em>, which would otherwise take a long time to marshal and unmarshal with all their child elements.</p>
<p>However, this lazy marshaling is slower if all properties will be accessed anyway. If there are performance issues due to lazy properties, then please let me know, and I’ll try to find a fix.</p>
</section>
<section id="methods" class="level3">
<h3 class="anchored" data-anchor-id="methods">Methods</h3>
<p><em>Methods</em> are wrapped Haskell functions: when calling a method, the arguments are unmarshaled back into Haskell objects, which are then passed to the wrapped function and processed in Haskell. The computation’s result is then pushed back to Lua.</p>
<p>This may sound weirdly complicated. While <em>it is</em> slow for very simple functions (like <code>pandoc.utils.type</code>), it’s very fast and convenient for complex methods like <code>Pandoc:walk</code>: objects with lazy properties are fast to unmarshal, the main Haskell code is fast, and it frees us from having to re-implement Haskell algorithms in Lua.</p>
</section>
<section id="iterating" class="level3">
<h3 class="anchored" data-anchor-id="iterating">Iterating</h3>
<p>The properties and methods are listed when iterating with <code>pairs</code>. The iteration order is defined at compile time, with properties listed first, followed by methods. We usually try to keep each of these lists sorted alphabetically, but there may be exceptions.</p>
<p>Calling <code>pairs</code> on a Haskell userdata object will always succeed, even if it has neither methods nor properties; the result will be the empty iterator in that case.</p>
</section>
<section id="aliases" class="level3">
<h3 class="anchored" data-anchor-id="aliases">Aliases</h3>
<p>Some objects also have property aliases: E.g., <code>div.classes</code> is really just an alias for <code>div.attr.classes</code>. Both entries point to the same list object. Aliases are not included in the iterator generated by <code>pairs</code>. See the internals on how to get a hold of them.</p>
</section>
<section id="list-behavior" class="level3">
<h3 class="anchored" data-anchor-id="list-behavior">List behavior</h3>
<p>Userdata objects can be made to behave like lists, but iterating over those “lists” is comparatively slow. That’s why the only object that uses this feature is <code>PANDOC_VERSION</code>: for example, we can write <code>PANDOC_VERSION[2] &gt;= 19</code> to check <em>just</em> the major version.<sup>1</sup></p>
</section>
<section id="internals" class="level3">
<h3 class="anchored" data-anchor-id="internals">Internals</h3>
<p>Each type has a metatable, which defines its behavior. Most users should not need to access the metatable, so the <code>getmetatable</code> function returns <code>true</code> instead of the actual metatable when called on a Haskell userdata object. As we’ve seen with type names, It’s still possible to inspect the userdata metatable with the help of <code>debug.getmetatable</code>.</p>
<p>The metatable has four interesting fields: <code>methods</code>, <code>aliases</code>, <code>getters</code>, and <code>setters</code>. The fields contain just what you’d expect.</p>
<p>E.g., we can inspect the list of aliases defined for Inline objects with</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">InlineMT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">debug.getmetatable</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Str <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb2-2"><span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">keys</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">in</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pairs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">InlineMT</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">aliases</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb2-3">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- print the alias name and the alias value</span></span>
<span id="cb2-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">name</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'is an alias for'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table.concat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">keys</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'.'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb2-5"><span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>Do not rely on the internal structure, and do not modify the metatable. Here be dragons.</p>


</section>
</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>This feature exists only to ensure backwards compatibility. It is better to do comparisons in like <code>PANDOC_VERSION &gt;= '2.19'</code> instead.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>Haskell</category>
  <category>Lua</category>
  <category>pandoc</category>
  <category>Quarto</category>
  <guid>https://tarleb.com/posts/haskell-lua-objects/</guid>
  <pubDate>Wed, 07 Sep 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Document font</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/tip-document-font/</link>
  <description><![CDATA[ 




<p>Setting the document font this way works for ConTeXt, LaTeX, and HTML output. The fonts used in docx or odt output must be controlled with the reference document instead.</p>
<p>The default LaTeX engine is pdflatex, which only supports TeX’s own font format and cannot use the TrueType or OpenType fonts installed on the system. However, XeLaTeX was written with that in mind; switching to that engine allows to specify any font available on the system.</p>
<p>A good source for free fonts is the <a href="https://fonts.google.com">Google Fonts</a> repository.</p>



 ]]></description>
  <category>pandoc</category>
  <category>tip</category>
  <category>PDF</category>
  <category>HTML</category>
  <guid>https://tarleb.com/posts/tip-document-font/</guid>
  <pubDate>Wed, 07 Sep 2022 00:00:00 GMT</pubDate>
  <media:content url="https://tarleb.com/images/pandoc-logo.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Generating a sitemap with Quarto</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/quarto-sitemap/</link>
  <description><![CDATA[ 




<p>Sitemaps are an easy way to list all pages that a search engine should crawl and index. Quarto supports the standard, XML based <a href="https://www.sitemaps.org/protocol.html">Sitemap Protocol</a>, although that fact is a bit hidden in the docs.</p>
<p>Quarto will automatically produce a sitemap if the website’s URL is given as <code>site-url</code> property:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">website</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb1-2"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">title</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> tarleb</span></span>
<span id="cb1-3"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">site-url</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://tarleb.com'</span></span>
<span id="cb1-4"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">site-path</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'/'</span></span></code></pre></div>
<p>The URL will contain a colon <code>:</code>, which is why the YAML value must be put in quotes.</p>
<p>You’ll find the <code>sitemap.xml</code> file in your <code>_site</code> folder after re-rendering your pages with <code>quarto render</code>.</p>



 ]]></description>
  <category>quarto</category>
  <guid>https://tarleb.com/posts/quarto-sitemap/</guid>
  <pubDate>Wed, 24 Aug 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Pandoc resources</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/pandoc-resources/</link>
  <description><![CDATA[ 




<p>These are the resources that I’d want to have if I was to learn about <a href="https://pandoc.org/">pandoc (the universal document converter)</a> all over again:</p>
<section id="installing" class="level2">
<h2 class="anchored" data-anchor-id="installing">Installing</h2>
<dl>
<dt><a href="https://github.com/jgm/pandoc/releases/latest">latest release</a></dt>
<dd>
The GitHub release page has installers for Windows, macOS, and Linux.
</dd>
<dt><a href="https://hub.docker.com/u/pandoc">Docker images</a></dt>
<dd>
<p>There are three types of pandoc Docker images:</p>
<ul>
<li><a href="https://hub.docker.com/r/pandoc/minimal">minimal</a> – very small, just the bare pandoc binary;</li>
<li><a href="https://hub.docker.com/r/pandoc/core">core</a> – includes pandoc-crossref and helpers programs, e.g. those used by pandoc for SVG image conversion;</li>
<li><a href="https://hub.docker.com/r/pandoc/latex">latex</a> – like core, plus TeXLive with all packages required by the default template.</li>
</ul>
<p>These images can be used as an alternative to a system-wide installation. The image repository descriptions also explain how the images can be used.</p>
</dd>
</dl>
</section>
<section id="documentation" class="level2">
<h2 class="anchored" data-anchor-id="documentation">Documentation</h2>
<dl>
<dt><a href="https://pandoc.org/MANUAL.html">manual</a></dt>
<dd>
<p>The <a href="https://pandoc.org/MANUAL.html">official pandoc manual</a>. When in doubt, this should always be the first resource to check. It covers all command line options, defaults files settings, format extensions, etc.</p>
<p>Note that this always documents the latest pandoc version. If something isn’t working as documented, you may need to update.</p>
</dd>
<dt><a href="https://pandoc.org/faqs.html">FAQs</a></dt>
<dd>
Frequently Asked Questions; click on the questions to see the answer.
</dd>
<dt><a href="https://github.com/jgm/pandoc/wiki">Wiki</a></dt>
<dd>
Pandoc’s GitHub wiki; contains many additional resources, links, and tips.
</dd>
<dt><a href="https://pandoc.org/lua-filters">Lua filters</a></dt>
<dd>
How to modify a document programmatically; also documents all constructors and utility functions exposed by pandoc.
</dd>
<dt><a href="https://pandoc.org/custom-readers">Custom reader</a></dt>
<dd>
Interface that allows to write parsers for otherwise unsupported formats.
</dd>
<dt><a href="https://pandoc.org/custom-writers">Custom writers</a></dt>
<dd>
Interface that allows to use pandoc to convert to a custom output format.
</dd>
<dt>Format-specific documentation</dt>
<dd>
<p>The support for some formats is tune-able enough to warrant additional documentation.</p>
<ul>
<li><a href="https://pandoc.org/epub.html">EPUB</a> – How to make an ebook</li>
<li><a href="https://pandoc.org/org.html">Org</a> – Emacs Org-mode</li>
<li><a href="https://pandoc.org/jats.html">JATS</a> – The Journal Article Tag Set</li>
</ul>
</dd>
</dl>
</section>
<section id="getting-help" class="level2">
<h2 class="anchored" data-anchor-id="getting-help">Getting help</h2>
<p>Please make sure to search the web before posting.</p>
<dl>
<dt><a href="https://groups.google.com/g/pandoc-discuss">pandoc-discuss</a></dt>
<dd>
<p>Official pandoc mailing list; usually the best way to get help. The main developers and many seasoned users lurk here and answer questions.</p>
<p>The web interface makes it seem like a Google account is required to post, but this isn’t so: Write a mail to <span class="obfuscated-mail-address" data-domain="googlegroups.com" data-user="pandoc-discuss+subscribe"><em>obfuscated mail address</em></span> to subscribe to the list with any mail address.</p>
</dd>
<dt><a href="https://stackoverflow.com/tags/pandoc/">StackOverflow</a></dt>
<dd>
Post here to reach a more programming oriented group of people. Please <em>do not</em> cross-post, many people that follow the <a href="https://stackoverflow.com/tags/pandoc/">pandoc tag</a> have also subscribed to the mailing list.
</dd>
<dt><a href="https://tex.stackexchange.com/">TeX/LaTeX Stack Exchange</a></dt>
<dd>
This is a good place to ask for help when pandoc is used to generate PDFs via LaTeX. Be sure to include the (relevant parts) of the generated LaTeX output in your question, as most people there do not use pandoc. Some even seem to actively dislike it, so be prepared.
</dd>
</dl>
</section>
<section id="misc" class="level2">
<h2 class="anchored" data-anchor-id="misc">Misc</h2>
<dl>
<dt><a href="https://fosstodon.org/@pandoc">pandoc in the fediverse</a></dt>
<dd>
I use this Mastodon account to post small tips and updates.
</dd>
<dt><a href="https://quarto.org">Quarto</a></dt>
<dd>
Scientific and technical publishing system based on pandoc.
</dd>
<dt><a href="https://zettlr.com">Zettlr</a></dt>
<dd>
Markdown editor with “zettelkasten” functionality.
</dd>
</dl>
</section>
<section id="edits" class="level2">
<h2 class="anchored" data-anchor-id="edits">Edits</h2>
<ul>
<li><em>2022-12-09</em>: Added Mastodon account in favor of Twitter; the account on the latter platform is no longer updated.</li>
</ul>


</section>

 ]]></description>
  <category>pandoc</category>
  <guid>https://tarleb.com/posts/pandoc-resources/</guid>
  <pubDate>Tue, 23 Aug 2022 00:00:00 GMT</pubDate>
  <media:content url="https://tarleb.com/posts/pandoc-resources/pandoc.png" medium="image" type="image/png" height="144" width="144"/>
</item>
<item>
  <title>Quarto Website with GitHub Actions</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/quarto-with-gh-pages/</link>
  <description><![CDATA[ 




<p><a href="https://quarto.org">Quarto</a> makes it very easy to publish a website via GitHub Pages: It is as simple as running <code>quarto publish gh-pages</code>. Here we explore a slightly different method that uses a GitHub Action to publish the website automatically every time it is updated.</p>
<section id="classic-github-pages" class="level2">
<h2 class="anchored" data-anchor-id="classic-github-pages">Classic GitHub Pages</h2>
<p>The classic way to publish a website via GitHub pages is to maintain a separate branch <code>gh-pages</code>. The branch is used to store the rendered HTML pages, and GitHub will publish the branch’s contents as website everytime that branch is updated.</p>
<p>Quarto uses this mechanism when called with</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">quarto</span> publish gh-pages</span></code></pre></div>
<p>We can combine this with GitHub Actions easily, ensuring that the site is updated every time new content is pushed to the main branch.</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># file: .github/workflows/publish.yml</span></span>
<span id="cb2-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Publish Website</span></span>
<span id="cb2-3"></span>
<span id="cb2-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Allow one concurrent deployment</span></span>
<span id="cb2-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">concurrency</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb2-6"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pages"</span></span>
<span id="cb2-7"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cancel-in-progress</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb2-8"></span>
<span id="cb2-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">on</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb2-10"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb2-11"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">branches</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'main'</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb2-12"></span>
<span id="cb2-13"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">jobs</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb2-14"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quarto-publish</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb2-15"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Publish with Quarto</span></span>
<span id="cb2-16"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runs-on</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> ubuntu-latest</span></span>
<span id="cb2-17"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">steps</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb2-18"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Checkout repository</span></span>
<span id="cb2-19"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> actions/checkout@v3</span></span>
<span id="cb2-20"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Install Quarto</span></span>
<span id="cb2-21"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> quarto-dev/quarto-actions/setup@v2</span></span>
<span id="cb2-22"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Publish to GitHub Pages</span></span>
<span id="cb2-23"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> quarto-dev/quarto-actions/publish@v2</span></span>
<span id="cb2-24"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">with</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb2-25"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">          </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">target</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> gh-pages</span></span></code></pre></div>
<p>The <code>quart-dev/quart-actions/publish</code> action calls <code>quarto publish</code> internally. This is short, to the point, and won’t interfere with local calls to <code>quarto publish gh-pages</code>.</p>
</section>
<section id="actions-only-pages-beta" class="level2">
<h2 class="anchored" data-anchor-id="actions-only-pages-beta">Actions-only Pages (Beta)</h2>
<p>GitHub recently added support for GitHub Pages that do not require an extra <code>gh-pages</code> branch. Instead, the website is compiled and pushed directly from an action.</p>
<p>This takes slightly more code to set up, as the action must be granted the necessary permissions. However, it is still fairly short and quick to do.</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode yaml code-with-copy"><code class="sourceCode yaml"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># file: .github/workflows/publish.yml</span></span>
<span id="cb3-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Publish Website</span></span>
<span id="cb3-3"></span>
<span id="cb3-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Allow one concurrent deployment</span></span>
<span id="cb3-5"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">concurrency</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-6"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">group</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"pages"</span></span>
<span id="cb3-7"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">cancel-in-progress</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">true</span></span>
<span id="cb3-8"></span>
<span id="cb3-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages</span></span>
<span id="cb3-10"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">permissions</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-11"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">contents</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> read</span></span>
<span id="cb3-12"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">pages</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> write</span></span>
<span id="cb3-13"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">id-token</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> write</span></span>
<span id="cb3-14"></span>
<span id="cb3-15"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">on</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-16"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">push</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-17"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">branches</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'main'</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb3-18"></span>
<span id="cb3-19"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">jobs</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-20"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">  </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">quarto</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-21"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">runs-on</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> ubuntu-latest</span></span>
<span id="cb3-22"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">environment</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-23"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> github-pages</span></span>
<span id="cb3-24"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">url</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> ${{ steps.deployment.outputs.page_url }}</span></span>
<span id="cb3-25"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">    </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">steps</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-26"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Checkout repository</span></span>
<span id="cb3-27"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> actions/checkout@v3</span></span>
<span id="cb3-28"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Install Quarto</span></span>
<span id="cb3-29"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> quarto-dev/quarto-actions/setup@v2</span></span>
<span id="cb3-30"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Setup Pages</span></span>
<span id="cb3-31"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> actions/configure-pages@v1</span></span>
<span id="cb3-32"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Render Website</span></span>
<span id="cb3-33"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">run</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> quarto render</span></span>
<span id="cb3-34"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Upload artifact</span></span>
<span id="cb3-35"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> actions/upload-pages-artifact@v1</span></span>
<span id="cb3-36"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">with</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span></span>
<span id="cb3-37"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">          </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">path</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'_site'</span></span>
<span id="cb3-38"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">      </span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">-</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">name</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> Deploy to GitHub Pages</span></span>
<span id="cb3-39"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">id</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> deployment</span></span>
<span id="cb3-40"><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">        </span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uses</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">:</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;"> actions/deploy-pages@main</span></span></code></pre></div>
<p>Now we must change the setting to use the new publishing workflow:</p>
<p>Under <em>Settings</em> → <em>Pages</em> → <em>Build and deployment</em> the source must be switched to “GitHub Action”:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://tarleb.com/posts/quarto-with-gh-pages/pages-settings.png" class="img-fluid figure-img"></p>
<figcaption>Required setting to enable the new method</figcaption>
</figure>
</div>
<p>The <code>gh-pages</code> branch is no longer needed and can be deleted.</p>
</section>
<section id="trade-offs" class="level2">
<h2 class="anchored" data-anchor-id="trade-offs">Trade-offs</h2>
<p>The branch-based method for GitHub pages always felt slightly inelegant. I prefer the new method, as it does not require an extra branch and feels much cleaner. We lose the ability to update the website via <code>quarto publish</code>, but as I usually rely on GitHub Actions to perform the updates, it doesn’t affect me much: <code>git push</code> has the same effect. However, it seems important to be aware of this trade-off.</p>


</section>

 ]]></description>
  <category>quarto</category>
  <guid>https://tarleb.com/posts/quarto-with-gh-pages/</guid>
  <pubDate>Mon, 08 Aug 2022 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Santa’s Little Lua Scripts</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/santas-little-lua-scripts/</link>
  <description><![CDATA[ 




<p>Santa sighted deeply as worry and uncertainty gave way, leaving a feeling of relieve and accomplishment. The year was one of the worst he’d seen so far. Large numbers of his helpers were moving from the North Pole to Antarctica to satisfy their ambient temperature preferences. There would be many telecommuting Elves this year, and each helper enjoyed additional autonomy. Tying everything together was a challenge. But he had succeeded: the wishes processing program was finished, and the elves would be able to help Santa from the comfort of their new homes.</p>
<section id="wishes" class="level2">
<h2 class="anchored" data-anchor-id="wishes">Wishes</h2>
<p>The part of the wishes system that Santa had been working on was focused on classic toys: wooden bricks, dolls, and train sets.</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">data</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Toy</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Bricks</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">TrainSet</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Doll</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">deriving</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Show</span></span></code></pre></div>
<p>The system also kept track of basic data about the children:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">data</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Behavior</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Nice</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Naughty</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">deriving</span> (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Eq</span>, <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Show</span>)</span>
<span id="cb2-2"></span>
<span id="cb2-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">data</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span></span>
<span id="cb2-4">  {<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> childName     ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Text</span></span>
<span id="cb2-5">  ,<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> childBehavior ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Behavior</span></span>
<span id="cb2-6">  } <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">deriving</span> (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Show</span>)</span></code></pre></div>
<p>Children and toys were tied together in a wish.</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">data</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span></span>
<span id="cb3-2">  {<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> wishingChild ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span></span>
<span id="cb3-3">  ,<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> wishedToy    ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Toy</span></span>
<span id="cb3-4">  } <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">deriving</span> (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Show</span>)</span></code></pre></div>
<p>It was most elegant. The problem for Santa was that the Elves, being independent and autonomous workers, needed to access and process the data in very custom ways. Unfortunately for him, very few Elves had a Haskell build environment installed, so he had to distribute the binary. Writing a completely custom processing language seemed like an enormous rabbit hole.</p>
</section>
<section id="lua" class="level2">
<h2 class="anchored" data-anchor-id="lua">Lua</h2>
<p>Fortunately, Santa had a better idea: <a href="https://lua.org/">Lua</a>, an embeddable scripting language. He had been using it for some projects<sup>1</sup> and also made use of it in <a href="https://pandoc.org/lua-filters.html">pandoc</a>, which he used to answer his mails. Santa would just need to expose the relevant parts of the Haskell system, so the Elves could access and script it as their hearts desired. He looked for a library, found <a href="https://github.com/hslua/hslua">HsLua</a>, and got to work.</p>
</section>
<section id="exposing-data" class="level2">
<h2 class="anchored" data-anchor-id="exposing-data">Exposing data</h2>
<p>Lua has a simple, yet powerful, stack-based <a href="https://www.lua.org/manual/5.4/manual.html#4">API</a>. The first step towards exposing Haskell data was to push them to the Lua stack. Keeping things simple, Santa chose strings to represent toys:</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb4-1"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">pushToy ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Toy</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Lua</span> ()</span>
<span id="cb4-2">pushToy <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> pushString <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">show</span></span></code></pre></div>
<p>Lua offers only a single construct to structure data: tables. So that’s what Child and Wish were represented with.</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb5-1"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">pushChild ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Lua</span> ()</span>
<span id="cb5-2">pushChild (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span> name behavior) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb5-3">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- create new Lua table on the stack</span></span>
<span id="cb5-4">  newtable</span>
<span id="cb5-5">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- push string to stack</span></span>
<span id="cb5-6">  pushText name</span>
<span id="cb5-7">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- table now in position 2; assign string to field in table</span></span>
<span id="cb5-8">  setfield (nth <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"name"</span></span>
<span id="cb5-9"></span>
<span id="cb5-10">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- push boolean to stack</span></span>
<span id="cb5-11">  pushBool (behavior <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Nice</span>)</span>
<span id="cb5-12">  setfield (nth <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"nice"</span></span>
<span id="cb5-13"></span>
<span id="cb5-14"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">pushWish ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Lua</span> ()</span>
<span id="cb5-15">pushWish (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span> child toy) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb5-16">  newtable</span>
<span id="cb5-17">  pushChild child</span>
<span id="cb5-18">  setfield (nth <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"child"</span></span>
<span id="cb5-19">  pushToy toy</span>
<span id="cb5-20">  setfield (nth <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span>) <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"toy"</span></span></code></pre></div>
</section>
<section id="running-scripts" class="level2">
<h2 class="anchored" data-anchor-id="running-scripts">Running scripts</h2>
<p>Santa’s goal for now was to allow his Elves to filter the list of wishes so each finds the ones relevant to them. For example, if an Elf only cares about wishes for train sets from children who were nice, then they should be able to use a script to filter those wishes out.</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb6-1"><span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">wish</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb6-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">wish</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">child</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">nice</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">and</span></span>
<span id="cb6-3">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">wish</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">toy</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'TrainSet'</span></span>
<span id="cb6-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>The script returns a (lambda) function that serves as a predicate for wishes. The function can be thought of having the type <code>Wish -&gt; IO Bool</code>. Santa needed to turn the Lua lambda function into an actual Haskell function <code>runPredicate :: Wish -&gt; Lua Bool</code>. If Santa assumed that the lambda function was at the top of the Lua stack, then he could push a <code>Wish</code> value to the Lua stack, call the function, and retrieve the result value from the stack.</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb7-1"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">runPredicate ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">-&gt;</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Lua</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Bool</span></span>
<span id="cb7-2">runPredicate wish <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb7-3">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Assume filter function is at the top of the stack;</span></span>
<span id="cb7-4">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- create a copy so we can re-use it.</span></span>
<span id="cb7-5">  pushvalue top</span>
<span id="cb7-6">  pushWish wish</span>
<span id="cb7-7">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Call the function. There is one argument on the stack,</span></span>
<span id="cb7-8">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- and we expect one result to be returned.</span></span>
<span id="cb7-9">  call (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">NumArgs</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>) (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">NumResults</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span>)</span>
<span id="cb7-10">  toboolean top <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;*</span> pop <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span></span></code></pre></div>
<p>What remained was loading the Elves’ script files. Santa did this with <a href="https://hackage.haskell.org/package/hslua/docs/Foreign-Lua-Core.html#v:dofile"><code>dofile</code></a> of type <code>FilePath -&gt; Lua Status</code>. The predicate then ends up on the top of the Lua stack, and can be called through <code>runPredicate</code>, e.g.&nbsp;to select a subset of wishes via <a href="https://hackage.haskell.org/package/base/docs/Control-Monad.html#v:filterM"><code>filterM</code></a>.</p>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb8-1"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">main ::</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">IO</span> ()</span>
<span id="cb8-2">main <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb8-3">  filterFile <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">fmap</span> (<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">!!</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span>) getArgs <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- get first argument</span></span>
<span id="cb8-4">  result <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> run <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">$</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb8-5">    _status <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">&lt;-</span> dofile filterFile</span>
<span id="cb8-6">    filterM runPredicate wishes</span>
<span id="cb8-7">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">print</span> result</span></code></pre></div>
<p>Santa tested his creation on a short list of wishes</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode haskell code-with-copy"><code class="sourceCode haskell"><span id="cb9-1"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">wishes ::</span> [<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span>]</span>
<span id="cb9-2">wishes <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">=</span></span>
<span id="cb9-3">  [ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span> (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Theodor"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Nice</span>) <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Bricks</span></span>
<span id="cb9-4">  , <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span> (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Philine"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Nice</span>) <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">TrainSet</span></span>
<span id="cb9-5">  , <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Wish</span> (<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Child</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Steve"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Naughty</span>) <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">Doll</span></span>
<span id="cb9-6">  ]</span></code></pre></div>
<p>by running <code>runhaskell wish-filter predicate.lua</code>. To his uttermost satisfaction, the terminal echoed the right information back to him.</p>
<pre><code>[Wish {wishingChild = Child {childName = "Philine", childBehavior = Nice}, wishedToy = TrainSet}]</code></pre>
<p>He reclined in his chair, shut down his device, and enjoyed a double chocolate chip cookie of which he felt very deserving now.</p>
<hr>
<p>Santa’s full code, as presented here, is available as part of the examples at <a href="https://github.com/hslua/hslua" class="uri">https://github.com/hslua/hslua</a>.</p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Santa learned about Lua from his game-devs. Now he uses it to keep his security teams on their toes with <a href="https://nmap.org">nmap</a> and <a href="https://wireshark.org/">Wireshark</a>; many of the North Pole’s servers contain custom Lua scripts, too (<a href="https://redis.io/commands/eval">redis</a>, <a href="https://github.com/openresty">nginx/OpenResty</a>, <a href="https://www.haproxy.com/blog/5-ways-to-extend-haproxy-with-lua/">HAProxy</a>, <a href="https://doc.powerdns.com/authoritative/lua-records/index.html">PowerDNS</a>).↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>lua</category>
  <category>hslua</category>
  <category>example</category>
  <guid>https://tarleb.com/posts/santas-little-lua-scripts/</guid>
  <pubDate>Sun, 06 Dec 2020 00:00:00 GMT</pubDate>
</item>
<item>
  <title>PDF Version of the Lua Manual</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/pdf-of-the-lua-manual/</link>
  <description><![CDATA[ 




<p>A question came up on the Lua mailing list, asking whether there was a PDF version of the <a href="https://lua.org/manual/5.4/manual.html">Lua manual</a>. This is, of course, the home domain of pandoc, and I got nerd-sniped into producing a PDF (and ePUB) version of the manual.</p>
<p>This is a good opportunity to showcase some pandoc features. The post describes the process of going from an HTML web page to a PDF file via LaTeX and pandoc. We will see how to</p>
<ol type="1">
<li>quickly convert documents with pandoc;</li>
<li>use Lua filters to improve the result by modifying the document; and</li>
<li>fine-tune the output by setting appropriate pandoc options.</li>
</ol>
<section id="invoking-pandoc" class="level2">
<h2 class="anchored" data-anchor-id="invoking-pandoc">Invoking pandoc</h2>
<p>The first step is to call pandoc on the Lua manual website. Even when keeping everything bare-bones, the result is already decent:</p>
<pre><code>pandoc --pdf-engine=xelatex --output=lua-manual.pdf \
    "https://lua.org/manual/5.4/manual.html"</code></pre>
<p>Produces</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://tarleb.com/posts/pdf-of-the-lua-manual/lua-refman-naive.png" class="img-fluid figure-img"></p>
<figcaption>First page of unoptimized PDF</figcaption>
</figure>
</div>
<p>This requires a somewhat recent version of pandoc as well as XeLaTeX to be installed. It is possible to forgo the trouble of installing the requirements by using the <em>pandoc/latex</em> Docker image:</p>
<pre><code>docker run --rm -v "$PWD":/data -u $(id -u):$(id -g) pandoc/latex:2.9.2.1 \
    --pdf-engine=xelatex --output=lua-manual.pdf \
    "https://lua.org/manual/5.4/manual.html"</code></pre>
</section>
<section id="replacing-characters" class="level2">
<h2 class="anchored" data-anchor-id="replacing-characters">Replacing characters</h2>
<p>The above commands will produce warnings about characters which are unavailable in the default fonts. We don’t want characters to go missing, of course, so let’s fix that first. The warnings are:</p>
<pre><code>[WARNING] Missing character: There is no ≤ (U+2264) in font [lmmono10-regular]:!
[WARNING] Missing character: There is no ≤ (U+2264) in font [lmmono10-regular]:!
[WARNING] Missing character: There is no π (U+03C0) in font [lmroman10-italic]:mapping=tex-text;!</code></pre>
<p>Searching the page for <code>≤</code> shows that it is used in inline code, while <code>π</code> occurs as emphasized character in the description of <code>math.pi</code>. We could, of course, search for a font which has the appropriate glyphs and instruct pandoc/LaTeX to use it. But we’ll go a different route.</p>
<p>A good way to improve the result of a converstion is to use a pandoc <a href="https://pandoc.org/lua-filters.html">Lua filter</a>. We create a file called <code>beautify-manual.lua</code> and pass it to pandoc via the <code>--lua-filter=beautify-manual.lua</code> command line option.</p>
<p>Handling <code>≤</code> is straight forward, we just replace the char with the slightly uglier looking ASCII sequence <code>&lt;=</code> in all code elements.</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb4-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> Code <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">c</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-2">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">c</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">text</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">c</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gsub</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'≤'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'&lt;='</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">c</span></span>
<span id="cb4-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>While there is no italics version <code>π</code> in the default font, there <em>is</em> such a glyph in the default math font. Pandoc’s internal representation for <em>π</em> is <code>Emph [Str "π"]</code>, which we replace with a math element holding the same content.</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> Emph <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">e</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">e</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb5-3">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">e</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">tag</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Str'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">text</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'π'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">then</span></span>
<span id="cb5-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Math<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'InlineMath'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'π'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-5">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb5-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>The document now compiles without warnings, and all characters are properly included.</p>
</section>
<section id="add-table-of-contents" class="level2">
<h2 class="anchored" data-anchor-id="add-table-of-contents">Add Table of Contents</h2>
<p>The Lua manual is long, often used as a reference, and, in its HTML version, comes with a table of contents on a separate page. The PDF, for it to be useful as a reference, should have a table of contents as well. Pandoc can be told to generate a table of contents by adding the <code>--toc</code> command line flag. The toc depth is controlled via <code>--toc-depth</code>; <code>2</code> is a good setting here. However, in this case, the result is neither pleasing nor informative:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://tarleb.com/posts/pdf-of-the-lua-manual/bad-toc.png" class="img-fluid figure-img"></p>
<figcaption>Bad looking table of contents</figcaption>
</figure>
</div>
<p>Something is terribly wrong. By inspecting the parsed document by running <code>pandoc --to=native …</code>, we see that all <em>Header</em>s contain a <em>Span</em>. That span holds the actual contents. Apparently LaTeX does not like this and omits the content of the span when generating the toc.</p>
<p>The span also has the id used by links to the header. Numbered sections start with the section number, which we’d rather produce via pandoc.</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb6-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> Header <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb6-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Unnumbered sections have the main contents as the first element.</span></span>
<span id="cb6-3">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Numbered sections start with the number and an em-dash, so</span></span>
<span id="cb6-4">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- the Span is the fifth element (Lua multipass).</span></span>
<span id="cb6-5">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">span</span></span>
<span id="cb6-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">if</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">].</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">tag</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">==</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Str'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">and</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">].</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">match</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'[%d%.]+'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">then</span></span>
<span id="cb6-7">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">span</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb6-8">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">else</span></span>
<span id="cb6-9">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">span</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb6-10">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">classes</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'unnumbered'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb6-11">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb6-12"></span>
<span id="cb6-13">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">identifier</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">span</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">identifier</span></span>
<span id="cb6-14">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">span</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span></span>
<span id="cb6-15"></span>
<span id="cb6-16">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">h</span></span>
<span id="cb6-17"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>The filter also removes the section numbering. We add it back by passing <code>--number-sections</code> to pandoc.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://tarleb.com/posts/pdf-of-the-lua-manual/less-bad-toc.png" class="img-fluid figure-img"></p>
<figcaption>less-bad table of contents</figcaption>
</figure>
</div>
<p>Not bad.</p>
</section>
<section id="improve-title-and-metadata" class="level2">
<h2 class="anchored" data-anchor-id="improve-title-and-metadata">Improve title and metadata</h2>
<p>The PDF is already quite usable, let’s prettify it a bit more: It would be important to properly list the authors in the title and metadata, remove the unnecessary first header, and maybe add the Lua logo to the title. All this is easiest when acting on the full document.</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb7-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> Pandoc <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb7-2">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- comma separated authors</span></span>
<span id="cb7-3">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">authors</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blocks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb7-4">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">authors</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">remove</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span>  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- remove 'by'</span></span>
<span id="cb7-5">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">meta</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">author</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>List<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">()</span></span>
<span id="cb7-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">for</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">author</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">in</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">utils</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>stringify<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">authors</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">):</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">gmatch</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'[^,]+'</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">do</span></span>
<span id="cb7-7">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">meta</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">author</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">insert</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">author</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb7-8">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span>
<span id="cb7-9"></span>
<span id="cb7-10">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Remove unnecessary blocks</span></span>
<span id="cb7-11">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blocks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">remove</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">4</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- menubar</span></span>
<span id="cb7-12">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blocks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">remove</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- authors paragraph</span></span>
<span id="cb7-13">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">blocks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">remove</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- title header</span></span>
<span id="cb7-14"></span>
<span id="cb7-15">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- add subtitle image</span></span>
<span id="cb7-16">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">meta</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">subtitle</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>MetaInlines<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb7-17">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>RawInline<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'latex'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\\</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">vspace{1em}'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">),</span></span>
<span id="cb7-18">    <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Image<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Lua logo"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- "https://www.lua.org/images/lua-logo.gif")</span></span>
<span id="cb7-19">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb7-20">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">doc</span></span>
<span id="cb7-21"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
</section>
<section id="final-touch" class="level2">
<h2 class="anchored" data-anchor-id="final-touch">Final touch</h2>
<p>Finally, we may want the PDF to add a little more visible structure, e.g., starting top-level sections on their own page.</p>
<p>The command used by pandoc to create the top level headings can be controlled with the <code>--top-level-division</code> option. Setting that option to <code>chapter</code> ensures that each major section starts on a new page. However, the default document class used by LaTeX doesn’t allow chapters, so a different class has to be set with <code>--variable documentclass=report</code>.</p>
</section>
<section id="summary" class="level2">
<h2 class="anchored" data-anchor-id="summary">Summary</h2>
<p>For completeness, <a href="lua-manual-cleanup.lua">here is the complete filter</a>, and this is the full pandoc command used to generate the PDF:</p>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pandoc</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-2">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--toc</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-3">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--toc-depth</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>2 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-4">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--metadata</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>documentclass=report <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-5">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--pdf-engine</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>xelatex <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-6">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--lua-filter</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>lua-manual-cleanup.lua <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-7">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--number-sections</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-8">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--top-level-division</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>chapter <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-9">  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--output</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>lua-5.4-manual.pdf <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb8-10">  <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://lua.org/manual/5.4/manual.html"</span></span></code></pre></div>
<p>One of the big advantages of pandoc is that it offers a lot of freedom. Since we already cleaned the content up, we can now also create other formats, like an ebook, just by changing the name of the output file. The final results are available below:</p>
<ul>
<li><a href="lua-5.4-manual.pdf">Lua 5.4 manual (PDF)</a></li>
<li><a href="lua-5.4-manual.epub">Lua 5.4 manual (EPUB)</a></li>
</ul>


</section>

 ]]></description>
  <category>pandoc</category>
  <category>lua</category>
  <category>pdf</category>
  <guid>https://tarleb.com/posts/pdf-of-the-lua-manual/</guid>
  <pubDate>Sat, 11 Jul 2020 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Extending pandoc with Lua</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/extending-pandoc-with-lua/</link>
  <description><![CDATA[ 




<p>My first exposure to Lua has been as a pandoc user, and adding new Lua features to pandoc turned Lua into one of my favorite languages. In this post I will take a look at <a href="https://pandoc.org/">pandoc</a>, the universal document converter, and explore how one can script and extend it with Lua. Pandoc includes a Lua interpreter since 2012, but the integration of Lua has been expanded significantly with the latest 2.0 release. My hope for this article is to highlight the beauty of these systems.</p>
<section id="the-universal-document-converter" class="level2">
<h2 class="anchored" data-anchor-id="the-universal-document-converter">The universal document converter</h2>
<p><a href="https://pandoc.org/">Pandoc</a> – written and maintained by <a href="https://johnmacfarlane.net">John MacFarlane</a> – is an relatively old project. It has grown considerably since the first version was published in 2006: at the time of writing, pandoc can read 27 different document formats and dialects, and can write 49 formats. Besides serving as a one-off document conversions tool, pandoc also frequently features as the central part of publishing pipelines. For example, Pandoc is used in <a href="https://github.com/mfenner/jekyll-pandoc">static</a> <a href="https://jaspervdj.be/hakyll/">site generators</a> and is frequently used <a href="https://programminghistorian.org/lessons/sustainable-authorship-in-plain-text-using-pandoc-and-markdown">by academic writers</a>, due also to its excellent support for citations.</p>
<p>As a brief example, consider the following commands which transform Markdown input into docx, HTML, or PDF:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># command to convert a markdown file to docx</span></span>
<span id="cb1-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pandoc</span> input-file.md <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--output</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>output-file.docx</span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># convert to HTML</span></span>
<span id="cb1-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pandoc</span> input-file.md <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--standalone</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--output</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>output-file.html</span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># convert to PDF (via LaTeX)</span></span>
<span id="cb1-8"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pandoc</span> input-file.md <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--output</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>output-file.pdf</span></code></pre></div>
<p>Many conversion tasks need to alter the default behavior or require special conversion features. This highlights the importance of good customization support for a conversion tool, one of the areas in which Lua shines.</p>
<p>Pandoc is unusual for a Lua-extendable program, in that it is written in Haskell. Using Haskell is very productive, but is less suitable as an extension language: its concepts are often alien to users of other languages, and shipping a full Haskell interpreter with pandoc would result in considerable bloat. Lua is an excellent choice here, as it is lightweight, simple, and beautiful. It should be noted, however, that <a href="https://github.com/hslua">bridging Haskell and Lua</a> is its own can of worms and worth a separate blog post.</p>
</section>
<section id="pandocs-document-ast" class="level2">
<h2 class="anchored" data-anchor-id="pandocs-document-ast">Pandoc’s document AST</h2>
<p>An important factor in pandoc’s immense transformation powers is its use of a unifying document representation: Every input is parsed into this document AST, which is then rendered in the desired output format. While a direct conversion between any of <em>n</em> input and <em>m</em> output formats would require <em>n </em> m* converters, using an intermediate representation reduces complexity to <em>n + m</em>.</p>
<p>There are additional advantages to this: as we’ll see, it becomes much simpler to work with a unified document representation than it would be to work with any of the input or output formats directly.</p>
<p>There are four main types in pandoc’s document model: inlines, blocks, document metadata, and the full document.</p>
<ul>
<li><p>Inline elements represent text and text markup. Examples are <em>Space</em> for inter-word spaces, <em>Str</em> for (usually non-whitespace) text, and <em>Emph</em> for emphasized text.</p></li>
<li><p>Blocks are elements like paragraphs, lists, code listings, and headers. They are usually rendered in lines or blocks of their own; many block elements contain lists of inline elements.</p></li>
<li><p>Meta information is a simple mapping from string keys to meta values. Meta values can be thought of as a special JSON or YAML object.</p></li>
<li><p>Last but not least, the <em>Pandoc</em> type represents a full document. A <em>Pandoc</em> element consists of a lists of block elements, plus additional document metadata.</p></li>
</ul>
<p>Pandoc’s Lua features revolve around modifying or converting these elements. The oldest use of Lua in pandoc enables the conversion of AST elements into strings as to output any document format.</p>
</section>
<section id="custom-writers" class="level2">
<h2 class="anchored" data-anchor-id="custom-writers">Custom writers</h2>
<p>Users can define custom writers in Lua to render any document format. Each of the aforementioned AST elements is transformed to a string by calling a Lua function of the same name as the element. E.g., this example demonstrates how emphasized text can be rendered as HTML:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> Emph<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content_string</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb2-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'&lt;em&gt;'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content_string</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">..</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'&lt;/em&gt;'</span></span>
<span id="cb2-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>A full custom writer is defined by specifying functions for all document AST elements. Example writers using this method include <a href="https://github.com/lilydjwg/2bbcode">2bbcode</a> by <a href="https://github.com/lilydjwg">@lilydjwg (依 云)</a>, as well as pandoc’s <code>sample.lua</code>. The latter is a well documented starting point for authors of new custom writers. The file can be produced by calling <code>pandoc --print-default-data-file=sample.lua</code>.</p>
<p>The <a href="https://pandoc-scholar.github.io/">pandoc-scholar</a> project serves as an example for the power offered by custom writers. It is a publishing tool intended to <a href="https://doi.org/10.7717/peerj-cs.112">help authors of scholarly articles</a> and was created with custom Lua writers. The tool leans on the custom writers feature in ways that writers were not intended to be used, which resulted in the development of lua filters.</p>
</section>
<section id="filters" class="level2">
<h2 class="anchored" data-anchor-id="filters">Filters</h2>
<p>An additional benefit of a unified document type is that the document can be modified programmatically, regardless of which input and output format is chosen. Pandoc provides two interfaces for this.</p>
<section id="json-filters" class="level3">
<h3 class="anchored" data-anchor-id="json-filters">JSON Filters</h3>
<p>The first – very flexible – method is based on JSON. Pandoc can serialize the document to JSON; other programs <a href="https://pandoc.org/filters.html">can read and modify</a> the document. The resulting document JSON is passed back to pandoc, thus allowing users to use any programming language capable of parsing JSON to alter the document. Many libraries for various languages have been implemented, including <a href="https://hackage.haskell.org/package/pandoc-types">Haskell</a>, <a href="http://scorreia.com/software/panflute/">Python</a>, <a href="https://heerdebeer.org/Software/markdown/paru/">Ruby</a>, and <a href="https://www.npmjs.com/package/pandoc-filter">JavaScript</a>.</p>
<p>The flexibility of JSON filters can also be a disadvantage, as it requires additional software and usually the full installation of a scripting language’s ecosystem. Pandoc is designed to work on all major platforms and without any dependencies on other libraries and binaries. Depending on additional software can be problematic, especially for non-technical users.</p>
</section>
<section id="lua-filters" class="level3">
<h3 class="anchored" data-anchor-id="lua-filters">Lua filters</h3>
<p>The <a href="https://pandoc.org/lua-filters.html">Lua filter</a> system added in pandoc 2.0 not only solves the portability issue of JSON filters, but also offers better performance and more functionality. Document elements can be selectively serialized to Lua tables, modified using the full power of Lua, and will then be transferred back, thus replacing the previous values.</p>
<p>Lua filters operate by calling filter functions on each element of the specified name. I.e., if a Lua filter contains a function with the same name as an AST element, then this function is called for all elements of the respective type. The serialized element is passed as input to the filter function, and the function’s return value is deserialized and used to replace the input element. This method is as simple as it is flexible, and fits well with the concept of immutability which is prevalent in Haskell programs: pandoc ignores modifications to the serialized object itself, it will just use the filter function’s return value.</p>
<p>The following example filter transforms all text set in small caps into emphasized text:</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> SmallCaps <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">element</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb3-2">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Emph<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">element</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">content</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb3-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>The element constructor functions in module pandoc, like <code>pandoc.Emph</code> in the above example, are also the central step when transforming elements from their pandoc-internal representation to Lua values. This ensures consistency in the way element values are produced, whether during serialization or through a constructor call in the filter script. The current implementation uses only strings, tables, and some metatables when constructing element values, with the goal of marking these values easy and flexible to use.</p>
</section>
</section>
<section id="lua-filter-example-macro-expander" class="level2">
<h2 class="anchored" data-anchor-id="lua-filter-example-macro-expander">Lua filter example: macro expander</h2>
<p>Below is the code for a simple macro expander using pandoc’s Lua filter functionality. The expander replaces all macro occurrences in the given document. Macro definitions are hard-coded into the filter, but could as well be read from an external file.</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- file: macro-expander.lua</span></span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Macro substitutions: contains macro identifier as</span></span>
<span id="cb4-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- keys and the expanded inlines as values.</span></span>
<span id="cb4-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">macro_substs</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-6">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{{hello}}'</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Emph<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">pandoc</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span>Str <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Hello, World!"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-7"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb4-8"></span>
<span id="cb4-9"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- Replace string with macro expansion, if any.</span></span>
<span id="cb4-10"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> Str <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-11">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">macro_substs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">or</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span></span>
<span id="cb4-12"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>The heart of the macro expander is the function <code>Str</code>. It is called on all simple strings in the document. The return value of this function is then read back into pandoc, replacing the original <code>Str</code> value.</p>
<p>Assume a Markdown file <code>greeting.md</code>:</p>
<pre><code>Greeting: {{hello}}</code></pre>
<p>We can apply the macro expander by calling</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pandoc</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--lua-filter</span> macro-expander.lua greeting.md</span></code></pre></div>
<p>resulting in the expected expansion:</p>
<blockquote class="blockquote">
<p>
Greeting: <em>Hello, World!</em>
</p>
</blockquote>
<p>The function <code>Str</code> could be shortened further by dropping the trailing <code>or s</code>:</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode lua code-with-copy"><code class="sourceCode lua"><span id="cb7-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span> Str <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">return</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">macro_substs</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">[</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">s</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">text</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">]</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">end</span></span></code></pre></div>
<p>This is a convenience feature of pandoc filters: if the function returns no value (or <code>nil</code>), the original value is kept unchanged. This makes filter functions easier to write and speeds up filtering, as unchanged elements don’t need to be deserialized again.</p>
</section>
<section id="whats-good-and-whats-next" class="level2">
<h2 class="anchored" data-anchor-id="whats-good-and-whats-next">What’s good, and what’s next</h2>
<p>Using pandoc with Lua is a fast, flexible, and platform independent way of augmenting pandoc with additional functionality. For me personally, having the full power of Lua at ones finger tips proved to be a lot of fun, while opening unexpected document processing possibilities.</p>
<p>Pandoc and its Lua subsystem are under constant development. E.g., the next versions will feature more utility functions exposed via Lua modules. There is constant work to make more and more internal functions available. The next big goal is to grant scripting access to all format-output functions. However, this requires some changes to pandoc’s internals. It remains a long way for pandoc to become a fully Lua-scriptable publishing platform.</p>
<p>If you want to learn more about Lua filters, the <a href="https://pandoc.org/lua-filters.html">Lua filter docs</a> is a good place to start. It includes up-to-date examples of Lua scripts, as well as a reference of all modules and functions accessible via Lua. Pandoc’s <a href="https://pandoc.org/MANUAL.html">user manual</a> is a good resource to learn about all of pandoc features and its command line options.</p>
<p><a href="https://groups.google.com/forum/#!forum/pandoc-discuss">Feedback</a> is always welcome!</p>
</section>
<section id="acknowledgements" class="level2">
<h2 class="anchored" data-anchor-id="acknowledgements">Acknowledgements</h2>
<p>A big thank you to Jennifer König, Birgit Pohl, and John MacFarlane for their feedback on an earlier version of this post, and to all pandoc contributors and users, who make working on this project incredibly fun.</p>


</section>

 ]]></description>
  <category>pandoc</category>
  <category>lua</category>
  <category>pandoc-filter</category>
  <guid>https://tarleb.com/posts/extending-pandoc-with-lua/</guid>
  <pubDate>Sat, 23 Dec 2017 00:00:00 GMT</pubDate>
</item>
<item>
  <title>MetaNook2014 – Command Line Talk</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/nook-2014/</link>
  <description><![CDATA[ 




<p>Last night was the night of this year’s MetaNook. It was the fourth time that the local hackers, most notably <a href="https://metameute.de">MetaMeute</a> and <a href="https://chaotikum.org">Chaotikum</a>, joined forces to organize a night full of beginner-friendly introductions, advanced tech talks, and project presentations.</p>
<p>My <a href="https://github.com/tarleb/shell-talk">talk contribution</a> this year was a brief introduction in the “magic” of the command-line. The talk slides are adapted to the topic in that the presentation must be given from the command line. Each slide is just a function, the whole presentation environment is held together by scripts and other shell-equivalences of duckt-tape. Feedback from the thirty or-so attendees was mostly positive.</p>
<p>It was a very fun experience over all, as usual.</p>



 ]]></description>
  <category>talk</category>
  <category>command-line</category>
  <guid>https://tarleb.com/posts/nook-2014/</guid>
  <pubDate>Sat, 22 Nov 2014 00:00:00 GMT</pubDate>
</item>
<item>
  <title>rt6_redirect: source isn’t a valid nexthop for redirect target</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/rt6_redirect/</link>
  <description><![CDATA[ 




<p>The zeitkraut server is configured to work with IPv6. For quite some time now, I’ve been seeing some strange errors in my log files. If you’ve been noticing something similar, here is what’s going on and how to prevent the messages from appearing.</p>
<section id="the-problem" class="level2">
<h2 class="anchored" data-anchor-id="the-problem">The Problem</h2>
<p>Everything works as expected, except for some weird messages in the logs:</p>
<pre><code>rt6_redirect: source isn't a valid nexthop for redirect target</code></pre>
<p>Not even <a href="https://startpage.com">startpage</a> was of much help. Searching for the above line only lists only some <a href="http://ubuntuforums.org/archive/index.php/t-1947743.html">unanswered</a> <a href="http://board.gulli.com/thread/1699675-rt6-redirect-source-isn-t-a-valid-nexthop/">forum</a> questions and the kernel source code which is producing the message. Oh, and a somewhat unhelpful blog entry <a href="https://www.kernel-error.de/kernel-error-blog/189-rt6-redirect-source-isn-t-a-valid-nexthop-for-redirect-target">telling</a> people to always use their routers link local address when routing. This is useless advice in my case, I don’t <em>have</em> a link-local address of the router, only it’s global address.</p>
</section>
<section id="the-cause" class="level2">
<h2 class="anchored" data-anchor-id="the-cause">The Cause</h2>
<p>I found a way to stop the message from appearing in my logs. On the way, I learned a bit more about IPv6 and improved server security on the way.</p>
<p>IPv6 contains functionality to tell a computer about better routes to the target destination. A router may send ICMPv6 redirect packages (type 137 to be specific), informing neighboring computers about more effective ways to reach their targets. This makes the most sense when applied within an environment heavily relying on auto-configuration – like a dynamic internal company or home network. It makes a lot less sense for servers very stable network topologies.</p>
<p>Attackers may try to exploit the redirect functionality by including themselves into the route to the target. The specification for those redirects includes some security-measures, requiring the attacker to correctly guess the server’s current next hop. If the attackers get it wrong, the Linux kernel refuses to use the new routing information. This is most-likely what happens when you see the above log messages.</p>
</section>
<section id="the-solution" class="level2">
<h2 class="anchored" data-anchor-id="the-solution">The Solution</h2>
<p>Long talk short, the solution is to disable IPv6 redirecting:</p>
<pre><code>sudo sysctl net.ipv6.conf.all.accept_redirects=0</code></pre>
<p>My server is not a router, so there is no need to accept any kind of route changing messages from external sources. We can simply disable redirects, using above command. The change can be made permanent by setting the value in <code>/etc/sysctl.conf</code>. In fact, we can disable routing for both IPv4 and IPv6. Be careful though, you might happen to be in a network environment requiring you to accept redirect commands for some reason.</p>
<p>If you are on Debian or similar distribution like Ubuntu, change the following lines in <code>/etc/sysctl.conf</code> from</p>
<pre><code># Do not accept ICMP redirects (prevent MITM attacks)
#net.ipv4.conf.all.accept_redirects = 0
#net.ipv6.conf.all.accept_redirects = 0
# _or_
# Accept ICMP redirects only for gateways listed in our default
# gateway list (enabled by default)
# net.ipv4.conf.all.secure_redirects = 1
#
# Do not send ICMP redirects (we are not a router)
#net.ipv4.conf.all.send_redirects = 0
#
# Do not accept IP source route packets (we are not a router)
#net.ipv4.conf.all.accept_source_route = 0
#net.ipv6.conf.all.accept_source_route = 0</code></pre>
<p>to</p>
<pre><code># Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
#
# Do not send ICMP redirects (we are not a router)
net.ipv4.conf.all.send_redirects = 0
#
# Do not accept IP source route packets (we are not a router)
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0</code></pre>
<p>Running <code>sudo sysctl -p</code> loads the new settings.</p>
</section>
<section id="alternative-solution" class="level2">
<h2 class="anchored" data-anchor-id="alternative-solution">Alternative Solution</h2>
<p>Completely disabling redirects in the kernel should keep you reasonably secure. However, if you need redirects within your internal network, you could also block redirect packages reaching you through external interfaces. E.g., to block redirect packages coming in on eth1, one would issue</p>
<pre><code>sudo ip6tables -A -i eth1 -p icmpv6 --icmpv6-type 137 -j DROP</code></pre>
<p>However, firewall configuration is a complex topic, so I’m not going to go into details here.</p>
<p>If you have any questions, corrections or comments on the matter, please drop me a line.</p>


</section>

 ]]></description>
  <category>security</category>
  <category>sysadmin</category>
  <guid>https://tarleb.com/posts/rt6_redirect/</guid>
  <pubDate>Fri, 01 Aug 2014 00:00:00 GMT</pubDate>
</item>
<item>
  <title>How to configure zsh with vi bindings and nice shortcuts</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/howto-zsh-vi-style/</link>
  <description><![CDATA[ 




<p>Having a good working environment is vital for feeling comfortable being productive. This extends to computational tools and the <a href="https://en.wikipedia.org/wiki/command%20shell">command shell</a> is an integral part of the daily work for many of us. It’s a good idea to configure the shell’s interface to be efficient and pleasant to use. Here we see how <code class="verbatim">zsh</code>, arguably the best shell around, can be configured to suit the needs of people used to vi key bindings (which are arguably arguably superior and more ergonomical than the default emacs-style bindings)<sup>1</sup>.</p>
<section id="using-vi-bindings-in-the-shell" class="level2">
<h2 class="anchored" data-anchor-id="using-vi-bindings-in-the-shell">Using vi-bindings in the shell</h2>
<p>The first step towards nice vi key bindings is almost too easy: The red pill takes the form of</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-v</span></span></code></pre></div>
<p>Type it into your prompt (and add it to your <code class="verbatim">.zshrc</code> file) and emacs bindings are going bye-bye. <code class="verbatim">Escape</code> will bring you to normal-mode, while <code>i</code>, <code>a</code>, <code>o</code> etc. will bring you back to insert-mode, just as with your favorite editor. Use <code>j</code> and <code>k</code> in normal-mode to go through your history and move around within the line with <code>h</code>, <code>l</code>, <code>w</code>, <code>b</code> and the like.</p>
<p>This is a good start, let’s see how we can bring it from “this is nice” to “that’s just awesome”.</p>
<p>First, we may want to keep some of the default key bindings in insert-mode since we’ve grown accustomed to them. No missing out, let’s put them back in:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Kill input from the current point to the end of line with Ctrl-k</span></span>
<span id="cb2-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'^k'</span> kill-line</span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Search the history incremantally with Ctrl-r</span></span>
<span id="cb2-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'^r'</span> history-incremental-search-backward</span>
<span id="cb2-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Insert and go through the "last words" of previous commands with Meta-.</span></span>
<span id="cb2-6"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># (or Escape-. for that matter).</span></span>
<span id="cb2-7"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'^[.'</span> insert-last-word</span>
<span id="cb2-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Show the man-page or other helpful infos with Meta-h</span></span>
<span id="cb2-9"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'^[h'</span> run-help</span></code></pre></div>
<p>You can take a look at the key bindings defined for emacs-mode by typing <code>bindkey -M emacs -L</code> and reuse the bindings you like. See the <code>zshzle</code> manpage for more pre-defined widgets for which you could define bindings.</p>
</section>
<section id="configuring-the-prompt-to-show-the-current-editing-mode" class="level2">
<h2 class="anchored" data-anchor-id="configuring-the-prompt-to-show-the-current-editing-mode">Configuring the prompt to show the current editing mode</h2>
<p>So the key bindings are quite usable now, but it’s a bit unfortunate that it is impossible to see if the shell is in insert- or normal-mode. There should be a mode indicator right in the shell prompt!</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># You may already have those in your .zshrc somewhere</span></span>
<span id="cb3-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">autoload</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-U</span> promptinit <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">promptinit</span></span>
<span id="cb3-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">autoload</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-U</span> colors     <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">&amp;&amp;</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">colors</span></span>
<span id="cb3-4"></span>
<span id="cb3-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">setopt</span> prompt_subst</span>
<span id="cb3-6"></span>
<span id="cb3-7"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Set the colors to your liking</span></span>
<span id="cb3-8"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vi_normal_marker</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[%{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$fg</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">[green]%}%BN%b%{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$reset_color</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">%}]"</span></span>
<span id="cb3-9"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vi_insert_marker</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[%{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$fg</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">[cyan]%}%BI%b%{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$reset_color</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">%}]"</span></span>
<span id="cb3-10"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vi_unknown_marker</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"[%{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$fg</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">[red]%}%BU%b%{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$reset_color</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">%}]"</span></span>
<span id="cb3-11"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vi_mode</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$vi_insert_marker</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb3-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">vi_mode_indicator ()</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-13">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">case</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${KEYMAP}</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">in</span></span>
<span id="cb3-14">    <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">(</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">vicmd</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">)</span>      <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$vi_normal_marker</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">;;</span></span>
<span id="cb3-15">    <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">(</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">main</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">|</span><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">viins</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">)</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$vi_insert_marker</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">;;</span></span>
<span id="cb3-16">    <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">(</span><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">*</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">)</span>          <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$vi_unknown_marker</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">;;</span></span>
<span id="cb3-17">  <span class="cf" style="color: #003B4F;
background-color: null;
font-style: inherit;">esac</span></span>
<span id="cb3-18"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-19"></span>
<span id="cb3-20"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Reset mode-marker and prompt whenever the keymap changes</span></span>
<span id="cb3-21"><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;"> zle-line-init</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">zle-keymap-select</span> {</span>
<span id="cb3-22">  <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">vi_mode</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$(</span><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">vi_mode_indicator</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">)</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb3-23">  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">zle</span> reset-prompt</span>
<span id="cb3-24"><span class="er" style="color: #AD0000;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb3-25"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">zle</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-N</span> zle-line-init</span>
<span id="cb3-26"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">zle</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-N</span> zle-keymap-select</span>
<span id="cb3-27"></span>
<span id="cb3-28"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Multiline-prompts don't quite work with reset-prompt; we work around this by</span></span>
<span id="cb3-29"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># printing the first line(s) via a precmd which is executed before the prompt</span></span>
<span id="cb3-30"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># is printed.  The following can be integrated into PROMPT for single-line</span></span>
<span id="cb3-31"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># prompts.</span></span>
<span id="cb3-32"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">#</span></span>
<span id="cb3-33"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Colorize freely</span></span>
<span id="cb3-34"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">user_host</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'%B%n%b@%m'</span></span>
<span id="cb3-35"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">current_dir</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'%~'</span></span>
<span id="cb3-36"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">precmd ()</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">print</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-rP</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${user_host}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;"> </span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${current_dir}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb3-37"></span>
<span id="cb3-38"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">local</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">return_code</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"%(?..%{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$fg</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">[red]%}%? %{</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$reset_color</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">%})"</span></span>
<span id="cb3-39"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">PROMPT</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'${return_code}${vi_mode} %# '</span></span></code></pre></div>
<p>This gives a prompt in the style of</p>
<pre><code>user@host /current/working/path
[I] %</code></pre>
<p>where <code>[I]</code> is the insert-mode indicator and is changed to <code>[N]</code> when normal-mode is activated. Neat, isn’t it?</p>
</section>
<section id="single--and-multi-key-shortcuts" class="level2">
<h2 class="anchored" data-anchor-id="single--and-multi-key-shortcuts">Single- and multi-key shortcuts</h2>
<p>This is all nice and dandy, but it’s not quite like vim yet. How about those sweet bindings where pressing <code>jj</code> in quick succession brings us to normal-mode without having to press <code>Esc</code>? Setting it up is easy as pie.</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Time in which two keys have to be pressed in order to be recognized as a</span></span>
<span id="cb5-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># single command (in centiseconds, set to 0.4 sec by default -- may be</span></span>
<span id="cb5-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># modified as needed).</span></span>
<span id="cb5-4"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">export</span> <span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">KEYTIMEOUT</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>40</span>
<span id="cb5-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'jj'</span> vi-cmd-mode</span></code></pre></div>
<p>We can also add two-key bindings to jump to the start and end of the line:</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Bind to both possible orders in which the keys could be pressed.</span></span>
<span id="cb6-2"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Move all the way to the left</span></span>
<span id="cb6-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">';l'</span> end-of-line</span>
<span id="cb6-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'l;'</span> end-of-line</span>
<span id="cb6-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Move all the way to the right</span></span>
<span id="cb6-6"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">';h'</span> beginning-of-line</span>
<span id="cb6-7"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">bindkey</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'h;'</span> beginning-of-line</span></code></pre></div>
<p>Jumping to the beginning of the line is now as easy as pressing <code>;</code> and <code>h</code> at the same time. No need to switch to normal-mode and your fingers don’t leave the your keyboard’s home-row. Try it, it’s great!</p>
</section>
<section id="more" class="level2">
<h2 class="anchored" data-anchor-id="more">More</h2>
<p>Customizations like this can make it much more pleasant to use the command line and boost your productivity. If the above is still not enough, here are some more ideas:</p>
<ul>
<li>Define custom keymaps, e.g.&nbsp;to control other programs such as <code>mpc</code> or <code>tmux</code>.</li>
<li>Switch to said keymaps via some nice bindings.</li>
<li>Show the status of version control systems and build environments in the prompt.</li>
</ul>
<p>If you don’t feel like doing all the work yourself, I can heartly reommend you take a look at <a href="http://ohmyz.sh">oh-my-zsh</a>. It offers a great collection of ideas to build on and some really cool ready-to-use plugins. Have fun!</p>


</section>


<div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Footnotes</h2>

<ol>
<li id="fn1"><p>Emacs is a great program which I’ve been using for years and continue to use daily, but vi bindings just make good things better. Thanks to <a href="https://gitorious.org/evil/pages/Home">evil</a>, that’s not a problem.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>command-line</category>
  <category>key bindings</category>
  <guid>https://tarleb.com/posts/howto-zsh-vi-style/</guid>
  <pubDate>Sun, 29 Jun 2014 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Exploring HTTP Headers with netcat</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/exploring-http-headers/</link>
  <description><![CDATA[ 




<p>One of the many great things about free and open source software and the whole GNU/Linux ecosystem are the simple yet powerful tools available. The possibilities enabled by almost trivial programs are incredible. A very positive side effect this has on me is that I like to go and explore technologies with the tools at my disposal. My latest experiments revolved around the HTTP protocol, specifically HTTP headers, and very basic open source networking tools.</p>
<section id="the-hypertext-transfer-protocol" class="level2">
<h2 class="anchored" data-anchor-id="the-hypertext-transfer-protocol">The HyperText Transfer Protocol</h2>
<p>Webservers on the internet sending a website to a browser use the HyperText Transfer Protocol (HTTP) to do so. Along with the HTML data for the page itself, the server answer includes additional information: Response code, cookies, and how the browser or proxy server should handle the contents is transfered within the <em>HTTP header</em>. The ability of the headers to control state on the client side is what makes them so interesting and the reason why we are going to have a closer look at them.</p>
</section>
<section id="communicating-with-netcat" class="level2">
<h2 class="anchored" data-anchor-id="communicating-with-netcat">Communicating with <code>netcat</code></h2>
<p>Instead of building our own HTTP client and server implementations – that would be total overkill – we restrict the goal to a simple networking tool that can be made to receive, send and alter basic HTTP commands: <code>netcat</code>, the self-described TCP/IP swiss army knife, combined with basic shell scripts.</p>
<p>We start by setting up a basic echoing server which sends everything back the same way it was received.</p>
<pre class="shell"><code>nc -l -p 8042 -e '/bin/cat'</code></pre>
<p>Pointing the browser at <code>http://localhost:8042</code>, then killing the <code>netcat</code> process manually by hitting <code>Control-C</code>, we can see the headers we sent within our browser. Everything that is send to our simple server is put through the <code>cat</code> program, which just passes it on to STDOUT, which is then sent back to the connecting browser. The process has to be terminated manually, as it doesn’t know when to stop listening for more input. It’s crude, yet effective.</p>
</section>
<section id="shell-scripting-for-more-advanced-features" class="level2">
<h2 class="anchored" data-anchor-id="shell-scripting-for-more-advanced-features">Shell Scripting for more advanced features</h2>
<p>The above is neither comfortable to use nor very good to toy with, so we replace <code>cat</code> with a script of our own, we’ll call it <code>exploring-http.sh</code>:</p>
<pre class="shell"><code>#!/bin/sh

# Keep reading everything until we hit the first empty line
read_headers ()
{
    read i
    while [ -n "$i" ] &amp;&amp;
          [ "$(echo -n "\r\n")" != "$i" ] &amp;&amp;
          [ "$(echo -n "\n")" != "$i" ]
    do
        echo "$i"
        read i
    done
}
request_headers="$(read_headers)"

# Get some response headers ready
response_headers ()
{
    printf "HTTP/1.1 200 OK\r\n"
    printf "Content-Type: text/plain\r\n"
    printf "\r\n"
}

# Send the response
respond ()
{
    local response_headers="$(response_headers)"
    echo "${response_headers}"
    echo "Browser Request Headers"
    echo "======================="
    echo "$request_headers"
    echo "\r\n"
    echo "Server Response Headers"
    echo "======================="
    echo "${response_headers}"
}

respond</code></pre>
<p>The request send by the browser is read till we reach the first black line, signaling the end of the request header. This time, we follow the protocol by prefixing the content with very simple response headers before sending it back to the browser. We also don’t have to manually terminate our <code>netcat</code> server, it terminates after answering to the request. Starting it again after each request is tedious, so we automate it and put it into a loop, restarting the server immediately once it terminates.</p>
<pre class="shell"><code>sh -c 'while true; do nc -l -p 8042 -e exploring-http.sh; done'</code></pre>
<p>Now we are free to experiment with HTTP headers and the way browser and server interact. For example, we can let the server add a <code>Last-Modified</code> header, the content of which should be sent back by the browser in the next request:</p>
<pre class="shell"><code>response_headers ()
{
    printf "HTTP/1.1 200 OK\r\n"
    printf "Content-Type: text/plain\r\n"
    printf "Last-Modified: $(date --rfc-2822)\r\n"
    printf "\r\n"
}</code></pre>
<p>Reloading twice, and the browser request will change to send an additional <code>If-Modified-Since</code> header.</p>
</section>
<section id="etags" class="level2">
<h2 class="anchored" data-anchor-id="etags">ETags</h2>
<p>The functionality of ETags, designed to communicate caching of old files, can be used follow users around without the need of cookies. Let’s see if we can do this with our little server.</p>
<p>The function generating the response headers is modified to extract any ETag supplied by the browser. If none exists, we generate a new one by hashing the number of nanoseconds passed since the beginning of the UNIX epoche. The parsed or newly generated etag is then sent back to the browser. We also add a few header to make sure the conents isn’t cached. As a result, we should be able to track a user through his or her browser cache.</p>
<pre class="shell"><code>response_headers ()
{
    local etag
    etag=$(echo "${request_headers}" | sed -ne 's/^\(If-None-Match: "\([a-f0-9]*\)".*\)/\2/gp')
    printf "HTTP/1.1 200 OK\r\n"
    printf "Content-Type: text/plain\r\n"
    printf "Last-Modified: $(date --rfc-2822)\r\n"
    printf "ETag: \"${etag:-$(date +%s%N | md5sum | cut -d' ' -f1)}\"\r\n"
    printf "Expires: Tue, 01 Jan 2013 00:00:01 GMT\r\n"
    printf "Cache-Control: max-age=0\r\n"
    printf "Connection: keep-alive\r\n"
    printf "\r\n"
}</code></pre>
<p>We can test this by reloading our test page twice and… it works! We can reload as often as we want, the ETag header sent by the browser will not change unless we clear the browser’s cache. A stealthy kind of user tracking can be simulated with just a few lines of shell script.</p>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>Even though we used nothing but simple command line tools and shell scripting, we managed to build a simple server and to experiment with the ways in which stateless servers and stateful browseres can effect each other through HTTP headers. Standard UNIX tools are very powerful by themselves; together with a tool like <code>netcat</code>, power and fun extend even into experiments with networking and default protocols.</p>


</section>

 ]]></description>
  <category>command-line</category>
  <category>network</category>
  <guid>https://tarleb.com/posts/exploring-http-headers/</guid>
  <pubDate>Tue, 05 Nov 2013 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Russian Process Roulette</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/russian-process-roulette/</link>
  <description><![CDATA[ 




<p>A couple of friends and I just discussed the idea of Russian Process Roulette: Everybody starts a little program which kills processes at random. The winner is the one whose computer remains usable the longest. Is this crazy? Yes. Immature? Sure. Fun? Definitely. Adviced against to actually play unless the consequences are fully understood? That too.</p>
<p>Playing the game is as simple as starting a command like the following:</p>
<pre class="shell"><code>while sleep 600; do kill -9 $(tr -cd "[:digit:]" &lt; /dev/urandom | head -c5); done</code></pre>
<p>This one-liner will wake up every 10 minutes, generate a random 5-digit number and then kill the process with the corresponding process ID. It will run forever, until it is either stopped, kills itself or has successfully crashed the user’s session.</p>
<p>Of course, there are some problems with this code. The time at which the next process will be killed is predictable, making it easier to prepare for the eventuality of a dying process. Worse, the range of random process ids (0 to 99999) is about three times as large as the actual range of process ids on a typical linux system (0 to 32768). This lowers the chance of hitting a valid process ID quite a bit. So let’s put our scripting-fu to some misguided use and “optimize” the code.</p>
<p>The first step is to write a function which gives uniformly distributed random numbers below a threshold.</p>
<pre class="shell"><code>random_number_below () {
  local upperbound=$1
  local candidate=$(( $1 + 1 ))
  local maxlen=$(printf $upperbound | wc -c)
  while [ $candidate -gt $upperbound ]
  do
      candidate=$(tr -cd '[:digit:]' &lt; /dev/urandom | head -c "$maxlen" )
  done
  echo $candidate
}</code></pre>
<p>Our random number generator is very very wasteful in terms of processor cycles. Even more, if the output of <code>/dev/urandom</code> is truly random, the function were not even guaranteed to terminate in any specified time frame. But given the nature of the application we have in mind, both caveats are completely acceptable here. Candidate numbers are generated by reading random characters from the systems urandom device, throwing away every character that isn’t a digit. After this, the candidate number is checked to make sure we haven’t generated a number greater than the specified upper bound. If that should be the case, we run the whole procedure again. Otherwise, the random number is returned. While wasteful, this function produces an unbiased uniform distribution on the interval [0, upperbound].</p>
<p>The second problem, regarding the range of possible process identifiers, is easier to fix. A little bit of searching reveals that the largest possible process identifier can be read from the file <code>/proc/sys/kernel/pid_max</code>. With this functionality in our hands, we can now write a “better” Russian Process Roulette script.</p>
<pre class="shell"><code>while sleep $(random_number_below 999)
do
    local maxpid=$(cat /proc/sys/kernel/pid_max)
    kill -9 $(random_number_below "$maxpid")
done</code></pre>
<p>We should (<em>probably not</em>) run this as <code>root</code>, thereby making sure no process is safe from our “process gun”.</p>
<p>While the result of our efforts isn’t necessarily useful, it is still a nice exercises in shell scripting. Our game remains destructive and immature, but the execution is slightly more sophisticated. Hope you like it.</p>



 ]]></description>
  <category>command-line</category>
  <category>nonsense</category>
  <guid>https://tarleb.com/posts/russian-process-roulette/</guid>
  <pubDate>Fri, 27 Sep 2013 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Avoid Mail Harvesting through Address Munging</title>
  <dc:creator>Albert Krewinkel</dc:creator>
  <link>https://tarleb.com/posts/avoiding-spam/</link>
  <description><![CDATA[ 




<p>Spam just doesn’t die. Every major mail provider has really good spam filters in place, as do the common mail clients. Nontheless, there seem to be enough people reading – and acting on – spam mail to make it a profitable business. No matter how much we hate it, we need to deal with spam.</p>
<p>Better than having a good spam filter is not to be spammed in the first place. Since nobody can sent me unsolicited bulk mail if they don’t know my mail address, keeping the mail address as private as possible is the way to go here. But what if we <em>want</em> our e-mail address to be public for other people to reach us? Adding minor obstacles to make it just a bit more difficult for spammers to get the address can be enough.</p>
<section id="address-munging" class="level2">
<h2 class="anchored" data-anchor-id="address-munging">Address Munging</h2>
<p>The usual way for spammers to collect email addresses is to crawl websites and to harvest everything that looks like a valid mail address. A common defense is <a href="https://en.wikipedia.org/wiki/Address_munging">address munging</a>, i.e.&nbsp;resolving to bogus comments, additional markup, images or javascript to hide mail addresses from automatic harvesters. I find the use of images or javascript problematic for various reasons and just dislike unnecessary comments. Luckily, HTML5 and CSS3 make it really easy to mangle addresses without using either of these methods.</p>
</section>
<section id="obfuscating-an-address-with-html5-css3" class="level2">
<h2 class="anchored" data-anchor-id="obfuscating-an-address-with-html5-css3">Obfuscating an Address with HTML5 &amp; CSS3</h2>
<p>Our approach here leverages the HTML5 <a href="http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes"><code>data-*</code></a> attributes as well as the <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::before"><code>::before</code></a> and <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/::after"><code>::after</code></a> pseudo-elements. The mail address is divided and stored in custom data attributes and displayed as pseudo-elements. The address is kept in the markup, the presentation is handled in the style sheet:</p>
<p>HTML:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode html code-with-copy"><code class="sourceCode html"><span id="cb1-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">span</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> data-user</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"john.doe"</span></span>
<span id="cb1-2"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">      data-domain</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"example.com"</span></span>
<span id="cb1-3"><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">      class</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"obfuscated-mail-address"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;!--</span></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">--&gt;</span>@<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">span</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span>obfuscated email address<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">span</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">span</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span></code></pre></div>
<p>CSS:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode css code-with-copy"><code class="sourceCode css"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.obfuscated-mail-address</span><span class="in" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::before</span> {</span>
<span id="cb2-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">content</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">data-user</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-3">}</span>
<span id="cb2-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.obfuscated-mail-address</span><span class="in" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">::after</span> {</span>
<span id="cb2-5">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">content</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">data-domain</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">)</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-6">}</span>
<span id="cb2-7"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">.obfuscated-email-address</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> {</span>
<span id="cb2-8">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">display</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">none</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb2-9">}</span></code></pre></div>
<p>The result is readable, but can be neither selected nor copied:</p>
<p><span class="obfuscated-mail-address dont-touch" data-user="john.doe" data-domain="example.com"><!--
--><span>obfuscated email address</span></span></p>
<p>The nested <code>&lt;span&gt;</code> and its styling could be omitted, without changing the presentation in most browsers. We use it to ensures that everything fails gracefully in browsers with limited CSS support. To see why this matters, have a look at this page in a text browser like <em>w3m</em> or <em>links</em>.</p>
</section>
<section id="drawbacks" class="level2">
<h2 class="anchored" data-anchor-id="drawbacks">Drawbacks</h2>
<p>The biggest advantage of this method is also it’s biggest disadvantage: The semantics are broken. The classic markup-code</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode html code-with-copy"><code class="sourceCode html"><span id="cb3-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">a</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;"> href</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"mailto:me@example.com"</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span>John Doe<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&lt;/</span><span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">a</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">&gt;</span></span></code></pre></div>
<p>is rendered as <a href="mailto:me@example.com">John Doe</a> and makes it very clear, to machines and humans alike, that <em>John Doe</em> can be reached at <em>me@example.com</em>. Address munging, like the above, preserves this meaning for humans, but takes it away for machines. For better and for worse, browsers, search engines, and spam bots will not be aware of the meaning of the obfuscated address.</p>
<p>These effects can be alleviated by resolving to additional javascript:</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb4-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// convert obfuscated mail addresses into clickable "mailto:" links</span></span>
<span id="cb4-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">jQuery</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"document"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">ready</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span>($) {</span>
<span id="cb4-3">  <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">var</span> mailAddressClass <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"obfuscated-mail-address"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-4">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">$</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"."</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span>mailAddressClass)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">each</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">function</span>() {</span>
<span id="cb4-5">    <span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">var</span> address <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">$</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">this</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data-user"</span>) <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"@"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">$</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">this</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">attr</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"data-domain"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-6">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">$</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">this</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">html</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">$</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"&lt;a href=</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">mailto:"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> address <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="sc" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">\"</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">&gt;"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> address <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">+</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"&lt;/a&gt;"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {}))<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-7">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">$</span>(<span class="kw" style="color: #003B4F;
background-color: null;
font-style: inherit;">this</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">removeClass</span>(mailAddressClass)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-8">  })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb4-9">})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
<p>The webpage is still usable with JavaScript turned off, and even fails gracefully on text-only browsers. If JavaScript is available, the obfuscated links offer the same experience as properly coded <code>&lt;a href="mailto:..."&gt;...&lt;/a&gt;</code> links: <span class="obfuscated-mail-address" data-user="john.doe" data-domain="example.com">@</span>. I believe this to be a very good trade-off between usability and safety from harvesters.</p>


</section>

 ]]></description>
  <category>html</category>
  <category>css</category>
  <category>javascript</category>
  <guid>https://tarleb.com/posts/avoiding-spam/</guid>
  <pubDate>Sun, 25 Aug 2013 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
