all repos — grayfriday @ b97990f1bba5a0a50de2574c1bbc3697374a44f0

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