vendor/github.com/cpuguy83/go-md2man/md2man/roff.go
changeset 246 0998f404dd31
parent 245 910f00ab2799
child 247 1ca743b3eb80
--- a/vendor/github.com/cpuguy83/go-md2man/md2man/roff.go	Sun Jan 13 12:58:50 2019 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,345 +0,0 @@
-package md2man
-
-import (
-	"fmt"
-	"io"
-	"os"
-	"strings"
-
-	"github.com/russross/blackfriday"
-)
-
-// roffRenderer implements the blackfriday.Renderer interface for creating
-// roff format (manpages) from markdown text
-type roffRenderer struct {
-	extensions   blackfriday.Extensions
-	listCounters []int
-	firstHeader  bool
-	defineTerm   bool
-	listDepth    int
-}
-
-const (
-	titleHeader      = ".TH "
-	topLevelHeader   = "\n\n.SH "
-	secondLevelHdr   = "\n.SH "
-	otherHeader      = "\n.SS "
-	crTag            = "\n"
-	emphTag          = "\\fI"
-	emphCloseTag     = "\\fP"
-	strongTag        = "\\fB"
-	strongCloseTag   = "\\fP"
-	breakTag         = "\n.br\n"
-	paraTag          = "\n.PP\n"
-	hruleTag         = "\n.ti 0\n\\l'\\n(.lu'\n"
-	linkTag          = "\n\\[la]"
-	linkCloseTag     = "\\[ra]"
-	codespanTag      = "\\fB\\fC"
-	codespanCloseTag = "\\fR"
-	codeTag          = "\n.PP\n.RS\n\n.nf\n"
-	codeCloseTag     = "\n.fi\n.RE\n"
-	quoteTag         = "\n.PP\n.RS\n"
-	quoteCloseTag    = "\n.RE\n"
-	listTag          = "\n.RS\n"
-	listCloseTag     = "\n.RE\n"
-	arglistTag       = "\n.TP\n"
-	tableStart       = "\n.TS\nallbox;\n"
-	tableEnd         = ".TE\n"
-	tableCellStart   = "T{\n"
-	tableCellEnd     = "\nT}\n"
-)
-
-// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents
-// from markdown
-func NewRoffRenderer() *roffRenderer { // nolint: golint
-	var extensions blackfriday.Extensions
-
-	extensions |= blackfriday.NoIntraEmphasis
-	extensions |= blackfriday.Tables
-	extensions |= blackfriday.FencedCode
-	extensions |= blackfriday.SpaceHeadings
-	extensions |= blackfriday.Footnotes
-	extensions |= blackfriday.Titleblock
-	extensions |= blackfriday.DefinitionLists
-	return &roffRenderer{
-		extensions: extensions,
-	}
-}
-
-// GetExtensions returns the list of extensions used by this renderer implementation
-func (r *roffRenderer) GetExtensions() blackfriday.Extensions {
-	return r.extensions
-}
-
-// RenderHeader handles outputting the header at document start
-func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) {
-	// disable hyphenation
-	out(w, ".nh\n")
-}
-
-// RenderFooter handles outputting the footer at the document end; the roff
-// renderer has no footer information
-func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) {
-}
-
-// RenderNode is called for each node in a markdown document; based on the node
-// type the equivalent roff output is sent to the writer
-func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
-
-	var walkAction = blackfriday.GoToNext
-
-	switch node.Type {
-	case blackfriday.Text:
-		r.handleText(w, node, entering)
-	case blackfriday.Softbreak:
-		out(w, crTag)
-	case blackfriday.Hardbreak:
-		out(w, breakTag)
-	case blackfriday.Emph:
-		if entering {
-			out(w, emphTag)
-		} else {
-			out(w, emphCloseTag)
-		}
-	case blackfriday.Strong:
-		if entering {
-			out(w, strongTag)
-		} else {
-			out(w, strongCloseTag)
-		}
-	case blackfriday.Link:
-		if !entering {
-			out(w, linkTag+string(node.LinkData.Destination)+linkCloseTag)
-		}
-	case blackfriday.Image:
-		// ignore images
-		walkAction = blackfriday.SkipChildren
-	case blackfriday.Code:
-		out(w, codespanTag)
-		escapeSpecialChars(w, node.Literal)
-		out(w, codespanCloseTag)
-	case blackfriday.Document:
-		break
-	case blackfriday.Paragraph:
-		// roff .PP markers break lists
-		if r.listDepth > 0 {
-			return blackfriday.GoToNext
-		}
-		if entering {
-			out(w, paraTag)
-		} else {
-			out(w, crTag)
-		}
-	case blackfriday.BlockQuote:
-		if entering {
-			out(w, quoteTag)
-		} else {
-			out(w, quoteCloseTag)
-		}
-	case blackfriday.Heading:
-		r.handleHeading(w, node, entering)
-	case blackfriday.HorizontalRule:
-		out(w, hruleTag)
-	case blackfriday.List:
-		r.handleList(w, node, entering)
-	case blackfriday.Item:
-		r.handleItem(w, node, entering)
-	case blackfriday.CodeBlock:
-		out(w, codeTag)
-		escapeSpecialChars(w, node.Literal)
-		out(w, codeCloseTag)
-	case blackfriday.Table:
-		r.handleTable(w, node, entering)
-	case blackfriday.TableCell:
-		r.handleTableCell(w, node, entering)
-	case blackfriday.TableHead:
-	case blackfriday.TableBody:
-	case blackfriday.TableRow:
-		// no action as cell entries do all the nroff formatting
-		return blackfriday.GoToNext
-	default:
-		fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String())
-	}
-	return walkAction
-}
-
-func (r *roffRenderer) handleText(w io.Writer, node *blackfriday.Node, entering bool) {
-	var (
-		start, end string
-	)
-	// handle special roff table cell text encapsulation
-	if node.Parent.Type == blackfriday.TableCell {
-		if len(node.Literal) > 30 {
-			start = tableCellStart
-			end = tableCellEnd
-		} else {
-			// end rows that aren't terminated by "tableCellEnd" with a cr if end of row
-			if node.Parent.Next == nil && !node.Parent.IsHeader {
-				end = crTag
-			}
-		}
-	}
-	out(w, start)
-	escapeSpecialChars(w, node.Literal)
-	out(w, end)
-}
-
-func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, entering bool) {
-	if entering {
-		switch node.Level {
-		case 1:
-			if !r.firstHeader {
-				out(w, titleHeader)
-				r.firstHeader = true
-				break
-			}
-			out(w, topLevelHeader)
-		case 2:
-			out(w, secondLevelHdr)
-		default:
-			out(w, otherHeader)
-		}
-	}
-}
-
-func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) {
-	openTag := listTag
-	closeTag := listCloseTag
-	if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
-		// tags for definition lists handled within Item node
-		openTag = ""
-		closeTag = ""
-	}
-	if entering {
-		r.listDepth++
-		if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
-			r.listCounters = append(r.listCounters, 1)
-		}
-		out(w, openTag)
-	} else {
-		if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
-			r.listCounters = r.listCounters[:len(r.listCounters)-1]
-		}
-		out(w, closeTag)
-		r.listDepth--
-	}
-}
-
-func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering bool) {
-	if entering {
-		if node.ListFlags&blackfriday.ListTypeOrdered != 0 {
-			out(w, fmt.Sprintf(".IP \"%3d.\" 5\n", r.listCounters[len(r.listCounters)-1]))
-			r.listCounters[len(r.listCounters)-1]++
-		} else if node.ListFlags&blackfriday.ListTypeDefinition != 0 {
-			// state machine for handling terms and following definitions
-			// since blackfriday does not distinguish them properly, nor
-			// does it seperate them into separate lists as it should
-			if !r.defineTerm {
-				out(w, arglistTag)
-				r.defineTerm = true
-			} else {
-				r.defineTerm = false
-			}
-		} else {
-			out(w, ".IP \\(bu 2\n")
-		}
-	} else {
-		out(w, "\n")
-	}
-}
-
-func (r *roffRenderer) handleTable(w io.Writer, node *blackfriday.Node, entering bool) {
-	if entering {
-		out(w, tableStart)
-		//call walker to count cells (and rows?) so format section can be produced
-		columns := countColumns(node)
-		out(w, strings.Repeat("l ", columns)+"\n")
-		out(w, strings.Repeat("l ", columns)+".\n")
-	} else {
-		out(w, tableEnd)
-	}
-}
-
-func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, entering bool) {
-	var (
-		start, end string
-	)
-	if node.IsHeader {
-		start = codespanTag
-		end = codespanCloseTag
-	}
-	if entering {
-		if node.Prev != nil && node.Prev.Type == blackfriday.TableCell {
-			out(w, "\t"+start)
-		} else {
-			out(w, start)
-		}
-	} else {
-		// need to carriage return if we are at the end of the header row
-		if node.IsHeader && node.Next == nil {
-			end = end + crTag
-		}
-		out(w, end)
-	}
-}
-
-// because roff format requires knowing the column count before outputting any table
-// data we need to walk a table tree and count the columns
-func countColumns(node *blackfriday.Node) int {
-	var columns int
-
-	node.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
-		switch node.Type {
-		case blackfriday.TableRow:
-			if !entering {
-				return blackfriday.Terminate
-			}
-		case blackfriday.TableCell:
-			if entering {
-				columns++
-			}
-		default:
-		}
-		return blackfriday.GoToNext
-	})
-	return columns
-}
-
-func out(w io.Writer, output string) {
-	io.WriteString(w, output) // nolint: errcheck
-}
-
-func needsBackslash(c byte) bool {
-	for _, r := range []byte("-_&\\~") {
-		if c == r {
-			return true
-		}
-	}
-	return false
-}
-
-func escapeSpecialChars(w io.Writer, text []byte) {
-	for i := 0; i < len(text); i++ {
-		// escape initial apostrophe or period
-		if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') {
-			out(w, "\\&")
-		}
-
-		// directly copy normal characters
-		org := i
-
-		for i < len(text) && !needsBackslash(text[i]) {
-			i++
-		}
-		if i > org {
-			w.Write(text[org:i]) // nolint: errcheck
-		}
-
-		// escape a character
-		if i >= len(text) {
-			break
-		}
-
-		w.Write([]byte{'\\', text[i]}) // nolint: errcheck
-	}
-}