blackfriday/latex.go
Vytautas Šaltenis a9baf845f1 Unpublish and rename LinkType constants (#285)
* Unpublish and rename LinkType constants

The constants are only used in the parsing phase, they are not recorded
in the AST directly, so make them private. Improve their names along the
way. Fix tagLength to return two values instead of taking an output
parameter.

* autoLinkType -> autolinkType

And remove unnecessary comment.
2016-07-29 08:01:31 +03:00

337 lines
7.2 KiB
Go

//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//
//
//
// LaTeX rendering backend
//
//
package blackfriday
import (
"bytes"
"io"
)
// Latex is a type that implements the Renderer interface for LaTeX output.
//
// Do not create this directly, instead use the NewLatexRenderer function.
type Latex struct {
w bytes.Buffer
}
// NewLatexRenderer creates and configures a Latex object, which
// satisfies the Renderer interface.
//
// flags is a set of LATEX_* options ORed together (currently no such options
// are defined).
func NewLatexRenderer(flags int) *Latex {
var writer bytes.Buffer
return &Latex{
w: writer,
}
}
// render code chunks using verbatim, or listings if we have a language
func (r *Latex) BlockCode(text []byte, lang string) {
if lang == "" {
r.w.WriteString("\n\\begin{verbatim}\n")
} else {
r.w.WriteString("\n\\begin{lstlisting}[language=")
r.w.WriteString(lang)
r.w.WriteString("]\n")
}
r.w.Write(text)
if lang == "" {
r.w.WriteString("\n\\end{verbatim}\n")
} else {
r.w.WriteString("\n\\end{lstlisting}\n")
}
}
func (r *Latex) TitleBlock(text []byte) {
}
func (r *Latex) BlockQuote(text []byte) {
r.w.WriteString("\n\\begin{quotation}\n")
r.w.Write(text)
r.w.WriteString("\n\\end{quotation}\n")
}
func (r *Latex) BlockHtml(text []byte) {
// a pretty lame thing to do...
r.w.WriteString("\n\\begin{verbatim}\n")
r.w.Write(text)
r.w.WriteString("\n\\end{verbatim}\n")
}
func (r *Latex) BeginHeader(level int, id string) {
switch level {
case 1:
r.w.WriteString("\n\\section{")
case 2:
r.w.WriteString("\n\\subsection{")
case 3:
r.w.WriteString("\n\\subsubsection{")
case 4:
r.w.WriteString("\n\\paragraph{")
case 5:
r.w.WriteString("\n\\subparagraph{")
case 6:
r.w.WriteString("\n\\textbf{")
}
}
func (r *Latex) EndHeader(level int, id string, header []byte) {
r.w.WriteString("}\n")
}
func (r *Latex) HRule() {
r.w.WriteString("\n\\HRule\n")
}
func (r *Latex) BeginList(flags ListType) {
if flags&ListTypeOrdered != 0 {
r.w.WriteString("\n\\begin{enumerate}\n")
} else {
r.w.WriteString("\n\\begin{itemize}\n")
}
}
func (r *Latex) EndList(flags ListType) {
if flags&ListTypeOrdered != 0 {
r.w.WriteString("\n\\end{enumerate}\n")
} else {
r.w.WriteString("\n\\end{itemize}\n")
}
}
func (r *Latex) ListItem(text []byte, flags ListType) {
r.w.WriteString("\n\\item ")
r.w.Write(text)
}
func (r *Latex) BeginParagraph() {
r.w.WriteString("\n")
}
func (r *Latex) EndParagraph() {
r.w.WriteString("\n")
}
func (r *Latex) Table(header []byte, body []byte, columnData []CellAlignFlags) {
r.w.WriteString("\n\\begin{tabular}{")
for _, elt := range columnData {
switch elt {
case TableAlignmentLeft:
r.w.WriteByte('l')
case TableAlignmentRight:
r.w.WriteByte('r')
default:
r.w.WriteByte('c')
}
}
r.w.WriteString("}\n")
r.w.Write(header)
r.w.WriteString(" \\\\\n\\hline\n")
r.w.Write(body)
r.w.WriteString("\n\\end{tabular}\n")
}
func (r *Latex) TableRow(text []byte) {
r.w.WriteString(" \\\\\n")
r.w.Write(text)
}
func (r *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align CellAlignFlags) {
if out.Len() > 0 {
out.WriteString(" & ")
}
out.Write(text)
}
func (r *Latex) TableCell(out *bytes.Buffer, text []byte, align CellAlignFlags) {
if out.Len() > 0 {
out.WriteString(" & ")
}
out.Write(text)
}
// TODO: this
func (r *Latex) BeginFootnotes() {
}
// TODO: this
func (r *Latex) EndFootnotes() {
}
func (r *Latex) FootnoteItem(name, text []byte, flags ListType) {
}
func (r *Latex) AutoLink(link []byte, kind autolinkType) {
r.w.WriteString("\\href{")
if kind == emailAutolink {
r.w.WriteString("mailto:")
}
r.w.Write(link)
r.w.WriteString("}{")
r.w.Write(link)
r.w.WriteString("}")
}
func (r *Latex) CodeSpan(text []byte) {
r.w.WriteString("\\texttt{")
r.escapeSpecialChars(text)
r.w.WriteString("}")
}
func (r *Latex) DoubleEmphasis(text []byte) {
r.w.WriteString("\\textbf{")
r.w.Write(text)
r.w.WriteString("}")
}
func (r *Latex) Emphasis(text []byte) {
r.w.WriteString("\\textit{")
r.w.Write(text)
r.w.WriteString("}")
}
func (r *Latex) Image(link []byte, title []byte, alt []byte) {
if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
// treat it like a link
r.w.WriteString("\\href{")
r.w.Write(link)
r.w.WriteString("}{")
r.w.Write(alt)
r.w.WriteString("}")
} else {
r.w.WriteString("\\includegraphics{")
r.w.Write(link)
r.w.WriteString("}")
}
}
func (r *Latex) LineBreak() {
r.w.WriteString(" \\\\\n")
}
func (r *Latex) Link(link []byte, title []byte, content []byte) {
r.w.WriteString("\\href{")
r.w.Write(link)
r.w.WriteString("}{")
r.w.Write(content)
r.w.WriteString("}")
}
func (r *Latex) RawHtmlTag(tag []byte) {
}
func (r *Latex) TripleEmphasis(text []byte) {
r.w.WriteString("\\textbf{\\textit{")
r.w.Write(text)
r.w.WriteString("}}")
}
func (r *Latex) StrikeThrough(text []byte) {
r.w.WriteString("\\sout{")
r.w.Write(text)
r.w.WriteString("}")
}
// TODO: this
func (r *Latex) FootnoteRef(ref []byte, id int) {
}
func needsBackslash(c byte) bool {
for _, r := range []byte("_{}%$&\\~#") {
if c == r {
return true
}
}
return false
}
func (r *Latex) escapeSpecialChars(text []byte) {
for i := 0; i < len(text); i++ {
// directly copy normal characters
org := i
for i < len(text) && !needsBackslash(text[i]) {
i++
}
if i > org {
r.w.Write(text[org:i])
}
// escape a character
if i >= len(text) {
break
}
r.w.WriteByte('\\')
r.w.WriteByte(text[i])
}
}
func (r *Latex) Entity(entity []byte) {
// TODO: convert this into a unicode character or something
r.w.Write(entity)
}
func (r *Latex) NormalText(text []byte) {
r.escapeSpecialChars(text)
}
// header and footer
func (r *Latex) DocumentHeader() {
r.w.WriteString("\\documentclass{article}\n")
r.w.WriteString("\n")
r.w.WriteString("\\usepackage{graphicx}\n")
r.w.WriteString("\\usepackage{listings}\n")
r.w.WriteString("\\usepackage[margin=1in]{geometry}\n")
r.w.WriteString("\\usepackage[utf8]{inputenc}\n")
r.w.WriteString("\\usepackage{verbatim}\n")
r.w.WriteString("\\usepackage[normalem]{ulem}\n")
r.w.WriteString("\\usepackage{hyperref}\n")
r.w.WriteString("\n")
r.w.WriteString("\\hypersetup{colorlinks,%\n")
r.w.WriteString(" citecolor=black,%\n")
r.w.WriteString(" filecolor=black,%\n")
r.w.WriteString(" linkcolor=black,%\n")
r.w.WriteString(" urlcolor=black,%\n")
r.w.WriteString(" pdfstartview=FitH,%\n")
r.w.WriteString(" breaklinks=true,%\n")
r.w.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
r.w.WriteString(Version)
r.w.WriteString("}}\n")
r.w.WriteString("\n")
r.w.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
r.w.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
r.w.WriteString("\\parindent=0pt\n")
r.w.WriteString("\n")
r.w.WriteString("\\begin{document}\n")
}
func (r *Latex) DocumentFooter() {
r.w.WriteString("\n\\end{document}\n")
}
func (r *Latex) Render(ast *Node) []byte {
// TODO
return nil
}
func (r *Latex) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus {
// TODO
return GoToNext
}