Skip to content

Commit 3006818

Browse files
plugin(table): add option to remove padding from tables (2) (#184)
1 parent 641563c commit 3006818

File tree

8 files changed

+177
-13
lines changed

8 files changed

+177
-13
lines changed

cli/html2markdown/cmd/cmd_convert.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ func (cli *CLI) convert(input []byte) ([]byte, error) {
112112
table.WithSpanCellBehavior(table.SpanCellBehavior(cli.config.tableSpanCellBehavior)),
113113
table.WithPresentationTables(cli.config.tablePresentationTables),
114114
table.WithNewlineBehavior(table.NewlineBehavior(cli.config.tableNewlineBehavior)),
115+
table.WithCellPaddingBehavior(table.CellPaddingBehavior(cli.config.tableCellPaddingBehavior)),
115116
),
116117
)
117118
}

cli/html2markdown/cmd/exec.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ type Config struct {
4040
// - - - - - Plugins - - - - - //
4141
enablePluginStrikethrough bool
4242

43-
enablePluginTable bool
44-
tableSkipEmptyRows bool
45-
tableHeaderPromotion bool
46-
tableSpanCellBehavior string
47-
tablePresentationTables bool
48-
tableNewlineBehavior string
43+
enablePluginTable bool
44+
tableSkipEmptyRows bool
45+
tableHeaderPromotion bool
46+
tableSpanCellBehavior string
47+
tablePresentationTables bool
48+
tableNewlineBehavior string
49+
tableCellPaddingBehavior string
4950
}
5051

5152
// Release holds the information (from the 3 ldflags) that goreleaser sets.

cli/html2markdown/cmd/flags.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func (cli *CLI) initFlags(progname string) {
9494
cli.flags.StringVar(&cli.config.tableSpanCellBehavior, "opt-table-span-cell-behavior", "", `[for --plugin-table] how colspan/rowspan should be rendered: "empty" or "mirror"`)
9595
cli.flags.BoolVar(&cli.config.tablePresentationTables, "opt-table-presentation-tables", false, `[for --plugin-table] whether tables with role="presentation" should be converted`)
9696
cli.flags.StringVar(&cli.config.tableNewlineBehavior, "opt-table-newline-behavior", "", `[for --plugin-table] how tables containing newlines should be handled: "skip" or "preserve"`)
97+
cli.flags.StringVar(&cli.config.tableCellPaddingBehavior, "opt-table-cell-padding-behavior", "", `[for --plugin-table] whether cells in the tables should include extra padding for visual continuity: "aligned", "minimal", or "none"`)
9798
}
9899

