Skip to content

Commit

Permalink
Merge pull request #69 from thaJeztah/fix_breaking_cells
Browse files Browse the repository at this point in the history
Fix inline markup causing table cells to split
  • Loading branch information
cpuguy83 committed Jul 13, 2021
2 parents 817886f + 934d1d5 commit 92cd0d0
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 39 deletions.
70 changes: 31 additions & 39 deletions md2man/roff.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const (
dtTag = "\n.TP\n"
dd2Tag = "\n"
tableStart = "\n.TS\nallbox;\n"
tableEnd = "\n.TE\n"
tableEnd = ".TE\n"
tableCellStart = "T{\n"
tableCellEnd = "\nT}\n"
)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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.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 {
Expand Down Expand Up @@ -259,7 +238,7 @@ func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering
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
// 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")
Expand All @@ -269,28 +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 {
// need to carriage return if we are at the end of the header row
if node.IsHeader && node.Next == nil {
end = 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 {
Expand Down
59 changes: 59 additions & 0 deletions md2man/roff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,66 @@ zebra T{
Sometimes black and sometimes white, depending on the stripe.
T}
robin red.
.TE
`,
}
doTestsInlineParam(t, tests, TestParams{blackfriday.Tables})
}

func TestTableWithEmptyCell(t *testing.T) {
var tests = []string{
`
| Col1 | Col2 | Col3 |
|:---------|:-----:|:----:|
| row one | | |
| row two | x | |
`,
`.nh
.TS
allbox;
l l l
l l l .
\fB\fCCol1\fR \fB\fCCol2\fR \fB\fCCol3\fR
row one
row two x
.TE
`,
}
doTestsInlineParam(t, tests, TestParams{blackfriday.Tables})
}

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 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
.TS
allbox;
l l
l l .
\fB\fCCol1\fR \fB\fCCol2\fR
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 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
`,
}
Expand Down

0 comments on commit 92cd0d0

Please sign in to comment.