diff --git a/md2man/roff.go b/md2man/roff.go index c5061a7..6b58361 100644 --- a/md2man/roff.go +++ b/md2man/roff.go @@ -91,7 +91,7 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering switch node.Type { case blackfriday.Text: - r.handleText(w, node, entering) + escapeSpecialChars(w, node.Literal) case blackfriday.Softbreak: out(w, crTag) case blackfriday.Hardbreak: @@ -151,13 +151,13 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering 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 + case blackfriday.TableCell: + r.handleTableCell(w, node, entering) case blackfriday.HTMLSpan: // ignore other HTML tags default: @@ -166,27 +166,6 @@ func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering 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.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 { @@ -269,36 +248,41 @@ func (r *roffRenderer) handleTable(w io.Writer, node *blackfriday.Node, entering } 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 { + var start string if node.Prev != nil && node.Prev.Type == blackfriday.TableCell { - out(w, "\t"+start) - } else { - out(w, start) + start = "\t" } + if node.IsHeader { + start += codespanTag + } else if nodeLiteralSize(node) > 30 { + start += tableCellStart + } + out(w, start) } else { - if node.Next == nil { - if node.IsHeader { - // need to carriage return if we are at the end of the header row - end = end + crTag - } else if node.FirstChild == nil { - // empty cell: need to carriage return if we are at the end of - // the table, because handleText() will not be called if there's - // no text to preocess (which would otherwise add the trailing - // carriage return) - end = crTag - } + var end string + if node.IsHeader { + end = codespanCloseTag + } else if nodeLiteralSize(node) > 30 { + end = tableCellEnd + } + if node.Next == nil && end != tableCellEnd { + // Last cell: need to carriage return if we are at the end of the + // header row and content isn't wrapped in a "tablecell" + end += crTag } out(w, end) } } +func nodeLiteralSize(node *blackfriday.Node) int { + total := 0 + for n := node.FirstChild; n != nil; n = n.FirstChild { + total += len(n.Literal) + } + return total +} + // 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 { diff --git a/md2man/roff_test.go b/md2man/roff_test.go index 0121f56..949f8f1 100644 --- a/md2man/roff_test.go +++ b/md2man/roff_test.go @@ -298,14 +298,15 @@ row two x func TestTableWrapping(t *testing.T) { var tests = []string{ ` -| Col1 | Col2 | -| ----------- | ----------------------------------------- | -| row one | This is a short line. | -| row\|two | Col1 should not wrap. | -| row three | no\|wrap | -| row four | Inline _cursive_ should not wrap. | -| row five | Inline ` + "`code`" + ` should not wrap. | -| row six | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eu ipsum eget tortor aliquam accumsan. Quisque ac turpis convallis, sagittis urna ac, tempor est. Mauris nibh arcu, hendrerit id eros sed, sodales lacinia ex. Suspendisse sed condimentum urna, vitae mattis lectus. Mauris imperdiet magna vel purus pretium, id interdum libero. | +| Col1 | Col2 | +| ----------- | ------------------------------------------------ | +| row one | This is a short line. | +| row\|two | Col1 should not wrap. | +| row three | no\|wrap | +| row four | Inline _cursive_ should not wrap. | +| row five | Inline ` + "`code markup`" + ` should not wrap. | +| row six | A line that's longer than 30 characters with inline ` + "`code markup`" + ` or _cursive_ should not wrap. | +| row seven | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eu ipsum eget tortor aliquam accumsan. Quisque ac turpis convallis, sagittis urna ac, tempor est. Mauris nibh arcu, hendrerit id eros sed, sodales lacinia ex. Suspendisse sed condimentum urna, vitae mattis lectus. Mauris imperdiet magna vel purus pretium, id interdum libero. | `, `.nh @@ -318,8 +319,11 @@ row one This is a short line. row|two Col1 should not wrap. row three no|wrap row four Inline \fIcursive\fP should not wrap. -row five Inline \fB\fCcode\fR should not wrap. +row five Inline \fB\fCcode markup\fR should not wrap. row six T{ +A line that's longer than 30 characters with inline \fB\fCcode markup\fR or \fIcursive\fP should not wrap. +T} +row seven T{ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eu ipsum eget tortor aliquam accumsan. Quisque ac turpis convallis, sagittis urna ac, tempor est. Mauris nibh arcu, hendrerit id eros sed, sodales lacinia ex. Suspendisse sed condimentum urna, vitae mattis lectus. Mauris imperdiet magna vel purus pretium, id interdum libero. T} .TE