99100
func (cli *CLI) parseFlags(args []string) error {
@@ -120,6 +121,9 @@ func (cli *CLI) parseFlags(args []string) error {
120121
if cli.config.tableNewlineBehavior != "" && !cli.config.enablePluginTable {
121122
return fmt.Errorf("--opt-table-newline-behavior requires --plugin-table to be enabled")
122123
}
124+
if cli.config.tableCellPaddingBehavior != "" && !cli.config.enablePluginTable {
125+
return fmt.Errorf("--opt-table-cell-padding-behavior requires --plugin-table to be enabled")
126+
}
123127

124128
// TODO: use constant for flag name & use formatFlag
125129
// var keyStrongDelimiter = "opt-strong-delimiter"

cli/html2markdown/cmd/testdata/TestExecute/[general]_help_pipe/stdout.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ Use a HTML sanitizer before displaying the HTML in the browser!
7272
Make bold text. Should <strong> be indicated by two asterisks or two underscores?
7373
"**" or "__" (default: "**")
7474

75+
--opt-table-cell-padding-behavior
76+
[for --plugin-table] whether cells in the tables should include extra padding for visual continuity: "aligned", "minimal", or "none"
77+
7578
--opt-table-header-promotion
7679
[for --plugin-table] first row should be treated as a header
7780

cli/html2markdown/cmd/testdata/TestExecute/[general]_help_terminal/stdout.golden

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ Use a HTML sanitizer before displaying the HTML in the browser!
7272
Make bold text. Should <strong> be indicated by two asterisks or two underscores?
7373
"**" or "__" (default: "**")
7474

75+
--opt-table-cell-padding-behavior
76+
[for --plugin-table] whether cells in the tables should include extra padding for visual continuity: "aligned", "minimal", or "none"
77+
7578
--opt-table-header-promotion
7679
[for --plugin-table] first row should be treated as a header
7780

plugin/table/3_render.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ func (s *tablePlugin) writeHeaderUnderline(w converter.Writer, alignments []stri
7373
w.WriteString("-")
7474
}
7575

76-
w.WriteString(strings.Repeat("-", maxLength))
76+
if s.cellPaddingBehavior == CellPaddingBehaviorAligned {
77+
w.WriteString(strings.Repeat("-", maxLength))
78+
} else {
79+
w.WriteString("-")
80+
}
7781

7882
if align == "right" || align == "center" {
7983
w.WriteString(":")
@@ -90,16 +94,24 @@ func (s *tablePlugin) writeRow(w converter.Writer, counts []int, cells [][]byte)
9094
if isFirstCell {
9195
w.WriteString("|")
9296
}
93-
w.WriteString(" ")
94-
w.Write(cell)
9597

9698
currentCount := utf8.RuneCount(cell)
9799
filler := counts[i] - currentCount
98100

99-
if filler > 0 {
101+
if s.cellPaddingBehavior == CellPaddingBehaviorAligned || s.cellPaddingBehavior == CellPaddingBehaviorMinimal {
102+
w.WriteString(" ")
103+
}
104+
105+
w.Write(cell)
106+
107+
if s.cellPaddingBehavior == CellPaddingBehaviorAligned && filler > 0 {
100108
w.WriteString(strings.Repeat(" ", filler))
101109
}
102110

103-
w.WriteString(" |")
111+
if s.cellPaddingBehavior == CellPaddingBehaviorAligned || s.cellPaddingBehavior == CellPaddingBehaviorMinimal {
112+
w.WriteString(" ")
113+
}
114+
115+
w.WriteString("|")
104116
}
105117
}

plugin/table/table.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,39 @@ func WithNewlineBehavior(behavior NewlineBehavior) option {
7171
}
7272
}
7373

74+
type CellPaddingBehavior string
75+
76+
const (
77+
// CellPaddingBehaviorAligned adds visual padding to cells to make each column equal width (default).
78+
CellPaddingBehaviorAligned CellPaddingBehavior = "aligned"
79+
// CellPaddingBehaviorMinimal keeps a very small amount of padding to balance table readability while also reducing character count.
80+
CellPaddingBehaviorMinimal CellPaddingBehavior = "minimal"
81+
// CellPaddingBehaviorNone refrains from adding the padding to the cells.
82+
CellPaddingBehaviorNone CellPaddingBehavior = "none"
83+
)
84+
85+
// WithCellPaddingBehavior configures how to handle padding in table cells.
86+
// When set to "aligned" (default), every cell's text is padded to the width of the largest cell in its column.
87+
// When set to "minimal", every cell gets a space at the beginning and end of the cell for some minimal padding.
88+
// When set to "none", no extra padding is applied to cells.
89+
func WithCellPaddingBehavior(behavior CellPaddingBehavior) option {
90+
return func(p *tablePlugin) error {
91+
switch behavior {
92+
case "":
93+
// Allow empty string to default to "aligned"
94+
p.cellPaddingBehavior = CellPaddingBehaviorAligned
95+
return nil
96+
97+
case CellPaddingBehaviorAligned, CellPaddingBehaviorMinimal, CellPaddingBehaviorNone:
98+
p.cellPaddingBehavior = behavior
99+
return nil
100+
101+
default:
102+
return fmt.Errorf("unknown value %q for cell padding behavior", behavior)
103+
}
104+
}
105+
}
106+
74107
// WithSkipEmptyRows configures the table plugin to omit empty rows from the output.
75108
// An empty row is defined as a row where all cells contain no content or only whitespace.
76109
// When set to true, empty rows will be omitted from the output. When false (default),
@@ -113,6 +146,7 @@ type tablePlugin struct {
113146
skipEmptyRows bool
114147
promoteFirstRowToHeader bool
115148
convertPresentationTables bool
149+
cellPaddingBehavior CellPaddingBehavior
116150
}
117151

118152
func (p *tablePlugin) setError(err error) {
@@ -129,7 +163,9 @@ func (p *tablePlugin) getError() error {
129163
}
130164

131165
func NewTablePlugin(opts ...option) converter.Plugin {
132-
plugin := &tablePlugin{}
166+
plugin := &tablePlugin{
167+
cellPaddingBehavior: CellPaddingBehaviorAligned,
168+
}
133169
for _, opt := range opts {
134170
err := opt(plugin)
135171
if err != nil {

plugin/table/table_test.go

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ B1 B2
620620
}
621621
}
622622

623-
func TestTableWithNewlines(t *testing.T) {
623+
func TestOptionFunc_NewlineBehavior(t *testing.T) {
624624
testCases := []struct {
625625
desc string
626626
input string
@@ -689,3 +689,107 @@ A12
689689
})
690690
}
691691
}
692+
693+
func TestOptionFunc_CellPaddingBehavior(t *testing.T) {
694+
testCases := []struct {
695+
desc string
696+
input string
697+
options []option
698+
expected string
699+
}{
700+
{
701+
desc: "with padding behavior (default)",
702+
options: []option{},
703+
input: `
704+
<table>
705+
<tr>
706+
<td>This line has some way longer text than the other line below it.</td>
707+
<td>A2</td>
708+
</tr>
709+
<tr>
710+
<td>B1</td>
711+
<td>This one has longer text than the line above.</td>
712+
</tr>
713+
</table>
714+
`,
715+
expected: `
716+
| | |
717+
|------------------------------------------------------------------|-----------------------------------------------|
718+
| This line has some way longer text than the other line below it. | A2 |
719+
| B1 | This one has longer text than the line above. |
720+
`,
721+
},
722+
{
723+
desc: "with minimal padding behavior",
724+
options: []option{
725+
WithCellPaddingBehavior(CellPaddingBehaviorMinimal),
726+
},
727+
input: `
728+
<table>
729+
<tr>
730+
<td>This line has some way longer text than the other line below it.</td>
731+
<td>A2</td>
732+
</tr>
733+
<tr>
734+
<td>B1</td>
735+
<td>This one has longer text than the line above.</td>
736+
</tr>
737+
</table>
738+
`,
739+
expected: `
740+
| | |
741+
|---|---|
742+
| This line has some way longer text than the other line below it. | A2 |
743+
| B1 | This one has longer text than the line above. |
744+
`,
745+
},
746+
{
747+
desc: "without padding behavior",
748+
options: []option{
749+
WithCellPaddingBehavior(CellPaddingBehaviorNone),
750+
},
751+
input: `
752+
<table>
753+
<tr>
754+
<td>This line has some way longer text than the other line below it.</td>
755+
<td>A2</td>
756+
</tr>
757+
<tr>
758+
<td>B1</td>
759+
<td>This one has longer text than the line above.</td>
760+
</tr>
761+
</table>
762+
`,
763+
expected: `
764+
|||
765+
|---|---|
766+
|This line has some way longer text than the other line below it.|A2|
767+
|B1|This one has longer text than the line above.|
768+
`,
769+
},
770+
}
771+
772+
for _, tC := range testCases {
773+
t.Run(tC.desc, func(t *testing.T) {
774+
conv := converter.NewConverter(
775+
converter.WithPlugins(
776+
base.NewBasePlugin(),
777+
commonmark.NewCommonmarkPlugin(),
778+
NewTablePlugin(tC.options...),
779+
),
780+
)
781+
782+
output, err := conv.ConvertString(tC.input)
783+
if err != nil {
784+
t.Error(err)
785+
}
786+
787+
actual := strings.TrimSpace(output)
788+
expected := strings.TrimSpace(tC.expected)
789+
790+
if actual != expected {
791+
t.Errorf("expected\n%s\nbut got\n%s\n", expected, actual)
792+
}
793+
})
794+
}
795+
}

0 commit comments

Comments
 (0)