.rst to .html

高端玩家Don't Use Markdown for Technical Docs!

萌新: 没有什么技术文档是Markdown无法表述的,不行就加个div元素。

NPC: 为咩不用Word?

起因

本站的内容起初是使用Markdown编写的,在样式表中给p元素添加了首行缩进。文本转译成.html后,原本独立的img元素被包裹在p标签中。

这就导致:不符合语义;移动端显示时,图片因缩进,而溢出屏幕边界。

经过

解决方法不外乎:1、在文本中插入一个div元素;2、使用新的文本标记语言。

因为插入div元素不能彻底解决问题,所以将Markdown替换成reStructuredText(被用于编写Python文档)。reStructuredText可以通过include指令引用外部文档(如:代码片段),达到去除冗余的目的。

接下来,要做的只是:编写一个Jekyll Converters插件,通过管道调用外部的Python脚本,将文本由.rst格式转换成.html格式。

Docutils源码中提供了相应的工具:rst2html5.py脚本,但这个转换脚本将输出一个带有head部分的.html文本。publish_cmdline函数位于docutils目录下的core.py文件中,此文件内包含有一个Publisher类和多个以“publish”开头的函数。

通过阅读文档字符串,可以看到publish_parts函数返回:a dictionary of document partspub.writer.parts)。pub对象,又是通过调用publish_programmatically函数——实例化Publisher类——产生的。

查看docutils/writers目录下的_html_base.py文件,可以获悉一个.html文本究竟是由哪几部分构成:

visitor_attributes = (
    'head_prefix', 'head', 'stylesheet', 'body_prefix',
    'body_pre_docinfo', 'docinfo', 'body', 'body_suffix',
    'title', 'subtitle', 'header', 'footer', 'meta', 'fragment',
    'html_prolog', 'html_head', 'html_title', 'html_subtitle',
    'html_body')

于是乎,我们可以编写出如下的.rst to .html转换函数:

settings = {'syntax_highlight': 'short',
            'initial_header_level': 2,
            'raw_enabled': False, }


def converter(source, part="html_body"):
    parts = publish_parts(
        source,
        writer_name='html5',
        settings_overrides=settings)
    return parts.get(part, '')

结果

Jekyll项目的_plugins/rst2html目录下,编写插件converter.rbrst2html5.py

converter.rb,代码如下:

module Jekyll
  class RstConverter < Converter
    safe true
    priority :low

    def matches(ext)
      ext =~ /rst/i
    end

    def output_ext(ext)
      ".html"
    end

    def convert(content)
      IO.popen("python #{File.expand_path(File.dirname(__FILE__))}/rst2html5.py", 'r+') do |pipe|
        pipe.puts(content)
        pipe.close_write
        result = pipe.read
        pipe.close_read
        result
      end
    end
  end

  module Filters
    def rst(input)
      site = @context.registers[:site]
      converter = site.find_converter_instance(::Jekyll::Converters::RstConverter)
      converter.convert(input)
    end
  end
end

rst2html5.py,代码如下:

try:
    import locale  # module missing in Jython

    locale.setlocale(locale.LC_ALL, '')
except locale.Error:
    pass

import sys

from docutils.core import publish_parts

settings = {'syntax_highlight': 'short',
            'initial_header_level': 2,
            'raw_enabled': False, }


def converter(source, part="html_body"):
    parts = publish_parts(
        source,
        writer_name='html5',
        settings_overrides=settings)
    return parts.get(part, '')


if __name__ == "__main__":
    sys.stdout.write(converter(sys.stdin.read()))