Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for distinct outer and inner unicode line styles #218

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 84 additions & 36 deletions table.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ type symbolID int

// Symbol ID constants which indicates the compass points, in order NESW, where
// a given symbol has connections to. The order here matches the order of box
// drawing unicode symbols.
// drawing unicode symbols. The symbols with a 'b' in their name have the
// connections before the b on the boundary and the ones after the b on the
// inside. E.g. symEWbS is an east-west connection on the (upper) boundary, and
// an inner line from that to the south.
const (
symEW symbolID = iota
symNS
Expand All @@ -66,6 +69,16 @@ const (
symESW
symNEW
symNESW
symEWb
symNSb
symESb
symSWb
symNEb
symNWb
symNSbE
symNSbW
symEWbS
symEWbN
)

type Table struct {
Expand Down Expand Up @@ -504,68 +517,87 @@ func (t *Table) center(i int, isFirstRow, isLastRow bool) string {
return t.syms[symEW]
}
if isFirstRow {
return t.syms[symES]
return t.syms[symESb]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t.syms[symESb] must we use map, can we not have a theme struct?

Copy link
Contributor Author

@gagern gagern Apr 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually a slice, not a map. Here are my thoughts on the trade-offs:

  1. Slice allows doing arithmetic on the offsets. So currently you can get from a non-boundary symbol to the corresponding boundary symbol by adding 11 to the symbol constant. I thought I would need that, but it turns out I don't.
  2. There are a number of places in this change here where I compute the index in one place, and then look it up in a another. That would no longer work with a struct, so we would always have to directly resolve to the symbol itself.
  3. If we add any form of character-changing API, that API might benefit from being able to refer to symbol roles as opposed to the current assignment for a given role. Maybe a pointer into a struct can serve that purpose, but it's less obvious.
  4. The current approach for turning the concise string representation into the slice is a straight-forward loop. With a struct it's harder to get the mapping right.

}
if isLastRow {
return t.syms[symNE]
return t.syms[symNEb]
}
return t.syms[symNES]
return t.syms[symNSbE]
}

if i == len(t.cs)-1 {
if !t.borders.Right {
return t.syms[symEW]
}
if isFirstRow {
return t.syms[symSW]
return t.syms[symSWb]
}
if isLastRow {
return t.syms[symNW]
return t.syms[symNWb]
}
return t.syms[symNSW]
return t.syms[symNSbW]
}

if isFirstRow {
return t.syms[symESW]
return t.syms[symEWbS]
}
if isLastRow {
return t.syms[symNEW]
return t.syms[symEWbN]
}
return t.syms[symNESW]
}

// Print line based on row width
func (t *Table) printLine(isFirst, isLast bool) {
fmt.Fprint(t.out, t.center(-1, isFirst, isLast))
horizontal := t.syms[symEW]
if isFirst || isLast {
horizontal = t.syms[symEWb]
}
for i := 0; i < len(t.cs); i++ {
v := t.cs[i]
fmt.Fprintf(t.out, "%s%s%s%s",
t.syms[symEW],
strings.Repeat(t.syms[symEW], v),
t.syms[symEW],
horizontal,
strings.Repeat(horizontal, v),
horizontal,
t.center(i, isFirst, isLast))
}
fmt.Fprint(t.out, t.newLine)
}

