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 # LaTeX rendering of Markdown documents
16 module markdown_latex_rendering
18 import markdown_rendering
19 import markdown_github
20 import markdown_wikilinks
22 # Markdown document renderer to LaTeX
26 # Generate the LaTeX document wrapper
28 # The header includes:
30 # * package importation
31 # * begin and end document directives
32 var wrap_document
= false is optional
, writable
34 # LaTeX document class
36 # Default is `article`.
37 var document_class
= "article" is optional
, writable
39 # LaTeX document page format
41 # Default is `letter`.
42 var page_format
= "letter" is optional
, writable
47 var font_size
= "10pt" is optional
, writable
49 # Use `listings` package for code blocks?
50 var use_listings
= false is optional
, writable
52 # LaTeX output under construction
53 private var latex
: Buffer is noinit
55 # Render `document` as LaTeX
56 redef fun render
(document
) do
59 return latex
.write_to_string
62 redef fun visit
(node
) do node
.render_latex
(self)
67 # Add a raw `string` to the output
69 # Raw means that the string will not be escaped.
70 fun add_raw
(string
: String) do latex
.append string
72 # Add `text` string to the output
74 # The string will be escaped.
75 fun add_text
(text
: String) do latex
.append latex_escape
(text
)
77 # Add a blank line to the output
79 if not latex
.is_empty
and latex
.last
!= '\n' then
84 # Add an indentation depending on `ident` level
85 fun add_indent
do latex
.append
" " * indent
87 # Escape `string` to LaTeX
88 fun latex_escape
(string
: String): String do
89 var buffer
= new Buffer
90 for i
in [0 .. string
.length
[ do
91 var c
= string
.chars
[i
]
93 buffer
.append
"\\textgreater"
96 buffer
.append
"\\textless"
98 else if c
== '\\' then
99 buffer
.append
"\\textbackslash"
101 else if escaped_chars
.has
(c
) then
109 # LaTeX characters to escape
110 var escaped_chars
= ['%', '$', '{', '}', '_', '#', '&']
115 # Render `self` as HTML
116 fun render_latex
(v
: LatexRenderer) do visit_all
(v
)
121 redef class MdDocument
122 redef fun render_latex
(v
) do
123 var wrap_document
= v
.wrap_document
124 if v
.wrap_document
then
126 v
.add_raw
"\\documentclass[{v.page_format},{v.font_size}]\{{v.document_class}\}\n\n"
127 v
.add_raw
"\\usepackage[utf8]\{inputenc\}\n"
128 if v
.use_listings
then
129 v
.add_raw
"\\usepackage\{listings\}\n"
131 v
.add_raw
"\\usepackage\{hyperref\}\n"
132 v
.add_raw
"\\usepackage\{graphicx\}\n"
133 v
.add_raw
"\\usepackage\{ulem\}\n\n"
134 v
.add_raw
"\\begin\{document\}\n\n"
136 var node
= first_child
137 while node
!= null do
140 if node
!= null then v
.add_raw
"\n"
142 if wrap_document
then
143 v
.add_raw
"\n\\end\{document\}\n"
148 redef class MdHeading
149 redef fun render_latex
(v
) do
150 var level
= self.level
154 v
.add_raw
"\\section\{"
155 else if level
== 2 then
156 v
.add_raw
"\\subsection\{"
157 else if level
== 3 then
158 v
.add_raw
"\\subsubsection\{"
159 else if level
== 4 then
160 v
.add_raw
"\\paragraph\{"
161 else if level
== 5 then
162 v
.add_raw
"\\subparagraph\{"
164 # use bold for level 6 headings
165 v
.add_raw
"\\textbf\{"
174 redef class MdBlockQuote
175 redef fun render_latex
(v
) do
178 v
.add_raw
"\\begin\{quote\}"
185 v
.add_raw
"\\end\{quote\}"
190 redef class MdIndentedCodeBlock
191 redef fun render_latex
(v
) do
192 var directive
= if v
.use_listings
then "lstlisting" else "verbatim"
195 v
.add_raw
"\\begin\{{directive}\}"
197 v
.add_raw literal
or else ""
200 v
.add_raw
"\\end\{{directive}\}"
205 redef class MdFencedCodeBlock
206 redef fun render_latex
(v
) do
208 var lstlistings
= v
.use_listings
209 var directive
= if lstlistings
then "lstlisting" else "verbatim"
212 v
.add_raw
"\\begin\{{directive}\}"
213 if lstlistings
and info
!= null and not info
.is_empty
then
214 v
.add_raw
"[language={info}]"
217 v
.add_raw literal
or else ""
220 v
.add_raw
"\\end\{{directive}\}"
225 redef class MdOrderedList
226 redef fun render_latex
(v
) do
227 var start
= self.start_number
230 v
.add_raw
"\\begin\{enumerate\}"
235 v
.add_raw
"\\setcounter\{enum{nesting_level}\}\{{start}\}"
242 v
.add_raw
"\\end\{enumerate\}"
246 # Depth of ordered list
248 # Used to compute the `setcounter` level.
249 fun nesting_level
: String do
252 var parent
= self.parent
253 while parent
!= null do
254 if parent
isa MdOrderedList then nesting
+= 1
255 parent
= parent
.parent
265 redef class MdUnorderedList
266 redef fun render_latex
(v
) do
269 v
.add_raw
"\\begin\{itemize\}"
276 v
.add_raw
"\\end\{itemize\}"
281 redef class MdListItem
282 redef fun render_latex
(v
) do
293 redef class MdThematicBreak
294 redef fun render_latex
(v
) do
297 v
.add_raw
"\\begin\{center\}\\rule\{3in\}\{0.4pt\}\\end\{center\}"
302 redef class MdParagraph
303 redef fun render_latex
(v
) do
311 redef class MdHtmlBlock
312 redef fun render_latex
(v
) do
315 v
.add_raw
"\\begin\{verbatim\}"
318 v
.add_raw literal
or else ""
321 v
.add_raw
"\\end\{verbatim\}"
328 redef class MdLineBreak
329 redef fun render_latex
(v
) do
336 redef fun render_latex
(v
) do
337 v
.add_raw
"\\texttt\{"
343 redef class MdEmphasis
344 redef fun render_latex
(v
) do
345 v
.add_raw
"\\textit\{"
351 redef class MdStrongEmphasis
352 redef fun render_latex
(v
) do
353 v
.add_raw
"\\textbf\{"
359 redef class MdHtmlInline
360 redef fun render_latex
(v
) do
361 v
.add_raw
"\\texttt\{"
362 v
.add_raw v
.latex_escape
(literal
)
368 redef fun render_latex
(v
) do
369 v
.add_raw
"\\includegraphics\{"
370 v
.add_text destination
374 private fun alt_text
: String do
375 var v
= new RawTextVisitor
376 return v
.render
(self)
381 redef fun render_latex
(v
) do
384 v
.add_text destination
388 var title
= self.title
390 v
.add_text destination
393 if title
!= null and not title
.is_empty
then
403 redef fun render_latex
(v
) do
411 redef fun render_latex
(v
) do
419 redef fun render_latex
(v
) do
420 v
.add_raw
"\\textsuperscript\{"
428 redef class MdWikilink
429 redef fun render_latex
(v
) do
430 v
.add_raw
"\\texttt\{"
431 var title
= self.title
432 if title
!= null then
433 v
.add_text
"{title} | "