Skip to content

Commit

Permalink
Fix wrapping for longer cell content
Browse files Browse the repository at this point in the history
The previous fix worked for table cells that were not wrapped in
by "table-cell" markers, but didn't fix situations where the cell
content was more than 30 characters (and wrapped by table-cell
markers).

This patch moves the logic from handleText() to handleTableCell().
A utility function was added to calculate the total length of
content in the cell (taking into account that inline markup will
create "child nodes").

Checking for empty cells at the end of a row is no longer needed
because of this, as we can unconditionally add a cariage return
for the last cell (except for long lines, as table-cell markers
already have a newline included).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
  • Loading branch information
thaJeztah committed Jul 13, 2021
1 parent 9962558 commit 934d1d5
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 54 deletions.
74 changes: 29 additions & 45 deletions md2man/roff.go
Original file line number Diff line number Diff line change
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.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 @@ -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 {
Expand Down
22 changes: 13 additions & 9 deletions md2man/roff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 934d1d5

Please sign in to comment.