markly 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,281 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cgi'
4
-
5
- module Markly
6
- class HTMLRenderer < Renderer
7
- def initialize(ids: false, tight: false, **options)
8
- super(**options)
9
-
10
- @ids = ids
11
- @section = nil
12
- @tight = tight
13
- end
14
-
15
- def document(_)
16
- @section = false
17
- super
18
- out("</ol>\n</section>\n") if @written_footnote_ix
19
- out("</section>") if @section
20
- end
21
-
22
- def id_for(node)
23
- if @ids
24
- id = node.to_plaintext.chomp.downcase.gsub(/\s+/, '-')
25
-
26
- return " id=\"#{CGI.escape_html id}\""
27
- end
28
- end
29
-
30
- def header(node)
31
- block do
32
- if @ids
33
- out('</section>') if @section
34
- @section = true
35
- out("<section#{id_for(node)}>")
36
- end
37
-
38
- out('<h', node.header_level, "#{source_position(node)}>", :children,
39
- '</h', node.header_level, '>')
40
- end
41
- end
42
-
43
- def paragraph(node)
44
- if @tight && node.parent.type != :blockquote
45
- out(:children)
46
- else
47
- block do
48
- container("<p#{source_position(node)}>", '</p>') do
49
- out(:children)
50
- if node.parent.type == :footnote_definition && node.next.nil?
51
- out(' ')
52
- out_footnote_backref
53
- end
54
- end
55
- end
56
- end
57
- end
58
-
59
- def list(node)
60
- old_tight = @tight
61
- @tight = node.list_tight
62
-
63
- block do
64
- if node.list_type == :bullet_list
65
- container("<ul#{source_position(node)}>\n", '</ul>') do
66
- out(:children)
67
- end
68
- else
69
- start = if node.list_start == 1
70
- "<ol#{source_position(node)}>\n"
71
- else
72
- "<ol start=\"#{node.list_start}\"#{source_position(node)}>\n"
73
- end
74
- container(start, '</ol>') do
75
- out(:children)
76
- end
77
- end
78
- end
79
-
80
- @tight = old_tight
81
- end
82
-
83
- def list_item(node)
84
- block do
85
- tasklist_data = tasklist(node)
86
- container("<li#{source_position(node)}#{tasklist_data}>#{' ' if tasklist?(node)}", '</li>') do
87
- out(:children)
88
- end
89
- end
90
- end
91
-
92
- def tasklist(node)
93
- return '' unless tasklist?(node)
94
-
95
- state = if checked?(node)
96
- 'checked="" disabled=""'
97
- else
98
- 'disabled=""'
99
- end
100
- "><input type=\"checkbox\" #{state} /"
101
- end
102
-
103
- def blockquote(node)
104
- block do
105
- container("<blockquote#{source_position(node)}>\n", '</blockquote>') do
106
- out(:children)
107
- end
108
- end
109
- end
110
-
111
- def hrule(node)
112
- block do
113
- out("<hr#{source_position(node)} />")
114
- end
115
- end
116
-
117
- def code_block(node)
118
- block do
119
- if flag_enabled?(GITHUB_PRE_LANG)
120
- out("<pre#{source_position(node)}")
121
- out(' lang="', node.fence_info.split(/\s+/)[0], '"') if node.fence_info && !node.fence_info.empty?
122
- out('><code>')
123
- else
124
- out("<pre#{source_position(node)}><code")
125
- if node.fence_info && !node.fence_info.empty?
126
- out(' class="language-', node.fence_info.split(/\s+/)[0], '">')
127
- else
128
- out('>')
129
- end
130
- end
131
- out(escape_html(node.string_content))
132
- out('</code></pre>')
133
- end
134
- end
135
-
136
- def html(node)
137
- block do
138
- if flag_enabled?(UNSAFE)
139
- out(tagfilter(node.string_content))
140
- else
141
- out('<!-- raw HTML omitted -->')
142
- end
143
- end
144
- end
145
-
146
- def inline_html(node)
147
- if flag_enabled?(UNSAFE)
148
- out(tagfilter(node.string_content))
149
- else
150
- out('<!-- raw HTML omitted -->')
151
- end
152
- end
153
-
154
- def emph(_)
155
- out('<em>', :children, '</em>')
156
- end
157
-
158
- def strong(_)
159
- out('<strong>', :children, '</strong>')
160
- end
161
-
162
- def link(node)
163
- out('<a href="', node.url.nil? ? '' : escape_href(node.url), '"')
164
- out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
165
- out('>', :children, '</a>')
166
- end
167
-
168
- def image(node)
169
- out('<img src="', escape_href(node.url), '"')
170
- plain do
171
- out(' alt="', :children, '"')
172
- end
173
- out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
174
- out(' />')
175
- end
176
-
177
- def text(node)
178
- out(escape_html(node.string_content))
179
- end
180
-
181
- def code(node)
182
- out('<code>')
183
- out(escape_html(node.string_content))
184
- out('</code>')
185
- end
186
-
187
- def linebreak(_node)
188
- out("<br />\n")
189
- end
190
-
191
- def softbreak(_)
192
- if flag_enabled?(HARD_BREAKS)
193
- out("<br />\n")
194
- elsif flag_enabled?(NO_BREAKS)
195
- out(' ')
196
- else
197
- out("\n")
198
- end
199
- end
200
-
201
- def table(node)
202
- @alignments = node.table_alignments
203
- @needs_close_tbody = false
204
- out("<table#{source_position(node)}>\n", :children)
205
- out("</tbody>\n") if @needs_close_tbody
206
- out("</table>\n")
207
- end
208
-
209
- def table_header(node)
210
- @column_index = 0
211
-
212
- @in_header = true
213
- out("<thead>\n<tr#{source_position(node)}>\n", :children, "</tr>\n</thead>\n")
214
- @in_header = false
215
- end
216
-
217
- def table_row(node)
218
- @column_index = 0
219
- if !@in_header && !@needs_close_tbody
220
- @needs_close_tbody = true
221
- out("<tbody>\n")
222
- end
223
- out("<tr#{source_position(node)}>\n", :children, "</tr>\n")
224
- end
225
-
226
- def table_cell(node)
227
- align = case @alignments[@column_index]
228
- when :left then ' align="left"'
229
- when :right then ' align="right"'
230
- when :center then ' align="center"'
231
- else; ''
232
- end
233
- out(@in_header ? "<th#{align}#{source_position(node)}>" : "<td#{align}#{source_position(node)}>", :children, @in_header ? "</th>\n" : "</td>\n")
234
- @column_index += 1
235
- end
236
-
237
- def strikethrough(_)
238
- out('<del>', :children, '</del>')
239
- end
240
-
241
- def footnote_reference(node)
242
- out("<sup class=\"footnote-ref\"><a href=\"#fn#{node.string_content}\" id=\"fnref#{node.string_content}\">#{node.string_content}</a></sup>")
243
- end
244
-
245
- def footnote_definition(_)
246
- unless @footnote_ix
247
- out("<section class=\"footnotes\">\n<ol>\n")
248
- @footnote_ix = 0
249
- end
250
-
251
- @footnote_ix += 1
252
- out("<li id=\"fn#{@footnote_ix}\">\n", :children)
253
- out("\n") if out_footnote_backref
254
- out("</li>\n")
255
- # </ol>
256
- # </section>
257
- end
258
-
259
- private
260
-
261
- def out_footnote_backref
262
- return false if @written_footnote_ix == @footnote_ix
263
-
264
- @written_footnote_ix = @footnote_ix
265
-
266
- out("<a href=\"#fnref#{@footnote_ix}\" class=\"footnote-backref\">↩</a>")
267
- true
268
- end
269
-
270
- def tasklist?(node)
271
- node.type_string == 'tasklist'
272
- end
273
-
274
- def checked?(node)
275
- node.tasklist_item_checked?
276
- end
277
- end
278
-
279
- # Legacy.
280
- HtmlRenderer = HTMLRenderer
281
- end
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'set'
4
- require 'stringio'
5
-
6
- module Markly
7
- class Renderer
8
- attr_accessor :in_tight, :warnings, :in_plain
9
- def initialize(flags: DEFAULT, extensions: [])
10
- @flags = flags
11
- @stream = StringIO.new(+'')
12
- @need_blocksep = false
13
- @warnings = Set.new
14
- @in_tight = false
15
- @in_plain = false
16
- @tagfilter = extensions.include?(:tagfilter)
17
- end
18
-
19
- def out(*args)
20
- args.each do |arg|
21
- if arg == :children
22
- @node.each { |child| out(child) }
23
- elsif arg.is_a?(Array)
24
- arg.each { |x| render(x) }
25
- elsif arg.is_a?(Node)
26
- render(arg)
27
- else
28
- @stream.write(arg)
29
- end
30
- end
31
- end
32
-
33
- def render(node)
34
- @node = node
35
- if node.type == :document
36
- document(node)
37
- @stream.string
38
- elsif @in_plain && node.type != :text && node.type != :softbreak
39
- node.each { |child| render(child) }
40
- else
41
- begin
42
- send(node.type, node)
43
- rescue NoMethodError => e
44
- @warnings.add("WARNING: #{node.type} not implemented.")
45
- raise e
46
- end
47
- end
48
- end
49
-
50
- def document(_node)
51
- out(:children)
52
- end
53
-
54
- def code_block(node)
55
- code_block(node)
56
- end
57
-
58
- def reference_def(_node); end
59
-
60
- def cr
61
- return if @stream.string.empty? || @stream.string[-1] == "\n"
62
-
63
- out("\n")
64
- end
65
-
66
- def blocksep
67
- out("\n")
68
- end
69
-
70
- def containersep
71
- cr unless @in_tight
72
- end
73
-
74
- def block
75
- cr
76
- yield
77
- cr
78
- end
79
-
80
- def container(starter, ender)
81
- out(starter)
82
- yield
83
- out(ender)
84
- end
85
-
86
- def plain
87
- old_in_plain = @in_plain
88
- @in_plain = true
89
- yield
90
- @in_plain = old_in_plain
91
- end
92
-
93
- private
94
-
95
- def escape_href(str)
96
- @node.html_escape_href(str)
97
- end
98
-
99
- def escape_html(str)
100
- @node.html_escape_html(str)
101
- end
102
-
103
- def tagfilter(str)
104
- if @tagfilter
105
- str.gsub(
106
- %r{
107
- <
108
- (
109
- title|textarea|style|xmp|iframe|
110
- noembed|noframes|script|plaintext
111
- )
112
- (?=\s|>|/>)
113
- }xi,
114
- '&lt;\1'
115
- )
116
- else
117
- str
118
- end
119
- end
120
-
121
- def source_position(node)
122
- return '' unless flag_enabled?(SOURCE_POSITION)
123
-
124
- s = node.source_position
125
- " data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
126
- "#{s[:end_line]}:#{s[:end_column]}\""
127
- end
128
-
129
- def flag_enabled?(flag)
130
- (@flags & flag) != 0
131
- end
132
- end
133
- end