latex.go (view raw)
1//
2// Black Friday Markdown Processor
3// Originally based on http://github.com/tanoku/upskirt
4// by Russ Ross <russ@russross.com>
5//
6
7//
8//
9// LaTeX rendering backend
10//
11//
12
13package blackfriday
14
15import (
16 "bytes"
17)
18
19func LatexRenderer(flags int) *Renderer {
20 // block-level rendering
21 r := new(Renderer)
22 r.BlockCode = latexBlockCode
23 r.BlockQuote = latexBlockQuote
24 //r.BlockHtml = ?
25 r.Header = latexHeader
26 r.HRule = latexHRule
27 r.List = latexList
28 r.ListItem = latexListItem
29 r.Paragraph = latexParagraph
30 r.Table = latexTable
31 r.TableRow = latexTableRow
32 r.TableCell = latexTableCell
33
34 // inline rendering
35 r.AutoLink = latexAutoLink
36 r.CodeSpan = latexCodeSpan
37 r.DoubleEmphasis = latexDoubleEmphasis
38 r.Emphasis = latexEmphasis
39 r.Image = latexImage
40 r.LineBreak = latexLineBreak
41 r.Link = latexLink
42 //r.rawHtmlTag = ?
43 r.StrikeThrough = latexStrikeThrough
44
45 r.NormalText = latexNormalText
46
47 r.DocumentHeader = latexDocumentHeader
48 r.DocumentFooter = latexDocumentFooter
49
50 r.Opaque = nil
51 return r
52}
53
54// render code chunks using verbatim, or listings if we have a language
55func latexBlockCode(out *bytes.Buffer, text []byte, lang string, opaque interface{}) {
56 if lang == "" {
57 out.WriteString("\n\\begin{verbatim}\n")
58 } else {
59 out.WriteString("\n\\begin{lstlisting}[language=")
60 out.WriteString(lang)
61 out.WriteString("]\n")
62 }
63 out.Write(text)
64 if lang == "" {
65 out.WriteString("\n\\end{verbatim}\n")
66 } else {
67 out.WriteString("\n\\end{lstlisting}\n")
68 }
69}
70
71func latexBlockQuote(out *bytes.Buffer, text []byte, opaque interface{}) {
72 out.WriteString("\n\\begin{quotation}\n")
73 out.Write(text)
74 out.WriteString("\n\\end{quotation}\n")
75}
76
77//BlockHtml func(out *bytes.Buffer, text []byte, opaque interface{})
78
79func latexHeader(out *bytes.Buffer, text func() bool, level int, opaque interface{}) {
80 marker := out.Len()
81
82 switch level {
83 case 1:
84 out.WriteString("\n\\section{")
85 case 2:
86 out.WriteString("\n\\subsection{")
87 case 3:
88 out.WriteString("\n\\subsubsection{")
89 case 4:
90 out.WriteString("\n\\paragraph{")
91 case 5:
92 out.WriteString("\n\\subparagraph{")
93 case 6:
94 out.WriteString("\n\\textbf{")
95 }
96 if !text() {
97 out.Truncate(marker)
98 return
99 }
100 out.WriteString("}\n")
101}
102
103func latexHRule(out *bytes.Buffer, opaque interface{}) {
104 out.WriteString("\n\\HRule\n")
105}
106
107func latexList(out *bytes.Buffer, text func() bool, flags int, opaque interface{}) {
108 marker := out.Len()
109 if flags&LIST_TYPE_ORDERED != 0 {
110 out.WriteString("\n\\begin{enumerate}\n")
111 } else {
112 out.WriteString("\n\\begin{itemize}\n")
113 }
114 if !text() {
115 out.Truncate(marker)
116 return
117 }
118 if flags&LIST_TYPE_ORDERED != 0 {
119 out.WriteString("\n\\end{enumerate}\n")
120 } else {
121 out.WriteString("\n\\end{itemize}\n")
122 }
123}
124
125func latexListItem(out *bytes.Buffer, text []byte, flags int, opaque interface{}) {
126 out.WriteString("\n\\item ")
127 out.Write(text)
128}
129
130func latexParagraph(out *bytes.Buffer, text []byte, opaque interface{}) {
131 out.WriteString("\n")
132 out.Write(text)
133 out.WriteString("\n")
134}
135
136func latexTable(out *bytes.Buffer, header []byte, body []byte, columnData []int, opaque interface{}) {
137 out.WriteString("\n\\begin{tabular}{")
138 for _, elt := range columnData {
139 switch elt {
140 case TABLE_ALIGNMENT_LEFT:
141 out.WriteByte('l')
142 case TABLE_ALIGNMENT_RIGHT:
143 out.WriteByte('r')
144 default:
145 out.WriteByte('c')
146 }
147 }
148 out.WriteString("}\n")
149 out.Write(header)
150 out.WriteString(" \\\\\n\\hline\n")
151 out.Write(body)
152 out.WriteString("\n\\end{tabular}\n")
153}
154
155func latexTableRow(out *bytes.Buffer, text []byte, opaque interface{}) {
156 if out.Len() > 0 {
157 out.WriteString(" \\\\\n")
158 }
159 out.Write(text)
160}
161
162func latexTableCell(out *bytes.Buffer, text []byte, align int, opaque interface{}) {
163 if out.Len() > 0 {
164 out.WriteString(" & ")
165 }
166 out.Write(text)
167}
168
169func latexAutoLink(out *bytes.Buffer, link []byte, kind int, opaque interface{}) int {
170 out.WriteString("\\href{")
171 if kind == LINK_TYPE_EMAIL {
172 out.WriteString("mailto:")
173 }
174 out.Write(link)
175 out.WriteString("}{")
176 out.Write(link)
177 out.WriteString("}")
178 return 1
179}
180
181func latexCodeSpan(out *bytes.Buffer, text []byte, opaque interface{}) int {
182 out.WriteString("\\texttt{")
183 escapeSpecialChars(out, text)
184 out.WriteString("}")
185 return 1
186}
187
188func latexDoubleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) int {
189 out.WriteString("\\textbf{")
190 out.Write(text)
191 out.WriteString("}")
192 return 1
193}
194
195func latexEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) int {
196 out.WriteString("\\textit{")
197 out.Write(text)
198 out.WriteString("}")
199 return 1
200}
201
202func latexImage(out *bytes.Buffer, link []byte, title []byte, alt []byte, opaque interface{}) int {
203 if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
204 // treat it like a link
205 out.WriteString("\\href{")
206 out.Write(link)
207 out.WriteString("}{")
208 out.Write(alt)
209 out.WriteString("}")
210 } else {
211 out.WriteString("\\includegraphics{")
212 out.Write(link)
213 out.WriteString("}")
214 }
215 return 1
216}
217
218func latexLineBreak(out *bytes.Buffer, opaque interface{}) int {
219 out.WriteString(" \\\\\n")
220 return 1
221}
222
223func latexLink(out *bytes.Buffer, link []byte, title []byte, content []byte, opaque interface{}) int {
224 out.WriteString("\\href{")
225 out.Write(link)
226 out.WriteString("}{")
227 out.Write(content)
228 out.WriteString("}")
229 return 1
230}
231
232func latexRawHtmlTag(out *bytes.Buffer, tag []byte, opaque interface{}) int {
233 return 0
234}
235
236func latexTripleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) int {
237 out.WriteString("\\textbf{\\textit{")
238 out.Write(text)
239 out.WriteString("}}")
240 return 1
241}
242
243func latexStrikeThrough(out *bytes.Buffer, text []byte, opaque interface{}) int {
244 out.WriteString("\\sout{")
245 out.Write(text)
246 out.WriteString("}")
247 return 1
248}
249
250func needsBackslash(c byte) bool {
251 for _, r := range []byte("_{}%$&\\~") {
252 if c == r {
253 return true
254 }
255 }
256 return false
257}
258
259func escapeSpecialChars(out *bytes.Buffer, text []byte) {
260 for i := 0; i < len(text); i++ {
261 // directly copy normal characters
262 org := i
263
264 for i < len(text) && !needsBackslash(text[i]) {
265 i++
266 }
267 if i > org {
268 out.Write(text[org:i])
269 }
270
271 // escape a character
272 if i >= len(text) {
273 break
274 }
275 out.WriteByte('\\')
276 out.WriteByte(text[i])
277 }
278}
279
280func latexNormalText(out *bytes.Buffer, text []byte, opaque interface{}) {
281 escapeSpecialChars(out, text)
282}
283
284// header and footer
285func latexDocumentHeader(out *bytes.Buffer, opaque interface{}) {
286 out.WriteString("\\documentclass{article}\n")
287 out.WriteString("\n")
288 out.WriteString("\\usepackage{graphicx}\n")
289 out.WriteString("\\usepackage{listings}\n")
290 out.WriteString("\\usepackage[margin=1in]{geometry}\n")
291 out.WriteString("\\usepackage[utf8]{inputenc}\n")
292 out.WriteString("\\usepackage{verbatim}\n")
293 out.WriteString("\\usepackage[normalem]{ulem}\n")
294 out.WriteString("\\usepackage{hyperref}\n")
295 out.WriteString("\n")
296 out.WriteString("\\hypersetup{colorlinks,%\n")
297 out.WriteString(" citecolor=black,%\n")
298 out.WriteString(" filecolor=black,%\n")
299 out.WriteString(" linkcolor=black,%\n")
300 out.WriteString(" urlcolor=black,%\n")
301 out.WriteString(" pdfstartview=FitH,%\n")
302 out.WriteString(" breaklinks=true,%\n")
303 out.WriteString(" pdfauthor={Black Friday Markdown Processor}}\n")
304 out.WriteString("\n")
305 out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
306 out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
307 out.WriteString("\\parindent=0pt\n")
308 out.WriteString("\n")
309 out.WriteString("\\begin{document}\n")
310}
311
312func latexDocumentFooter(out *bytes.Buffer, opaque interface{}) {
313 out.WriteString("\n\\end{document}\n")
314}