Repository: jedib0t/go-pretty (go)

Issue:
Background color of last row continues to bottom border of table
**Describe the bug**

Background color of last row unexpectedly continues to the bottom border of rendered table. See the repro below.

**To Reproduce**

```go
package main

import (
	"os"

	"github.com/jedib0t/go-pretty/v6/table"
	"github.com/jedib0t/go-pretty/v6/text"
)

func main() {
	t := table.NewWriter()
	t.SetOutputMirror(os.Stdout)
	t.AppendHeader(table.Row{"Hello"})
	t.AppendRow(table.Row{"World"})
	t.SetStyle(table.StyleRounded)
	t.Style().Color.Row = text.Colors{text.Reset, text.BgHiBlack}
	t.Render()
}
```

**Expected behavior**
Only the "World" row is highlighted with `BgHiBlack`.

**Screenshots**
<img width="81" alt="image" src="https://user-images.githubusercontent.com/823277/208425234-dced8955-48f3-49ad-9beb-f2887ed73663.png">

As you see, the highlighted color continues in bottom border of table `╰───────╯`

**Software (please complete the following information):**
 - OS: macOS 11.7
 - GoLang Version 1.19

**Additional context**

I at first saw this issue in https://github.com/google/osv-scanner and noticed the issue happened in this package.

<img width="873" alt="image" src="https://user-images.githubusercontent.com/823277/208425565-a1176d12-a9ff-4769-aefe-ed2db7825d45.png">



Pull request:
table: option to avoid coloring borders/separators; fixes #248
## Proposed Changes
  - provide new option in Style.Options to avoid coloring Borders and Separators

Fixes #248.


