树处理器扩展
当源中的块被解析成文档结构(由 Document 对象及其子 AbstractNode 对象(例如 Section、Block、List、ListItem)表示)之后,会针对 Document 实例运行一个 TreeProcessor 扩展。
Asciidoctor 会在每个已注册的 TreeProcessor 扩展的实例上调用 Processor#process 方法。
| 树处理器扩展在任何行内标记被解释之前运行。当调用 TreeProcessor 扩展上的 process 方法时,文档中的块节点包含未经处理、未转换的文本。行内标记的转换是在文档被转换时完成的。因此,树处理器扩展有可能替换节点上的源文本,但必须考虑到文本仍将根据块的内容模型进行解析的事实。 |
树处理器扩展示例
- 目的
-
检测包含 shell 命令的字面块,去除提示符字符,并使用 CSS 样式化命令,使其提示符字符不可选(如 help.github.com 所示)。
ShellSessionTreeProcessor
class ShellSessionTreeProcessor < Asciidoctor::Extensions::TreeProcessor
LF = ?\n
def process document
(document.find_by(context: :literal) {|candidate| candidate.lines[0].start_with? '$ ', '> ' }).each do |block|
(children = block.parent.blocks)[children.index block] = convert_to_terminal_listing block
end
nil
end
def convert_to_terminal_listing block
attrs = block.attributes
attrs['role'] = 'terminal'
prompt_attr = (attrs.key? 'prompt') ? %( data-prompt="#{block.sub_specialchars attrs['prompt']}") : nil
lines = (block.content.split LF).map do |line|
if line.start_with? '$ '
%(<span class="command"#{prompt_attr}>#{line[2..-1]}</span>)
elsif line.start_with? '> '
%(<span class="output">#{line[5..-1]}</span>)
#%(<span class="output"><span class="comment-prefix"># </span>#{line[5..-1]}</span>)
else
line
end
end
create_listing_block block.parent, lines * LF, attrs, subs: nil
end
end