对 Markdown 渲染引擎 kramdown 的几点 hack
kramdown version: 1.11.1
使生成 head ID 功能支持中文
我查看了 kramdown 选项部分的所有文档,发现它只支持 transliterated_header_ids. 但是我不喜欢将中文音译为拼音,所以干脆直接修改代码好了,还比较简单。
首先找到相关的代码,如下所示:
## /lib/kramdown/converter/base.rb
def generate_id(str)
str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids]
gen_id = str.gsub(/^[^a-zA-Z]+/, '')
gen_id.tr!('^a-zA-Z0-9 -', '')
gen_id.tr!(' ', '-')
gen_id.downcase!
gen_id = 'section' if gen_id.length == 0
@used_ids ||= {}
if @used_ids.has_key?(gen_id)
gen_id += '-' << (@used_ids[gen_id] += 1).to_s
else
@used_ids[gen_id] = 0
end
@options[:auto_id_prefix] + gen_id
end
我们看上面代码中的 5-8 行,就是对 ID 的转换, str 表示 head 的 raw text.
原代码的意思是:取以字母开始的子串,去掉除了字母,数字,空格,连字符的字符,将空格替换为连字符,将字母变为小写
我们将代码改为如下:
def generate_id(str)
str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids]
# gen_id = str.gsub(/^[^a-zA-Z]+/, '')
# gen_id.tr!('^a-zA-Z0-9 -', '')
# gen_id.tr!(' ', '-')
# gen_id.downcase!
# gen_id = 'section' if gen_id.length == 0
gen_id = str.scan(/([a-zA-Z0-9 \-]|[^\x00-\x7F])/).join
gen_id.gsub!(/[ \-]+/, '-')
gen_id.downcase!
@used_ids ||= {}
if @used_ids.has_key?(gen_id)
gen_id += '-' << (@used_ids[gen_id] += 1).to_s
else
@used_ids[gen_id] = 0
end
@options[:auto_id_prefix] + gen_id
end
代码的意思是:移除 ASCII 字符中除了字母,数字,空格,连字符的字符,但是不移除所有非 ASCII 字符,然后将其中空格和连字符(包括重复的)转换为一个连字符,再将其转换为小写。
我个人比较喜欢这种表达 ID 的方式,所以就那么改了,你可以随便改成什么样子。
绕过 alt text 中出现 “|” 产生的 bug
先看几个例子体会一下这个 bug 是什么,以下都是链接的例子,当然在图片中也会有问题
-
出错,会转换为表格。
[明无梦的博客 | 明无梦](http://www.dreamxu.com/)
转换为:
<table> <tbody> <tr> <td>[明无梦的博客</td> <td>明无梦](http://www.dreamxu.com/)</td> </tr> </tbody> </table>
-
正常,但是需要将
|
转义,显然我不会这样做,我的 Markdown 代码写的没问题,没必要修改,而且 ‘|’ 看起来不直观。[明无梦的博客 \| 明无梦](http://www.dreamxu.com/)
转换为:
<p> <a href="http://www.dreamxu.com/">明无梦的博客 | 明无梦</a> </p>
-
正常,但是链接前后必须有其它文字。为什么我单独写个链接就不行!显然也不是我能接受的解决方案。
这是一个博客: [明无梦的博客 | 明无梦](http://www.dreamxu.com/)
转换为:
<p>这是一个博客: <a href="http://www.dreamxu.com/">明无梦的博客 | 明无梦</a></p>
产生这个 bug 的原因很简单,就是 kramdown 支持 PHP Markdown 式的表格,其中有用 |
关键词,所以会将其转换为表格。
我看 Github 上也有人提出了这个 bug: https://github.com/gettalong/kramdown/issues/135, 看样子是已经修好了。但是从上面的例子中也可以看出来并没有修好,所以我打算绕过这个 bug, 这是最简单的处理方式了。
我们只要将其 table parse 功能取消掉就好了,反正我也不使用这种表格写法。注意,如果你用到了这个功能,那么就不要这么做了。
# /lib/kramdown/parser/kramdown.rb
def initialize(source, options)
super
reset_env
@alds = {}
@footnotes = {}
@link_defs = {}
update_link_definitions(@options[:link_defs])
# 原来的代码是这个样子的,将 :table 去掉即可
#
# @block_parsers = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :atx_header,
# :horizontal_rule, :list, :definition_list, :block_html, :setext_header,
# :block_math, :table, :footnote_definition, :link_definition, :abbrev_definition,
# :block_extensions, :eob_marker, :paragraph]
@block_parsers = [:blank_line, :codeblock, :codeblock_fenced, :blockquote, :atx_header,
:horizontal_rule, :list, :definition_list, :block_html, :setext_header,
:block_math, :footnote_definition, :link_definition, :abbrev_definition,
:block_extensions, :eob_marker, :paragraph]
@span_parsers = [:emphasis, :codespan, :autolink, :span_html, :footnote_marker, :link, :smart_quotes, :inline_math,
:span_extensions, :html_entity, :typographic_syms, :line_break, :escaped_chars]
end