Patch:
diff --git a/table/render.go b/table/render.go
index 8a13df5..d58f189 100644
--- a/table/render.go
+++ b/table/render.go
@@ -365,15 +365,19 @@ func (t *Table) renderRowsHeader(out *strings.Builder) {
 func (t *Table) renderTitle(out *strings.Builder) {
 	if t.title != "" {
 		colors := t.style.Title.Colors
+		colorsBorder := colors
+		if t.style.Options.DoNotColorBordersAndSeparators {
+			colorsBorder = nil
+		}
 		rowLength := t.maxRowLength
 		if t.allowedRowLength != 0 && t.allowedRowLength < rowLength {
 			rowLength = t.allowedRowLength
 		}
 		if t.style.Options.DrawBorder {
 			lenBorder := rowLength - text.RuneWidthWithoutEscSequences(t.style.Box.TopLeft+t.style.Box.TopRight)
-			out.WriteString(colors.Sprint(t.style.Box.TopLeft))
-			out.WriteString(colors.Sprint(text.RepeatAndTrim(t.style.Box.MiddleHorizontal, lenBorder)))
-			out.WriteString(colors.Sprint(t.style.Box.TopRight))
+			out.WriteString(colorsBorder.Sprint(t.style.Box.TopLeft))
+			out.WriteString(colorsBorder.Sprint(text.RepeatAndTrim(t.style.Box.MiddleHorizontal, lenBorder)))
+			out.WriteString(colorsBorder.Sprint(t.style.Box.TopRight))
 		}
 
 		lenText := rowLength - text.RuneWidthWithoutEscSequences(t.style.Box.PaddingLeft+t.style.Box.PaddingRight)
@@ -382,12 +386,12 @@ func (t *Table) renderTitle(out *strings.Builder) {
 		}
 		titleText := text.WrapText(t.title, lenText)
 		for _, titleLine := range strings.Split(titleText, "\n") {
-			t.renderTitleLine(out, lenText, titleLine, colors)
+			t.renderTitleLine(out, lenText, titleLine, colors, colorsBorder)
 		}
 	}
 }
 
-func (t *Table) renderTitleLine(out *strings.Builder, lenText int, titleLine string, colors text.Colors) {
+func (t *Table) renderTitleLine(out *strings.Builder, lenText int, titleLine string, colors text.Colors, colorsBorder text.Colors) {
 	titleLine = strings.TrimSpace(titleLine)
 	titleLine = t.style.Title.Format.Apply(titleLine)
 	titleLine = t.style.Title.Align.Apply(titleLine, lenText)
@@ -397,10 +401,10 @@ func (t *Table) renderTitleLine(out *strings.Builder, lenText int, titleLine str
 		out.WriteRune('\n')
 	}
 	if t.style.Options.DrawBorder {
-		out.WriteString(colors.Sprint(t.style.Box.Left))
+		out.WriteString(colorsBorder.Sprint(t.style.Box.Left))
 	}
 	out.WriteString(colors.Sprint(titleLine))
 	if t.style.Options.DrawBorder {
-		out.WriteString(colors.Sprint(t.style.Box.Right))
+		out.WriteString(colorsBorder.Sprint(t.style.Box.Right))
 	}
 }
diff --git a/table/render_hint.go b/table/render_hint.go
index e585389..d32504b 100644
--- a/table/render_hint.go
+++ b/table/render_hint.go
@@ -16,6 +16,10 @@ type renderHint struct {
 	rowNumber         int  // the row number/index
 }
 
+func (h *renderHint) isBorderOrSeparator() bool {
+	return h.isBorderTop || h.isSeparatorRow || h.isBorderBottom
+}
+
 func (h *renderHint) isRegularRow() bool {
 	return !h.isHeaderRow && !h.isFooterRow
 }
diff --git a/table/style.go b/table/style.go
index 2c1795c..b55b04d 100644
--- a/table/style.go
+++ b/table/style.go
@@ -703,6 +703,10 @@ var (
 // Options defines the global options that determine how the Table is
 // rendered.
 type Options struct {
+	// DoNotColorBordersAndSeparators disables coloring all the borders and row
+	// or column separators.
+	DoNotColorBordersAndSeparators bool
+
 	// DrawBorder enables or disables drawing the border around the Table.
 	// Example of a table where it is disabled:
 	//     # │ FIRST NAME │ LAST NAME │ SALARY │
diff --git a/table/table.go b/table/table.go
index 297de86..2369199 100644
--- a/table/table.go
+++ b/table/table.go
@@ -326,7 +326,9 @@ func (t *Table) getAutoIndexColumnIDs() rowStr {
 }
 
 func (t *Table) getBorderColors(hint renderHint) text.Colors {
-	if hint.isHeaderRow {
+	if t.style.Options.DoNotColorBordersAndSeparators {
+		return nil
+	} else if hint.isHeaderRow {
 		return t.style.Color.Header
 	} else if hint.isFooterRow {
 		return t.style.Color.Footer
@@ -381,6 +383,9 @@ func (t *Table) getBorderRight(hint renderHint) string {
 }
 
 func (t *Table) getColumnColors(colIdx int, hint renderHint) text.Colors {
+	if hint.isBorderOrSeparator() && t.style.Options.DoNotColorBordersAndSeparators {
+		return text.Colors{} // not nil to force caller to paint with no colors
+	}
 	if t.rowPainter != nil && hint.isRegularNonSeparatorRow() && !t.isIndexColumn(colIdx, hint) {
 		colors := t.rowsColors[hint.rowNumber-1]
 		if colors != nil {
@@ -578,7 +583,9 @@ func (t *Table) getRowConfig(hint renderHint) RowConfig {
 }
 
 func (t *Table) getSeparatorColors(hint renderHint) text.Colors {
-	if hint.isHeaderRow {
+	if t.style.Options.DoNotColorBordersAndSeparators {
+		return nil
+	} else if hint.isHeaderRow {
 		return t.style.Color.Header
 	} else if hint.isFooterRow {
 		return t.style.Color.Footer


Test patch:
diff --git a/table/render_test.go b/table/render_test.go
index 4f3df8d..ceb8041 100644
--- a/table/render_test.go
+++ b/table/render_test.go
@@ -1008,6 +1008,40 @@ func TestTable_Render_Colored(t *testing.T) {
 		)
 	})
 
+	t.Run("with borders and separators not colored", func(t *testing.T) {
+		tw := NewWriter()
+		tw.AppendHeader(testHeader)
+		tw.AppendRows(testRows)
+		tw.AppendRow(testRowMultiLine)
+		tw.AppendFooter(testFooter)
+		tw.SetTitle(testTitle1)
+		tw.Style().Title.Colors = text.Colors{text.FgYellow}
+		tw.Style().Color = ColorOptions{
+			Header:       text.Colors{text.FgRed},
+			Row:          text.Colors{text.FgGreen},
+			RowAlternate: text.Colors{text.FgHiGreen},
+			Footer:       text.Colors{text.FgBlue},
+		}
+		tw.Style().Options.DoNotColorBordersAndSeparators = true
+
+		compareOutputColored(t, tw.Render(), ""+
+			"+---------------------------------------------------------------------+\n"+
+			"|\x1b[33m Game of Thrones                                                     \x1b[0m|\n"+
+			"+-----+------------+-----------+--------+-----------------------------+\n"+
+			"|\x1b[31m   # \x1b[0m|\x1b[31m FIRST NAME \x1b[0m|\x1b[31m LAST NAME \x1b[0m|\x1b[31m SALARY \x1b[0m|\x1b[31m                             \x1b[0m|\n"+
+			"+-----+------------+-----------+--------+-----------------------------+\n"+
+			"|\x1b[32m   1 \x1b[0m|\x1b[32m Arya       \x1b[0m|\x1b[32m Stark     \x1b[0m|\x1b[32m   3000 \x1b[0m|\x1b[32m                             \x1b[0m|\n"+
+			"|\x1b[92m  20 \x1b[0m|\x1b[92m Jon        \x1b[0m|\x1b[92m Snow      \x1b[0m|\x1b[92m   2000 \x1b[0m|\x1b[92m You know nothing, Jon Snow! \x1b[0m|\n"+
+			"|\x1b[32m 300 \x1b[0m|\x1b[32m Tyrion     \x1b[0m|\x1b[32m Lannister \x1b[0m|\x1b[32m   5000 \x1b[0m|\x1b[32m                             \x1b[0m|\n"+
+			"|\x1b[92m   0 \x1b[0m|\x1b[92m Winter     \x1b[0m|\x1b[92m Is        \x1b[0m|\x1b[92m      0 \x1b[0m|\x1b[92m Coming.                     \x1b[0m|\n"+
+			"|\x1b[92m     \x1b[0m|\x1b[92m            \x1b[0m|\x1b[92m           \x1b[0m|\x1b[92m        \x1b[0m|\x1b[92m The North Remembers!        \x1b[0m|\n"+
+			"|\x1b[92m     \x1b[0m|\x1b[92m            \x1b[0m|\x1b[92m           \x1b[0m|\x1b[92m        \x1b[0m|\x1b[92m This is known.              \x1b[0m|\n"+
+			"+-----+------------+-----------+--------+-----------------------------+\n"+
+			"|\x1b[34m     \x1b[0m|\x1b[34m            \x1b[0m|\x1b[34m TOTAL     \x1b[0m|\x1b[34m  10000 \x1b[0m|\x1b[34m                             \x1b[0m|\n"+
+			"+-----+------------+-----------+--------+-----------------------------+",
+		)
+	})
+
 	t.Run("column customizations", func(t *testing.T) {
 		tw := NewWriter()
 		tw.AppendHeader(testHeader)