From 0393242cc3aba41b3aafc14a18494c25d8311cf3 Mon Sep 17 00:00:00 2001 From: Pharis Date: Mon, 20 Jul 2020 13:26:12 -0700 Subject: [PATCH 1/2] Support for no white space. --- html2text.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/html2text.go b/html2text.go index 4398909..6df62f8 100644 --- a/html2text.go +++ b/html2text.go @@ -33,6 +33,7 @@ type PrettyTablesOptions struct { FooterAlignment int Alignment int ColumnAlignment []int + NoWhiteSapce bool NewLine string HeaderLine bool RowLine bool @@ -54,6 +55,7 @@ func NewPrettyTablesOptions() *PrettyTablesOptions { FooterAlignment: tablewriter.ALIGN_DEFAULT, Alignment: tablewriter.ALIGN_DEFAULT, ColumnAlignment: []int{}, + NoWhiteSapce: false, NewLine: tablewriter.NEWLINE, HeaderLine: true, RowLine: false, @@ -338,6 +340,7 @@ func (ctx *textifyTraverseContext) handleTableElement(node *html.Node) error { table.SetRowLine(options.RowLine) table.SetAutoMergeCells(options.AutoMergeCells) table.SetBorders(options.Borders) + table.SetNoWhiteSpace(options.NoWhiteSapce) } table.SetHeader(ctx.tableCtx.header) table.SetFooter(ctx.tableCtx.footer) From d61a567da86e9fd4854b8679111940aeb1c8a6e3 Mon Sep 17 00:00:00 2001 From: Pharis Date: Tue, 21 Jul 2020 09:38:04 -0700 Subject: [PATCH 2/2] Support for minimum table columns widths. --- html2text.go | 51 +++++++++++++++++++++++++++++++ html2text_test.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/html2text.go b/html2text.go index 6df62f8..0c543c6 100644 --- a/html2text.go +++ b/html2text.go @@ -2,7 +2,9 @@ package html2text import ( "bytes" + "fmt" "io" + "math" "regexp" "strings" "unicode" @@ -26,6 +28,7 @@ type PrettyTablesOptions struct { AutoWrapText bool ReflowDuringAutoWrap bool ColWidth int + MinColWidth int ColumnSeparator string RowSeparator string CenterSeparator string @@ -510,11 +513,43 @@ func (ctx *textifyTraverseContext) normalizeHrefLink(link string) string { // textuual representaitons separated by a single newline. func (ctx *textifyTraverseContext) renderEachChild(node *html.Node) (string, error) { buf := &bytes.Buffer{} + + l := ctx.options.PrettyTablesOptions.MinColWidth + for c := node.FirstChild; c != nil; c = c.NextSibling { s, err := FromHTMLNode(c, ctx.options) if err != nil { return "", err } + + // See if a minimum width has been specified and pad as necessary. + if l > 0 && len(s) < l { + c := 0 + // Check alignment and pad appropriately. + switch ctx.options.PrettyTablesOptions.Alignment { + case tablewriter.ALIGN_LEFT: + c = l - len(s) + spc := strings.Repeat(" ", c) + s = fmt.Sprintf("%s%s", s, spc) + case tablewriter.ALIGN_RIGHT: + c = l - len(s) + spc := strings.Repeat(" ", c) + s = fmt.Sprintf("%s%s", spc, s) + case tablewriter.ALIGN_CENTER: + ls := len(s) + c := 0.0 // We need to use a float to have the division work properly here, so declare a local scope variable named c rather than use the int version of c from the parent. + c = math.Floor(float64(l-ls) / 2.0) + spc := strings.Repeat(" ", int(c)) + s = fmt.Sprintf("%s%s", spc, s) + c = math.Ceil(float64(l-ls) / 2.0) + spc = strings.Repeat(" ", int(c)) + s = fmt.Sprintf("%s%s", s, spc) + case tablewriter.ALIGN_DEFAULT: // Default to left alignment. + c = l - len(s) + spc := strings.Repeat(" ", c) + s = fmt.Sprintf("%s%s", s, spc) + } + } if _, err = buf.WriteString(s); err != nil { return "", err } @@ -527,6 +562,22 @@ func (ctx *textifyTraverseContext) renderEachChild(node *html.Node) (string, err return buf.String(), nil } +// largestChildWidth - Returns the width (in characters) of the largest child of a node. +func (ctx *textifyTraverseContext) largestChildWidth(node *html.Node) (int, error) { + l := 0 + for c := node.FirstChild; c != nil; c = c.NextSibling { + s, err := FromHTMLNode(c, ctx.options) + if err != nil { + return l, err + } + + if len(s) > l { + l = len(s) + } + } + return l, nil +} + func getAttrVal(node *html.Node, attrName string) string { for _, attr := range node.Attr { if attr.Key == attrName { diff --git a/html2text_test.go b/html2text_test.go index 452b45e..e04fc2a 100644 --- a/html2text_test.go +++ b/html2text_test.go @@ -9,6 +9,8 @@ import ( "regexp" "strings" "testing" + + "github.com/olekukonko/tablewriter" ) const destPath = "testdata" @@ -337,6 +339,79 @@ Table 2 Header 1 Table 2 Header 2 Table 2 Footer 1 Table 2 Footer 2 Table 2 Row PrettyTables: true, PrettyTablesOptions: NewPrettyTablesOptions(), } + + // Check pretty tabular ASCII version. + if msg, err := wantString(testCase.input, testCase.tabularOutput, options); err != nil { + t.Error(err) + } else if len(msg) > 0 { + t.Log(msg) + } + + // Check plain version. + if msg, err := wantString(testCase.input, testCase.plaintextOutput); err != nil { + t.Error(err) + } else if len(msg) > 0 { + t.Log(msg) + } + } +} + +func TestMinColWidthTable(t *testing.T) { + testCases := []struct { + input string + tabularOutput string + plaintextOutput string + alignment string + }{ + { + "
HelloWorld!
", + // Empty table + // +--+--+ + // | | | + // +--+--+ + "+------------+------------+\n| Hello | World! |\n+------------+------------+", + "Hello World!", + "Left", + }, + { + "
HelloWorld!
", + // Empty table + // +--+--+ + // | | | + // +--+--+ + "+------------+------------+\n| Hello | World! |\n+------------+------------+", + "Hello World!", + "Right", + }, + { + "
HelloWorld!
", + // Empty table + // +--+--+ + // | | | + // +--+--+ + "+------------+------------+\n| Hello | World! |\n+------------+------------+", + "Hello World!", + "Center", + }, + } + + for _, testCase := range testCases { + options := Options{ + PrettyTables: true, + PrettyTablesOptions: NewPrettyTablesOptions(), + } + options.PrettyTablesOptions.MinColWidth = 10 + + switch testCase.alignment { + case "Left": + options.PrettyTablesOptions.Alignment = tablewriter.ALIGN_LEFT + case "Right": + options.PrettyTablesOptions.Alignment = tablewriter.ALIGN_RIGHT + case "Center": + options.PrettyTablesOptions.Alignment = tablewriter.ALIGN_CENTER + default: + options.PrettyTablesOptions.Alignment = tablewriter.ALIGN_DEFAULT + } // Check pretty tabular ASCII version. if msg, err := wantString(testCase.input, testCase.tabularOutput, options); err != nil { t.Error(err) @@ -351,6 +426,7 @@ Table 2 Header 1 Table 2 Header 2 Table 2 Footer 1 Table 2 Footer 2 Table 2 Row t.Log(msg) } } + } func TestStrippingLists(t *testing.T) {