latex.go (view raw)
1//
2// Blackfriday Markdown Processor
3// Available at http://github.com/russross/blackfriday
4//
5// Copyright © 2011 Russ Ross <russ@russross.com>.
6// Distributed under the Simplified BSD License.
7// See README.md for details.
8//
9
10//
11//
12// LaTeX rendering backend
13//
14//
15
16package blackfriday
17
18import (
19 "bytes"
20)
21
22// Latex is a type that implements the Renderer interface for LaTeX output.
23//
24// Do not create this directly, instead use the LatexRenderer function.
25type Latex struct {
26 w HtmlWriter
27}
28
29// LatexRenderer creates and configures a Latex object, which
30// satisfies the Renderer interface.
31//
32// flags is a set of LATEX_* options ORed together (currently no such options
33// are defined).
34func LatexRenderer(flags int) Renderer {
35 var writer HtmlWriter
36 return &Latex{
37 w: writer,
38 }
39}
40
41func (r *Latex) CaptureWrites(processor func()) []byte {
42 var output bytes.Buffer
43 // preserve old captureBuff state for possible nested captures:
44 tmp := r.w.captureBuff
45 tmpd := r.w.dirty
46 r.w.captureBuff = &output
47 r.w.dirty = false
48 processor()
49 // restore:
50 r.w.captureBuff = tmp
51 r.w.dirty = tmpd
52 return output.Bytes()
53}
54
55func (r *Latex) CopyWrites(processor func()) []byte {
56 var output bytes.Buffer
57 r.w.copyBuff = &output
58 processor()
59 r.w.copyBuff = nil
60 return output.Bytes()
61}
62
63func (r *Latex) Write(b []byte) (int, error) {
64 return r.w.Write(b)
65}
66
67func (r *Latex) GetResult() []byte {
68 return r.w.output.Bytes()
69}
70
71func (r *Latex) GetFlags() HtmlFlags {
72 return 0
73}
74
75// render code chunks using verbatim, or listings if we have a language
76func (r *Latex) BlockCode(text []byte, lang string) {
77 if lang == "" {
78 r.w.WriteString("\n\\begin{verbatim}\n")
79 } else {
80 r.w.WriteString("\n\\begin{lstlisting}[language=")
81 r.w.WriteString(lang)
82 r.w.WriteString("]\n")
83 }
84 r.w.Write(text)
85 if lang == "" {
86 r.w.WriteString("\n\\end{verbatim}\n")
87 } else {
88 r.w.WriteString("\n\\end{lstlisting}\n")
89 }
90}
91
92func (r *Latex) TitleBlock(text []byte) {
93
94}
95
96func (r *Latex) BlockQuote(text []byte) {
97 r.w.WriteString("\n\\begin{quotation}\n")
98 r.w.Write(text)
99 r.w.WriteString("\n\\end{quotation}\n")
100}
101
102func (r *Latex) BlockHtml(text []byte) {
103 // a pretty lame thing to do...
104 r.w.WriteString("\n\\begin{verbatim}\n")
105 r.w.Write(text)
106 r.w.WriteString("\n\\end{verbatim}\n")
107}
108
109func (r *Latex) BeginHeader(level int, id string) {
110 switch level {
111 case 1:
112 r.w.WriteString("\n\\section{")
113 case 2:
114 r.w.WriteString("\n\\subsection{")
115 case 3:
116 r.w.WriteString("\n\\subsubsection{")
117 case 4:
118 r.w.WriteString("\n\\paragraph{")
119 case 5:
120 r.w.WriteString("\n\\subparagraph{")
121 case 6:
122 r.w.WriteString("\n\\textbf{")
123 }
124}
125
126func (r *Latex) EndHeader(level int, id string, header []byte) {
127 r.w.WriteString("}\n")
128}
129
130func (r *Latex) HRule() {
131 r.w.WriteString("\n\\HRule\n")
132}
133
134func (r *Latex) BeginList(flags ListType) {
135 if flags&ListTypeOrdered != 0 {
136 r.w.WriteString("\n\\begin{enumerate}\n")
137 } else {
138 r.w.WriteString("\n\\begin{itemize}\n")
139 }
140}
141
142func (r *Latex) EndList(flags ListType) {
143 if flags&ListTypeOrdered != 0 {
144 r.w.WriteString("\n\\end{enumerate}\n")
145 } else {
146 r.w.WriteString("\n\\end{itemize}\n")
147 }
148}
149
150func (r *Latex) ListItem(text []byte, flags ListType) {
151 r.w.WriteString("\n\\item ")
152 r.w.Write(text)
153}
154
155func (r *Latex) BeginParagraph() {
156 r.w.WriteString("\n")
157}
158
159func (r *Latex) EndParagraph() {
160 r.w.WriteString("\n")
161}
162
163func (r *Latex) Table(header []byte, body []byte, columnData []int) {
164 r.w.WriteString("\n\\begin{tabular}{")
165 for _, elt := range columnData {
166 switch elt {
167 case TableAlignmentLeft:
168 r.w.WriteByte('l')
169 case TableAlignmentRight:
170 r.w.WriteByte('r')
171 default:
172 r.w.WriteByte('c')
173 }
174 }
175 r.w.WriteString("}\n")
176 r.w.Write(header)
177 r.w.WriteString(" \\\\\n\\hline\n")
178 r.w.Write(body)
179 r.w.WriteString("\n\\end{tabular}\n")
180}
181
182func (r *Latex) TableRow(text []byte) {
183 if r.w.dirty {
184 r.w.WriteString(" \\\\\n")
185 }
186 r.w.Write(text)
187}
188
189func (r *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
190 if out.Len() > 0 {
191 out.WriteString(" & ")
192 }
193 out.Write(text)
194}
195
196func (r *Latex) TableCell(out *bytes.Buffer, text []byte, align int) {
197 if out.Len() > 0 {
198 out.WriteString(" & ")
199 }
200 out.Write(text)
201}
202
203// TODO: this
204func (r *Latex) BeginFootnotes() {
205}
206
207// TODO: this
208func (r *Latex) EndFootnotes() {
209}
210
211func (r *Latex) FootnoteItem(name, text []byte, flags ListType) {
212
213}
214
215func (r *Latex) AutoLink(link []byte, kind LinkType) {
216 r.w.WriteString("\\href{")
217 if kind == LinkTypeEmail {
218 r.w.WriteString("mailto:")
219 }
220 r.w.Write(link)
221 r.w.WriteString("}{")
222 r.w.Write(link)
223 r.w.WriteString("}")
224}
225
226func (r *Latex) CodeSpan(text []byte) {
227 r.w.WriteString("\\texttt{")
228 r.escapeSpecialChars(text)
229 r.w.WriteString("}")
230}
231
232func (r *Latex) DoubleEmphasis(text []byte) {
233 r.w.WriteString("\\textbf{")
234 r.w.Write(text)
235 r.w.WriteString("}")
236}
237
238func (r *Latex) Emphasis(text []byte) {
239 r.w.WriteString("\\textit{")
240 r.w.Write(text)
241 r.w.WriteString("}")
242}
243
244func (r *Latex) Image(link []byte, title []byte, alt []byte) {
245 if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
246 // treat it like a link
247 r.w.WriteString("\\href{")
248 r.w.Write(link)
249 r.w.WriteString("}{")
250 r.w.Write(alt)
251 r.w.WriteString("}")
252 } else {
253 r.w.WriteString("\\includegraphics{")
254 r.w.Write(link)
255 r.w.WriteString("}")
256 }
257}
258
259func (r *Latex) LineBreak() {
260 r.w.WriteString(" \\\\\n")
261}
262
263func (r *Latex) Link(link []byte, title []byte, content []byte) {
264 r.w.WriteString("\\href{")
265 r.w.Write(link)
266 r.w.WriteString("}{")
267 r.w.Write(content)
268 r.w.WriteString("}")
269}
270
271func (r *Latex) RawHtmlTag(tag []byte) {
272}
273
274func (r *Latex) TripleEmphasis(text []byte) {
275 r.w.WriteString("\\textbf{\\textit{")
276 r.w.Write(text)
277 r.w.WriteString("}}")
278}
279
280func (r *Latex) StrikeThrough(text []byte) {
281 r.w.WriteString("\\sout{")
282 r.w.Write(text)
283 r.w.WriteString("}")
284}
285
286// TODO: this
287func (r *Latex) FootnoteRef(ref []byte, id int) {
288}
289
290func needsBackslash(c byte) bool {
291 for _, r := range []byte("_{}%$&\\~#") {
292 if c == r {
293 return true
294 }
295 }
296 return false
297}
298
299func (r *Latex) escapeSpecialChars(text []byte) {
300 for i := 0; i < len(text); i++ {
301 // directly copy normal characters
302 org := i
303
304 for i < len(text) && !needsBackslash(text[i]) {
305 i++
306 }
307 if i > org {
308 r.w.Write(text[org:i])
309 }
310
311 // escape a character
312 if i >= len(text) {
313 break
314 }
315 r.w.WriteByte('\\')
316 r.w.WriteByte(text[i])
317 }
318}
319
320func (r *Latex) Entity(entity []byte) {
321 // TODO: convert this into a unicode character or something
322 r.w.Write(entity)
323}
324
325func (r *Latex) NormalText(text []byte) {
326 r.escapeSpecialChars(text)
327}
328
329// header and footer
330func (r *Latex) DocumentHeader() {
331 r.w.WriteString("\\documentclass{article}\n")
332 r.w.WriteString("\n")
333 r.w.WriteString("\\usepackage{graphicx}\n")
334 r.w.WriteString("\\usepackage{listings}\n")
335 r.w.WriteString("\\usepackage[margin=1in]{geometry}\n")
336 r.w.WriteString("\\usepackage[utf8]{inputenc}\n")
337 r.w.WriteString("\\usepackage{verbatim}\n")
338 r.w.WriteString("\\usepackage[normalem]{ulem}\n")
339 r.w.WriteString("\\usepackage{hyperref}\n")
340 r.w.WriteString("\n")
341 r.w.WriteString("\\hypersetup{colorlinks,%\n")
342 r.w.WriteString(" citecolor=black,%\n")
343 r.w.WriteString(" filecolor=black,%\n")
344 r.w.WriteString(" linkcolor=black,%\n")
345 r.w.WriteString(" urlcolor=black,%\n")
346 r.w.WriteString(" pdfstartview=FitH,%\n")
347 r.w.WriteString(" breaklinks=true,%\n")
348 r.w.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
349 r.w.WriteString(VERSION)
350 r.w.WriteString("}}\n")
351 r.w.WriteString("\n")
352 r.w.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
353 r.w.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
354 r.w.WriteString("\\parindent=0pt\n")
355 r.w.WriteString("\n")
356 r.w.WriteString("\\begin{document}\n")
357}
358
359func (r *Latex) DocumentFooter() {
360 r.w.WriteString("\n\\end{document}\n")
361}
362
363func (r *Latex) Render(ast *Node) []byte {
364 return nil
365}