The Blogdown package

[Tags:agpl, library, program, test]

A library and executable that implement a modified, extended version of Markdown designed for writing blog posts.


[Skip to Readme]

Properties

Versions 0.1.0
Change log ChangeLog.md
Dependencies base (==4.9.*), containers (==0.5.*), MissingH (==1.4.*), parsec (==3.1.*) [details]
License AGPL-3
Copyright (c) 2017 Alex Becker
Author Alex Becker
Maintainer acbecker@uchicago.edu
Category Web
Source repository head: git clone https://github.com/alexbecker/blogdown
Uploaded Mon Apr 3 07:56:51 UTC 2017 by alexbecker
Distributions NixOS:0.1.0
Downloads 39 total (39 in the last 30 days)
Votes
0 []
Status Docs available [build log]
Last success reported on 2017-04-03 [all 1 reports]

Modules

[Index]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees

Readme for Blogdown

Readme for Blogdown-0.1.0

<p><i>Note: If you are viewing this Readme on GitHub, its Blogdown-specific features will not render correctly.
The Blogdown-formatted output is in Readme.html.</i></p>
<h1>Blogdown</h1>
<p>Blogdown is a markup language based on Markdown, designed for writing blog posts.
Blogdown's goals are:</p>
<ul><li>Clean syntax for common blog post features absent from Markdown.</li>
<li>Ability to handle untrusted input.</li>
<li>Simple syntax, with no surprises.</li>
<li>Debuggability.</li>
<li>Near compatibility with common Markdown implementations.</li>
</ul>
<p>Because there is no Markdown standard and existing Markdown implementations
<a href="http://johnmacfarlane.net/babelmark2/?text=Hello+world%0A*+this+is+a+list%0A%3E+this+is+a+quote">disagree wildly even on simple cases</a>,
Blogdown cannot be 100% compatible with even a majority of Markdown implementations.
While there have been attemps to create a common Markdown standard&mdash;most notably <a href="http://commonmark.org/">CommonMark</a>&mdash;they
are necessarily quite complex. The primary cause of this complexity is that Markdown insists on rendering <i>something</i> for every input,
no matter how malformed. Blogdown is considerably simpler, and hopefully easier for authors to debug, because it fails on malformed inputs.
With full compatability out of the window, I have chosen to make some other small improvements on Markdown syntax.</p>
<h2>Installation</h2>
<h3>With Cabal or Stack</h3>
<p>The recommended way to install any Haskell project is using <a href="https://www.haskell.org/cabal/">Cabal</a> or <a href="https://docs.haskellstack.org/en/stable/README/">Stack</a>.
With these tools, you can simply run <code>cabal install</code> or <code>stack build</code> respectively.</p>
<h3>Without Haskell Tooling</h3>
<p>Because configuring Cabal and Stack can be tricky for Haskell beginners, Blogdown supports installation without any Haskell tooling.</p>
<p>First, install <a href="https://www.haskell.org/ghc/">GHC</a>, <a href="https://hackage.haskell.org/package/parsec">Parsec</a> and <a href="https://hackage.haskell.org/package/MissingH">MissingH</a>,
all of which are available through common Linux package managers.
Then run <code>ghc -isrc -o Blogdown src/Blogdown.hs</code> in the repository's base directory.</p>
<h2>Usage</h2>
<p>The <code>Blogdown</code> binary reads from <code>stdin</code> and writes to <code>stdout</code>. Typical usage looks like:</p>
<pre><code>cat blogpost.md | ./Blogdown &gt; blogpost.html
</code></pre>
<h3>Optional Styling and Scripts</h3>
<p>It is recommended to include <code>footnotes.css</code> and <code>footnotes.js</code> on any pages which make use of Blogdown-generated footnotes,
which improve the appearance of footnotes and allow them to be shown inline.
These can be inlined using the <code>--inline-css</code> and <code>--inline-js</code> flags respectively<sup><a href="#-footnote-0" id="a--footnote-0">[0]</a></sup>.</p>
<h3>Optional Flags</h3>
<p><code>Blogdown</code> accepts the following long-style flags:</p>
<ul><li><code>--footnote-prefix</code>: Defines a prefix for the <code>id</code>s of footnotes. Recommended if multiple output files are included in a single HTML page, to avoid <code>id</code> collisions.</li>
<li><code>--footnote-index-from</code>: The index from which footnotes are numbered. Defaults to 0.</li>
<li><code>--footnote-backlinks</code>: If this flag is passed, footnotes will be preceded by a caret linking back to the point where the footnote is referenced.</li>
<li><code>--em-dashes</code>: If this flag is passed, <code>--</code> will be replaced with "&mdash;" in text.</li>
<li><code>--inline-css</code>: If this flag is passed, the recommended CSS will be inlined at the end of the output document.</li>
<li><code>--inline-js</code>: If this flag is passed, the recommended JS will be inlined at the end of the output document.</li>
</ul>
<h2>Syntax</h2>
<h3>Differences from Markdown</h3>
<p>Most of the syntax of Blogdown should be familiar to Markdown users, but some new syntax has been added, and some existing syntax has changed.</p>
<h4>New Features</h4>
<p>Blogdown adds footnote support to Markdown.
Footnotes can be referenced inline with ^[<i>footnote-name</i>], which will render as a superscript link to a <i>footnote-definition</i>
at the end of the document, which is defined by ~[<i>footnote-name</i>] followed by the footnote contents.</p>
<h4>Markdown Incompatibilities</h4>
<p>Blogdown does not support the Markdown syntax of underlining text with <code>=</code> or <code>-</code> characters to define a header,
as this comes at a large cost in the parser implementation<sup><a href="#-footnote-1" id="a--footnote-1">[1]</a></sup>.
The <code>#</code> syntax for headers is supported instead.</p>
<p>It also does not support using multiple trailing spaces to force a breakpoint at the end of a line.
The <code>&lt;br/&gt;</code> tag is supported instead.</p>
<p>The <code>~</code> and <code>^</code> characters are now special, and must be escaped to be used in text.
Additionally, while most Markdown implementations do not require escaping many special characters when their special meaning would
not be valid, Blogdown always requires they be escaped.</p>
<h3>Formal Description</h3>
<p>The body of a Blogdown document consists of a sequence of <i>block nodes</i>, which in turn consist of <i>inline nodes</i>.</p>
<h4>Block Nodes</h4>
<p>Block nodes can contain any sequence of inline nodes, with the exception of code and HTML blocks, whose contents are rendered verbatim.
Block nodes can span multiple lines and are terminated by a blank line, the beginning of another type of block, or the end of the document.</p>
<p>The following block node types are supported:</p>
<ul><li><b>Paragraph</b>: The default block type; any content not in another block is part of a paragraph.
Paragraphs must be separated by a blank line.
Can contain arbitrary inline nodes.</li>
<li><b>Header</b>: 1-6 <code>#</code> characters at the beginning of a line begins a header, with the number of <code>#</code> characters determining the header level.
Can contain arbitrary inline nodes.</li>
<li><b>Ordered Lists</b>: A <code> - </code> begins an ordered list item, which itself is a block.
Sequential ordered list items form an ordered list.
Can contain arbitrary inline nodes.</li>
<li><b>Unordered Lists</b>: A <code> * </code> begins an unordered list item, which itself is a block.
Sequential unordered list items form an unordered list.
Can contain arbitrary inline nodes.</li>
<li><b>Blockquote</b>: Lines beginning with <code>&gt; </code> define a blockquote.
Can contain arbitrary inline nodes.
Note that the first line not beginning with <code>&gt; </code> will start a new block.</li>
<li><b>Code Block</b>: Lines indented with 4+ spaces or a tab define a code block.
Code blocks are rendered verbatim, ignoring special characters.
Note that the first un-indented line will start a new block.</li>
<li><b>HTML Block</b>: An HTML tag at the beginning of a line starts an HTML block.
Its contents must be valid HTML, and it is ended by the corresponding closing tag.
HTML blocks are rendered verbatim, unless HTML bleaching is enabled.</li>
<li><b>Hard Rule</b>: A line consisting of 3+ <code>-</code> defines a hard rule.</li>
<li><b>Table</b>: A <code>|</code>character at the beginning of a line begins a table row, consisting of table cells separated by <code>|</code> characters.
The cells are themselves blocks, and as such can contain newlines. The rows are terminated by a <code>|</code> followed by a newline.
By default the table has only a body, but if rows are separated by an alternating string of <code>+</code> and multiple <code>-</code> characters,
e.g. <code>+---+---+</code>, then every row above the separator will be in the header and every row below will be in the body.
Optionally the table may start and end with such a separator as well.</li>
</ul>
<h4>Inline Nodes</h4>
<p>Inline nodes can generally contain a sequence of other inline nodes, but cannot contain nodes of the same type.
Despite the name, inline nodes can span multiple lines, e.g. to accomodate line length limits.</p>
<p>The following inline node types are supported:</p>
<ul><li><b>Plaintext</b>: The default inline type; any text not in another inline node is plaintext. Rendered verbatim.</li>
<li><b>Italic</b>: Surrounding text with <code>*</code> <i>italicizes</i> it. Italic nodes can contain any other type of inline node.</li>
<li><b>Bold</b>: Surrounding text with <code>**</code> <b>bolds</b> it. Bold nodes can contain any other type of inline node.</li>
<li><b>Code</b>: Surrounding text with <code>`</code> renders it as <code>code</code>. The content is rendered verbatim.</li>
<li><b>Link</b>: A <a href="#">link</a> is written as [<i>text</i>](<i>href</i>). The <i>text</i> portion can contain any other type of inline node.
The <i>href</i> portion is the link destination, and is parsed verbatim except that any literal <code>(</code> or <code>)</code> must be escaped.</li>
<li><b>Footnote Reference</b>: Writing ^[<i>footnote-name</i>] defines a footnote reference.
It is rendered as a superscript footnote number<sup><a href="#-footnote-2" id="a--footnote-2">[2]</a></sup>, and links to the footnote named <i>footnote-name</i>
if it is present in the footer.</li>
</ul>
<h4>Footer</h4>
<p>A Blogdown document may optionally include a footer after the body.
The footer consists of a sequence of <i>footnote definitions</i>, each of which begins on a new line with ~[<i>footnote-name</i>] and consists of an arbitrary sequence of blocks.
A footnote definition is only terminated by another footnote definition or the end of the document.</p>
<h3>Escaping</h3>
<p>Any character (special or not) can be escaped with <code>\</code>. For a literal backslash, use <code>\\</code>.
A backslash before a newline acts as a continuation character.</p>
<h2>Planned improvements</h2>
<ul><li>Nested lists</li>
<li>Better error messages on parse failures</li>
<li>Windows support</li>
<li>Better tests</li>
<li>Document building & running tests</li>
<li>Comments</li>
</ul>
<hr/>
<ol start="0" class="footnotes"><li id="-footnote-0"><p>Inlining CSS and JS is not recommended if you will be rendering multiple Blogdown documents on a single page, e.g. multiple blog posts on a blog.
Doing so will degrade network and browser performance slightly.</p></li>
<li id="-footnote-1"><p>Supporting underlines for headers requires the parser to look-ahead arbitrarily far, resulting in quadratic time complexity.</p></li>
<li id="-footnote-2"><p>Footnotes are auto-numbered in order of appearance, starting from 0 by default (this can be changed by passing the <code>--footnote-index-from</code> flag).</p></li>
</ol>
<style>.footnotes > li {
    margin: 15px 0;
}

/* Keeps the back-link on the same line as the first block. */
.footnotes > li > *:nth-child(2) {
    display: inline;
}

.inline-footnote {
    margin: .5em;
    padding: .5em;
    border-left: 2px solid #555;
}

.inline-footnote > p {
    margin: 0;
}
</style>
<script>function inlineFootnote(footnote) {
    var ref = document.getElementById("a-" + footnote.id);
    var inline = document.createElement("div");
    for (var i=0; i<footnote.children.length;) {
        var child = footnote.children[i];
        if (child.tagName == "A" && child.getAttribute("href") == "#" + ref.id) {
            i++;
            continue;
        }
        inline.appendChild(child);
    }
    inline.className = "inline-footnote";
    inline.style.display = "none";
    ref.parentNode.parentNode.insertBefore(inline, ref.parentNode.nextSibling);
    ref.origIndex = ref.textContent;
    ref.expanded = false;
    ref.addEventListener("click", function (e) {
        e.preventDefault();
        if (ref.expanded) {
            inline.style.display = "none";
            ref.textContent = ref.origIndex;
        } else {
            inline.style.display = "block";
            ref.textContent = "X";
        }
        ref.expanded = !ref.expanded;
    });
}

function inlineFootnotes() {
    var footnoteLists = document.getElementsByClassName("footnotes");
    while (footnoteLists.length > 0) {
        var footnotes = footnoteLists[0].children;
        for (var j=0; j<footnotes.length; j++) {
            inlineFootnote(footnotes[j]);
        }
        footnoteLists[0].remove();
    }
}

inlineFootnotes()
</script>