Scott Olson

Posts? On my blog?

It’s more likely than you think.

Today I set up my website for blogging. I’m using the nanoc static site generator, which I also use to render pages like my movies page with a bunch of gross Ruby code. To set up nanoc for blogging I mostly followed this guide. For the estimated reading time in my article subtitle, I was inspired by this post but I greatly simplified the code as follows:

def reading_time(text)
  words =  text.split.size
  wpm = 200.0
  mins = (words / wpm).ceil

  if mins == 1
    '~1 minute'
  else
    "~#{mins} minutes"
  end
end

Syntax highlighting

Speaking of code, setting up syntax highlighting was more work than I expected. I found out that kramdown only supports highlighting Rust code through Rouge, and Rouge’s Rust parser failed badly on the very first thing I tried. At the time of writing, the lifetimes were marked with CSS .err classes and highlighted in red. Lifetimes are everywhere in Rust!

Instead of attempting to fix Rouge, I found a way to switch to good old Pygments. It turns out nanoc has support for a filter that parses HTML and syntax highlights code in <code class="language-foo"> tags using Pygments. Fortunately, I can disable kramdown’s syntax highlighting and make it emit exactly that, with proper language-foo classes and all.

It’s a somewhat convoluted process, but I now have proper Rust highlighting! Here’s a sample:

/// An iterator wrapping a `std::str::Chars` iterator which also keeps track of
/// the current line and column position.
#[derive(Clone)]
struct CharsPos<'a> {
    chars: Chars<'a>,
    pos: Pos,
}

impl<'a> Iterator for CharsPos<'a> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        let opt_c = self.chars.next();
        match opt_c {
            Some('\n') => { self.pos.line += 1; self.pos.column = 1; }
            Some(_) => { self.pos.column += 1; }
            None => {}
        }
        opt_c
    }
}

Incidentally, I’ve been dabbling with Perl 6 lately and finding that it has a lot of fun, wacky features. It turns out Rouge doesn’t support Perl 6 at all. Luckily for me, Pygments does, so I guess I’ll drop a random sample of that, too:

sub format-duration(Int $milliseconds where * >= 0) returns Str {
  my ($ms, $s, $m, $h, $d) = $milliseconds.polymod(1000, 60, 60, 24);
  my $ms-hundreds = ($ms / 100).round;

  if $d {
    "{$d}d {$h}h {$m}m {$s}s"
  } elsif $h {
    "{$h}h {$m}m {$s}s"
  } elsif $m {
    "{$m}m {$s}s"
  } else {
    "{$s}.{$ms-hundreds}s"
  }
}

LaTeX Math

Oh, and apparently kramdown supports \LaTeX math via MathJax. Let’s render the Taylor series expansion of e^x, why not?1

e^x = \sum_{n = 0}^{\infty} {x^n \over n!} = 1 + x + {x^2 \over 2!} + {x^3 \over 3!} + {x^4 \over 4!} + \cdots

Atom feed

I also use nanoc to generate an Atom feed for my blog posts, so you should be able to throw my website into your feed aggregator if you’re one of those rare people like me who still uses one.

Source code

Finally, the entire source code for my website, including this post, is available on GitHub.

That’s all for now, folks.

  1. Yes, I’m just showing off all the crap my site can do. Turns out it can do footnotes, too. Welcome to the footnote.2

  2. Did you know footnotes could contain yet more footnotes? Now you do.3

  3. Okay, this is just ridiculous.2