Hashes codeblocks (<pre> elements).

    Codeblocks are strictly defined to be (non-list) lines that are
    indented at least 4 spaces from the newline. Exactly 4 spaces will
    be stripped from the beginning of the line -- any leading
    whitespace after that is preserved.

    Codeblock lines that are separated only by blank lines will be
    included in the same codeblock (as will the intermediate newlines).

    Certain HTML entities (&, <, >, ", ') will always be escaped inside
    code blocks.

    Markdown defines code blocks to be <pre><code>, not just <pre>.
    Certain highlighting packages (like highlight.js) are designed
    to accomodate (and even look) for this type of conversion.

def hash_codeblocks(text, hashes):
    """Hashes codeblocks (<pre> elements).

    Codeblocks are strictly defined to be (non-list) lines that are
    indented at least 4 spaces from the newline. Exactly 4 spaces will
    be stripped from the beginning of the line -- any leading
    whitespace after that is preserved.

    Codeblock lines that are separated only by blank lines will be
    included in the same codeblock (as will the intermediate newlines).

    Certain HTML entities (&, <, >, ", ') will always be escaped inside
    code blocks.

    Markdown defines code blocks to be <pre><code>, not just <pre>.
    Certain highlighting packages (like highlight.js) are designed
    to accomodate (and even look) for this type of conversion.
    """
    def sub(match):
        block = match.group(1).rstrip('\n')
        block = re.sub(r'(?:(?<=\n)|(?<=\A)) {4}', '', block)
        block = escape(block)
        block = '<pre><code>{}</code></pre>'.format(block)
        hashed = hash_text(block, 'pre')
        hashes[hashed] = block
        return '\n\n' + hashed + '\n\n'
    return re_codeblock.sub(sub, text)