all repos — grayfriday @ 4bd8627b2ca34a46892d1f5bdf88daadf0609f06

blackfriday fork with a few changes

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