// Print line based on row width with our without cell separator
func (t *Table) printLineOptionalCellSeparators(nl bool, displayCellSeparator []bool) {
fmt.Fprint(t.out, t.syms[symNES])
centerSym := symNESW
for len(displayCellSeparator) < len(t.cs) {
displayCellSeparator = append(displayCellSeparator, true)
}
centerSym := symNSbE
if !displayCellSeparator[0] {
centerSym = symNSb
}
fmt.Fprint(t.out, t.syms[centerSym])
for i := 0; i < len(t.cs); i++ {
v := t.cs[i]
if i == len(t.cs)-1 {
centerSym = symNSW
}
if i > len(displayCellSeparator) || displayCellSeparator[i] {
if displayCellSeparator[i] {
// Display the cell separator
centerSym = symNESW
if i == len(t.cs)-1 {
centerSym = symNSbW
} else if !displayCellSeparator[i+1] {
centerSym = symNSW
}
fmt.Fprintf(t.out, "%s%s%s%s",
t.syms[symEW],
strings.Repeat(string(t.syms[symEW]), v),
t.syms[symEW],
t.syms[centerSym])
} else {
// Don't display the cell separator for this cell
centerSym = symNES
if i == len(t.cs)-1 {
centerSym = symNSb
} else if !displayCellSeparator[i+1] {
centerSym = symNS
}
fmt.Fprintf(t.out, "%s%s",
strings.Repeat(" ", v+2),
t.syms[centerSym])
Expand Down Expand Up @@ -616,7 +648,7 @@ func (t *Table) printHeading() {
// Check if border is set
// Replace with space if not set
if !t.noWhiteSpace {
fmt.Fprint(t.out, ConditionString(t.borders.Left, t.syms[symNS], SPACE))
fmt.Fprint(t.out, ConditionString(t.borders.Left, t.syms[symNSb], SPACE))
}

for y := 0; y <= end; y++ {
Expand All @@ -629,7 +661,11 @@ func (t *Table) printHeading() {
if t.autoFmt {
h = Title(h)
}
pad := ConditionString((y == end && !t.borders.Left), SPACE, t.syms[symNS])
vertical := symNS
if y == end {
vertical = symNSb
}
pad := ConditionString((y == end && !t.borders.Left), SPACE, t.syms[vertical])
if t.noWhiteSpace {
pad = ConditionString((y == end && !t.borders.Left), SPACE, t.tablePadding)
}
Expand Down Expand Up @@ -700,7 +736,7 @@ func (t *Table) printFooter() {
for x := 0; x < max; x++ {
// Check if border is set
// Replace with space if not set
fmt.Fprint(t.out, ConditionString(t.borders.Bottom, t.syms[symNS], SPACE))
fmt.Fprint(t.out, ConditionString(t.borders.Bottom, t.syms[symNSb], SPACE))

for y := 0; y <= end; y++ {
v := t.cs[y]
Expand All @@ -711,7 +747,11 @@ func (t *Table) printFooter() {
if t.autoFmt {
f = Title(f)
}
pad := ConditionString((y == end && !t.borders.Top), SPACE, t.syms[symNS])
vertical := symNS
if y == end {
vertical = symNSb
}
pad := ConditionString((y == end && !t.borders.Top), SPACE, t.syms[vertical])

if erasePad[y] || (x == 0 && len(f) == 0) {
pad = SPACE
Expand Down Expand Up @@ -740,8 +780,8 @@ func (t *Table) printFooter() {

for i := 0; i <= end; i++ {
v := t.cs[i]
pad := t.syms[symEW]
center := t.syms[symNEW]
pad := t.syms[symEWb]
center := t.syms[symEWbN]
length := len(t.footers[i][0])

if length > 0 {
Expand All @@ -756,9 +796,9 @@ func (t *Table) printFooter() {
// Print first junction
if i == 0 {
if length > 0 && !t.borders.Left {
center = t.syms[symEW]
center = t.syms[symEWb]
} else if center != SPACE {
center = t.syms[symNE]
center = t.syms[symNEb]
}
fmt.Fprint(t.out, center)
}
Expand All @@ -769,17 +809,17 @@ func (t *Table) printFooter() {
}
// Ignore left space as it has printed before
if hasPrinted || t.borders.Left {
pad = t.syms[symEW]
center = t.syms[symNEW]
pad = t.syms[symEWb]
center = t.syms[symEWbN]
}

// Change Center end position
if center != SPACE {
if i == end {
if t.borders.Right {
center = t.syms[symNW]
center = t.syms[symNWb]
} else {
center = t.syms[symEW]
center = t.syms[symEWb]
}
}
}
Expand All @@ -788,9 +828,9 @@ func (t *Table) printFooter() {
if center == SPACE {
if i < end && len(t.footers[i+1][0]) != 0 {
if !t.borders.Left {
center = t.syms[symEW]
center = t.syms[symEWb]
} else {
center = t.syms[symNEW]
center = t.syms[symEWbN]
}
}
}
Expand Down Expand Up @@ -887,7 +927,11 @@ func (t *Table) printRow(columns [][]string, rowIdx int) {

// Check if border is set
if !t.noWhiteSpace {
fmt.Fprint(t.out, ConditionString((!t.borders.Left && y == 0), SPACE, t.syms[symNS]))
vertical := symNS
if y == 0 {
vertical = symNSb
}
fmt.Fprint(t.out, ConditionString((!t.borders.Left && y == 0), SPACE, t.syms[vertical]))
fmt.Fprintf(t.out, SPACE)
}

Expand Down Expand Up @@ -931,7 +975,7 @@ func (t *Table) printRow(columns [][]string, rowIdx int) {
// Check if border is set
// Replace with space if not set
if !t.noWhiteSpace {
fmt.Fprint(t.out, ConditionString(t.borders.Left, t.syms[symNS], SPACE))
fmt.Fprint(t.out, ConditionString(t.borders.Left, t.syms[symNSb], SPACE))
}
fmt.Fprint(t.out, t.newLine)
}
Expand Down Expand Up @@ -992,7 +1036,11 @@ func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx
for y := 0; y < total; y++ {

// Check if border is set
fmt.Fprint(writer, ConditionString((!t.borders.Left && y == 0), SPACE, t.syms[symNS]))
vertical := symNS
if y == 0 {
vertical = symNSb
}
fmt.Fprint(writer, ConditionString((!t.borders.Left && y == 0), SPACE, t.syms[vertical]))

fmt.Fprintf(writer, SPACE)

Expand Down Expand Up @@ -1046,7 +1094,7 @@ func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, rowIdx
}
// Check if border is set
// Replace with space if not set
fmt.Fprint(writer, ConditionString(t.borders.Left, t.syms[symNS], SPACE))
fmt.Fprint(writer, ConditionString(t.borders.Left, t.syms[symNSb], SPACE))
fmt.Fprint(writer, t.newLine)
}

Expand Down
Loading