all repos — grayfriday @ d1b544e27876215d6e6dd56bdf7aebb3d2f340a9

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	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}