1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
# frozen_string_literal: true
require "set"
require "stringio"
module CommonMarker
class Renderer
attr_accessor :in_tight, :warnings, :in_plain
def initialize(options: :DEFAULT, extensions: [])
@opts = Config.process_options(options, :render)
@stream = StringIO.new(+"")
@need_blocksep = false
@warnings = Set.new([])
@in_tight = false
@in_plain = false
@tagfilter = extensions.include?(:tagfilter)
end
def out(*args)
args.each do |arg|
case arg
when :children
@node.each { |child| out(child) }
when Array
arg.each { |x| render(x) }
when Node
render(arg)
else
@stream.write(arg)
end
end
end
def render(node)
@node = node
if node.type == :document
document(node)
@stream.string
elsif @in_plain && node.type != :text && node.type != :softbreak
node.each { |child| render(child) }
else
begin
send(node.type, node)
rescue NoMethodError => e
@warnings.add("WARNING: #{node.type} not implemented.")
raise e
end
end
end
def document(_node)
out(:children)
end
def code_block(node)
code_block(node)
end
def reference_def(_node); end
def cr
return if @stream.string.empty? || @stream.string[-1] == "\n"
out("\n")
end
def blocksep
out("\n")
end
def containersep
cr unless @in_tight
end
def block
cr
yield
cr
end
def container(starter, ender)
out(starter)
yield
out(ender)
end
def plain
old_in_plain = @in_plain
@in_plain = true
yield
@in_plain = old_in_plain
end
private
def escape_href(str)
@node.html_escape_href(str)
end
def escape_html(str)
@node.html_escape_html(str)
end
def tagfilter(str)
if @tagfilter
str.gsub(
%r{
<
(
title|textarea|style|xmp|iframe|
noembed|noframes|script|plaintext
)
(?=\s|>|/>)
}xi,
'<\1',
)
else
str
end
end
def sourcepos(node)
return "" unless option_enabled?(:SOURCEPOS)
s = node.sourcepos
" data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
"#{s[:end_line]}:#{s[:end_column]}\""
end
def option_enabled?(opt)
(@opts & CommonMarker::Config::OPTS.dig(:render, opt)) != 0
end
end
end
|