Blogging about Rust using Rust's Compiler Toolchain
Alexis Beingessner - May 23, 2015 - Rust 1.0.0
A while ago I had an annoying problem: I would like to write blog posts about Rust, but all I have at my disposal is a static file server that I can't modify on a system I have no priviledges on. I could post things on Github or like Mediumblr or something, but that didn't feel... right. I want to host my own words, damn it!
Now, I can definitely hand-write everything in html. At some limit, that's eveything I host. Still, I really like markdown. I'd also be writing a lot about code, which html is kinda janky at. I want to be lazy, damn it!
So like pandoc or something is probably a thing... I'd have to look that up... download stuff... install it... figure out how it works... nonono, all wrong! See the previous proclamation for details.
What I did know is that the Rust compiler has a nifty little too called rustdoc, for building documentation. It's most powerful feature is scraping an entire crate's source and building nice static html indexes. However more obscure is that you can just feed it markdown files, and it will spit out html. That's how TRPL is built. It comes with the rest of the compiler tools, so it's even already in my $PATH
. Sounds like what I want!
The only special thing it requires from your file is a title line prefixed by a %
. It works pretty ok on its own but the raw output is pretty... raw. No source highlighting. No CSS. On the other end of the spectrum, it produces this TOC that I really don't like. And spits the file out in a doc/
folder (which it would just crash on the absence of!).
Thankfully, rustdoc --help
is full of little goodies:
> rustdoc --help
/Users/ABeingessner/.multirust/toolchains/nightly/bin/rustdoc [options] <input>
Options:
-h --help show this help message
-V --version print rustdoc's version
-v --verbose use verbose output
-r --input-format [rust|json]
the input type of the specified file
-w --output-format [html|json]
the output type to write
-o --output PATH where to place the output
--crate-name NAME specify the name of this crate
-L --library-path DIR
directory to add to crate search path
--cfg pass a --cfg to rustc
--extern NAME=PATH pass an --extern to rustc
--plugin-path DIR directory to load plugins from
--passes PASSES list of passes to also run, you might want to pass it
multiple times; a value of `list` will print available
passes
--plugins PLUGINS space separated list of plugins to also load
--no-defaults don't run the default passes
--test run code examples as tests
--test-args ARGS arguments to pass to the test runner
--target TRIPLE target triple to document
--markdown-css FILES
CSS files to include via <link> in a rendered Markdown
file
--html-in-header FILES
files to include inline in the <head> section of a
rendered Markdown file or generated documentation
--html-before-content FILES
files to include inline between <body> and the content
of a rendered Markdown file or generated documentation
--html-after-content FILES
files to include inline between the content and
</body> of a rendered Markdown file or generated
documentation
--markdown-playground-url URL
URL to send code snippets to
--markdown-no-toc don't include table of contents
Right at the bottom is a direct answer to one of my problems: --markdown-no-toc
. For a bit I got by with the rest by just hand-editing the HTML. Paste in the CSS, add some extra html hooks for the CSS, etc. Unfortunately this was pretty brittle to editing the text!
Someone on the internet helpfully pointed out that my code was being marked up for code highlighting, I just didn't have the CSS for it. Having worked on rustdoc a bit myself, I knew roughly where that would have to be. A quick ctrl+f for code
brought up this:
/* Code highlighting */
pre.rust .kw { color: #8959A8; }
pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
pre.rust .number, pre.rust .string { color: #718C00; }
pre.rust .self, pre.rust .boolval, pre.rust .prelude-val,
pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
pre.rust .comment { color: #8E908C; }
pre.rust .doccomment { color: #4D4D4C; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
pre.rust .lifetime { color: #B76514; }
which I promptly stole.
I still was hand-editing some stuff into the file, though. After a couple posts I decided the time waste had reach a critical mass and paid a little more attention to the above flags. The three --html-*
flags give me exactly the places I was editing content into. Then I just tossed it all in a bash script so that I could forget how to do all of this forever:
#!/bin/bash
mkdir doc
rustdoc --markdown-no-toc --html-in-header ../rustblog/head.html --html-before-content ../rustblog/before.html --html-after-content ../rustblog/after.html "$1.md"
mv -f "doc/$1.html" ./
rm -rf doc
And thus rustblog
was born. Was it worth it? I don't even know. But heck, it works. Here's this post's text.