all repos — grayfriday @ 1e40ebaf472ae0587bc0c5efb72a807279df4e12

blackfriday fork with a few changes

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 []byte, level int, opaque interface{}) {
 80	switch level {
 81	case 1:
 82		out.WriteString("\n\\section{")
 83	case 2:
 84		out.WriteString("\n\\subsection{")
 85	case 3:
 86		out.WriteString("\n\\subsubsection{")
 87	case 4:
 88		out.WriteString("\n\\paragraph{")
 89	case 5:
 90		out.WriteString("\n\\subparagraph{")
 91	case 6:
 92		out.WriteString("\n\\textbf{")
 93	}
 94	out.Write(text)
 95	out.WriteString("}\n")
 96}
 97
 98func latexHRule(out *bytes.Buffer, opaque interface{}) {
 99	out.WriteString("\n\\HRule\n")
100}
101
102func latexList(out *bytes.Buffer, text []byte, flags int, opaque interface{}) {
103	if flags&LIST_TYPE_ORDERED != 0 {
104		out.WriteString("\n\\begin{enumerate}\n")
105	} else {
106		out.WriteString("\n\\begin{itemize}\n")
107	}
108	out.Write(text)
109	if flags&LIST_TYPE_ORDERED != 0 {
110		out.WriteString("\n\\end{enumerate}\n")
111	} else {
112		out.WriteString("\n\\end{itemize}\n")
113	}
114}
115
116func latexListItem(out *bytes.Buffer, text []byte, flags int, opaque interface{}) {
117	out.WriteString("\n\\item ")
118	out.Write(text)
119}
120
121func latexParagraph(out *bytes.Buffer, text []byte, opaque interface{}) {
122	out.WriteString("\n")
123	out.Write(text)
124	out.WriteString("\n")
125}
126
127func latexTable(out *bytes.Buffer, header []byte, body []byte, columnData []int, opaque interface{}) {
128	out.WriteString("\n\\begin{tabular}{")
129	for _, elt := range columnData {
130		switch elt {
131		case TABLE_ALIGNMENT_LEFT:
132			out.WriteByte('l')
133		case TABLE_ALIGNMENT_RIGHT:
134			out.WriteByte('r')
135		default:
136			out.WriteByte('c')
137		}
138	}
139	out.WriteString("}\n")
140	out.Write(header)
141	out.WriteString(" \\\\\n\\hline\n")
142	out.Write(body)
143	out.WriteString("\n\\end{tabular}\n")
144}
145
146func latexTableRow(out *bytes.Buffer, text []byte, opaque interface{}) {
147	if out.Len() > 0 {
148		out.WriteString(" \\\\\n")
149	}
150	out.Write(text)
151}
152
153func latexTableCell(out *bytes.Buffer, text []byte, align int, opaque interface{}) {
154	if out.Len() > 0 {
155		out.WriteString(" & ")
156	}
157	out.Write(text)
158}
159
160func latexAutoLink(out *bytes.Buffer, link []byte, kind int, opaque interface{}) int {
161	out.WriteString("\\href{")
162	if kind == LINK_TYPE_EMAIL {
163		out.WriteString("mailto:")
164	}
165	out.Write(link)
166	out.WriteString("}{")
167	out.Write(link)
168	out.WriteString("}")
169	return 1
170}
171
172func latexCodeSpan(out *bytes.Buffer, text []byte, opaque interface{}) int {
173	out.WriteString("\\texttt{")
174	escapeSpecialChars(out, text)
175	out.WriteString("}")
176	return 1
177}
178
179func latexDoubleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) int {
180	out.WriteString("\\textbf{")
181	out.Write(text)
182	out.WriteString("}")
183	return 1
184}
185
186func latexEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) int {
187	out.WriteString("\\textit{")
188	out.Write(text)
189	out.WriteString("}")
190	return 1
191}
192
193func latexImage(out *bytes.Buffer, link []byte, title []byte, alt []byte, opaque interface{}) int {
194	if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
195		// treat it like a link
196		out.WriteString("\\href{")
197		out.Write(link)
198		out.WriteString("}{")
199		out.Write(alt)
200		out.WriteString("}")
201	} else {
202		out.WriteString("\\includegraphics{")
203		out.Write(link)
204		out.WriteString("}")
205	}
206	return 1
207}
208
209func latexLineBreak(out *bytes.Buffer, opaque interface{}) int {
210	out.WriteString(" \\\\\n")
211	return 1
212}
213
214func latexLink(out *bytes.Buffer, link []byte, title []byte, content []byte, opaque interface{}) int {
215	out.WriteString("\\href{")
216	out.Write(link)
217	out.WriteString("}{")
218	out.Write(content)
219	out.WriteString("}")
220	return 1
221}
222
223func latexRawHtmlTag(out *bytes.Buffer, tag []byte, opaque interface{}) int {
224	return 0
225}
226
227func latexTripleEmphasis(out *bytes.Buffer, text []byte, opaque interface{}) int {
228	out.WriteString("\\textbf{\\textit{")
229	out.Write(text)
230	out.WriteString("}}")
231	return 1
232}
233
234func latexStrikeThrough(out *bytes.Buffer, text []byte, opaque interface{}) int {
235	out.WriteString("\\sout{")
236	out.Write(text)
237	out.WriteString("}")
238	return 1
239}
240
241func needsBackslash(c byte) bool {
242	for _, r := range []byte("_{}%$&\\~") {
243		if c == r {
244			return true
245		}
246	}
247	return false
248}
249
250func escapeSpecialChars(out *bytes.Buffer, text []byte) {
251	for i := 0; i < len(text); i++ {
252		// directly copy normal characters
253		org := i
254
255		for i < len(text) && !needsBackslash(text[i]) {
256			i++
257		}
258		if i > org {
259			out.Write(text[org:i])
260		}
261
262		// escape a character
263		if i >= len(text) {
264			break
265		}
266		out.WriteByte('\\')
267		out.WriteByte(text[i])
268	}
269}
270
271func latexNormalText(out *bytes.Buffer, text []byte, opaque interface{}) {
272	escapeSpecialChars(out, text)
273}
274
275// header and footer
276func latexDocumentHeader(out *bytes.Buffer, opaque interface{}) {
277	out.WriteString("\\documentclass{article}\n")
278	out.WriteString("\n")
279	out.WriteString("\\usepackage{graphicx}\n")
280	out.WriteString("\\usepackage{listings}\n")
281	out.WriteString("\\usepackage[margin=1in]{geometry}\n")
282	out.WriteString("\\usepackage[utf8]{inputenc}\n")
283	out.WriteString("\\usepackage{verbatim}\n")
284	out.WriteString("\\usepackage[normalem]{ulem}\n")
285	out.WriteString("\\usepackage{hyperref}\n")
286	out.WriteString("\n")
287	out.WriteString("\\hypersetup{colorlinks,%\n")
288	out.WriteString("  citecolor=black,%\n")
289	out.WriteString("  filecolor=black,%\n")
290	out.WriteString("  linkcolor=black,%\n")
291	out.WriteString("  urlcolor=black,%\n")
292	out.WriteString("  pdfstartview=FitH,%\n")
293	out.WriteString("  breaklinks=true,%\n")
294	out.WriteString("  pdfauthor={Black Friday Markdown Processor}}\n")
295	out.WriteString("\n")
296	out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
297	out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
298	out.WriteString("\\parindent=0pt\n")
299	out.WriteString("\n")
300	out.WriteString("\\begin{document}\n")
301}
302
303func latexDocumentFooter(out *bytes.Buffer, opaque interface{}) {
304	out.WriteString("\n\\end{document}\n")
305}