02439e1dcbcfcc86a40c772c41b5cc8fbaff0f75
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Markdown rendering of Markdown documents
16 module markdown_md_rendering
18 import markdown_rendering
20 # Markdown document renderer to Markdown
21 class MarkdownRenderer
24 # Markdown output under construction
25 private var md
: Buffer is noinit
27 # Render `node` as Markdown
28 redef fun render
(node
) do
31 return md
.write_to_string
34 redef fun visit
(node
) do node
.render_md
(self)
36 # Reset internal state
41 # Current indentation level
42 private var indent
= 0
44 # Are we currently in a blockquote?
47 # Add a `md` string to the output
48 fun add_raw
(md
: String) do self.md
.append
(md
)
50 # Add a blank line to the output
51 fun add_line
do add_raw
"\n"
53 # Add an indentation depending on `ident` level
59 private class TextLengthVisitor
64 redef fun visit
(node
) do node
.process_len
(self)
69 # Render `self` as Markdown
70 fun render_md
(v
: MarkdownRenderer) do visit_all
(v
)
72 private fun process_len
(v
: TextLengthVisitor) do visit_all
(v
)
75 redef class MdDocument
76 redef fun render_md
(v
) do
77 var node
= first_child
90 redef class MdBlockQuote
91 redef fun render_md
(v
) do
93 var node
= first_child
104 redef class MdIndentedCodeBlock
105 redef fun render_md
(v
) do
106 var literal
= self.literal
107 if literal
== null then return
109 var lines
= literal
.split
("\n")
110 for i
in [0..lines
.length
[ do
111 if i
== lines
.length
- 1 then continue
113 if line
.is_empty
then
129 redef class MdFencedCodeBlock
130 redef fun render_md
(v
) do
133 v
.add_raw fence_char
.to_s
* fence_length
134 v
.add_raw info
or else ""
135 for line
in (literal
or else "").split
("\n") do
137 if not line
.is_empty
then
143 v
.add_raw fence_char
.to_s
* fence_length
148 redef class MdHeading
149 redef fun render_md
(v
) do
152 var length_visitor
= new TextLengthVisitor
153 length_visitor
.enter_visit
(self)
156 v
.add_raw
"=" * length_visitor
.length
158 v
.add_raw
"-" * length_visitor
.length
161 v
.add_raw
"#" * level
164 if has_atx_trailing
then
166 v
.add_raw
"#" * level
173 redef class MdOrderedList
175 private var md_numbering
: Int = start_number
is lazy
178 redef class MdListItem
179 redef fun render_md
(v
) do
180 var parent
= self.parent
181 var is_tight
= parent
.as(MdListBlock).is_tight
184 if parent
isa MdUnorderedList then
185 v
.add_raw parent
.bullet_marker
.to_s
187 else if parent
isa MdOrderedList then
188 v
.add_raw
"{parent.md_numbering}{parent.delimiter.to_s}"
192 var node
= first_child
198 while node
!= null do
201 if node
!= null and not is_tight
then
206 if next
!= null and not is_tight
then
210 if parent
isa MdUnorderedList then
212 else if parent
isa MdOrderedList then
213 parent
.md_numbering
+= 1
219 redef class MdParagraph
220 redef fun render_md
(v
) do
221 if not parent
isa MdBlockQuote and not parent
isa MdListItem or prev
!= null then
224 # if parent isa MdBlockQuote then
226 # var node = first_child
227 # while node != null do
228 # v.enter_visit(node)
229 # if node isa MdSoftLineBreak or node isa MdHardLineBreak then
242 redef class MdThematicBreak
243 redef fun render_md
(v
) do
244 v
.add_raw original_pattern
249 redef class MdHtmlBlock
250 redef fun render_md
(v
) do
251 v
.add_raw literal
or else ""
258 redef class MdHardLineBreak
259 redef fun render_md
(v
) do
260 if has_backslash
then
267 v
.add_raw
"> " * v
.in_quote
270 redef fun process_len
(v
) do
276 redef class MdSoftLineBreak
277 redef fun render_md
(v
) do
280 v
.add_raw
"> " * v
.in_quote
283 redef fun process_len
(v
) do
290 redef fun render_md
(v
) do
296 redef fun process_len
(v
) do
298 v
.length
+= delimiter
.length
302 redef class MdDelimited
303 redef fun render_md
(v
) do
309 redef fun process_len
(v
) do
311 v
.length
+= delimiter
.length
* 2
315 redef class MdHtmlInline
316 redef fun render_md
(v
) do
320 redef fun process_len
(v
) do
321 v
.length
+= literal
.length
325 redef class MdLinkOrImage
326 redef fun render_md
(v
) do
327 var title
= self.title
335 v
.add_raw destination
339 if title
!= null and not title
.is_empty
then
341 v.add_raw title.replace("\
"", "\\\"")
350 redef fun render_md
(v
) do
357 redef fun render_md
(v
) do
360 v
.add_raw destination
369 redef fun render_md
(v
) do
373 redef fun process_len
(v
) do
374 v
.length
+= literal
.length