Class: MarkdownViews::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/markdown_views/renderer.rb

Class Method Summary collapse

Class Method Details

.render(template) ⇒ Object



5
6
7
8
9
10
11
# File 'lib/markdown_views/renderer.rb', line 5

def render(template)
  out = template.to_s
  out = strip_comments(out) if MarkdownViews.strip_comments
  out = render_md(out)
  out = strip_comments(out) if MarkdownViews.strip_comments
  out.html_safe
end

.render_md(input) ⇒ Object

remainder all considered private



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/markdown_views/renderer.rb', line 15

def render_md(input)
  doc = Commonmarker.parse(input, options: {
    extension: MarkdownViews.extensions,
    parse: MarkdownViews.parsing_opts,
  })

  if MarkdownViews.transformers.include? :code_blocks
    code_blocks = transform_code_blocks(doc)
  end

  out = doc.to_html(
    options: {
      extension: MarkdownViews.extensions,
      render: MarkdownViews.rendering_opts,
    },
    plugins: MarkdownViews.plugins
  )
  code_blocks&.each do |uuid, cb|
    out.sub! uuid, cb
  end
  out
end

.rouge_formatterObject



38
39
40
# File 'lib/markdown_views/renderer.rb', line 38

def rouge_formatter
  MarkdownViews.rouge_opts[:formatter] || Rouge::Formatters::HTML.new
end

.strip_comments(input) ⇒ Object

removes single & multi-line comments

if any content besides comment & whitespace is on same line(s), strips just the comment.
if no other content, strips the lines & whitespace too.


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/markdown_views/renderer.rb', line 45

def strip_comments(input)
  # ^[ \t]*(<!--.*?-->)++[ \t]*\r?\n    lines with just comments
  # |                                   or
  # <!--.*?-->                          comments on lines with other content
  #
  # ^                 start of line
  # [ \t]*            optional spaces or tabs
  # (<!--.*?-->)++
  #   <!--            start of html comment
  #   .*?             any char, incl linefeed (for multi-line comments)
  #                     lazy (non-greedy): *?
  #   -->             end of html comment
  #   ++              possessive match - prevents a match across comment boundaries
  #                     ie: prevent matching this: <!-- a --> keep <!-- b -->
  #                     explanation: initially .*? will refuse to match --> because it's
  #                       non-greedy. but, in search of pre/post whitespace, the regex engine
  #                       could backtrack and ask .*? to match an --> as long as there's
  #                       another --> later. possessive disables the backtracking.
  #                     can combine <!-- a --><!-- b --> into one match, which is of no harm.
  # [ \t]*            optional spaces or tabs
  # \r?\n             end of line (either unix or windows style)
  input.gsub(/^[ \t]*(<!--.*?-->)++[ \t]*\r?\n|<!--.*?-->/m, '')
end

.transform_code_blocks(doc) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/markdown_views/renderer.rb', line 69

def transform_code_blocks(doc)
  code_blocks = {}
  doc.walk do |node|
    next unless node.type == :code_block
    next if node.fence_info == ''

    lang = node.fence_info
    code = node.string_content
    lexer = Rouge::Lexer.find(lang) || Rouge::Lexers::PlainText
    html = rouge_formatter.format(lexer.lex code).rstrip
    if MarkdownViews.rouge_opts[:wrap]
      html = %Q{<pre lang="#{lang.gsub(/[^a-z0-9_-]/,'')}"><code class="rouge-highlight">#{html}</code></pre>}
    end

    uuid = SecureRandom.uuid
    code_blocks[uuid] = html
    new_node = Commonmarker::Node.new(:text, content: "#{uuid}\n")
    node.replace new_node
  end
  code_blocks
end