forked from TrueCloudLab/restic
Merge pull request #4849 from fthoma/table-tcwidth
Use character display width for table padding
This commit is contained in:
commit
78485160fc
4 changed files with 68 additions and 8 deletions
|
@ -8,6 +8,8 @@ import (
|
|||
"math/bits"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/width"
|
||||
)
|
||||
|
||||
func FormatBytes(c uint64) string {
|
||||
|
@ -105,3 +107,24 @@ func ToJSONString(status interface{}) string {
|
|||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// TerminalDisplayWidth returns the number of terminal cells needed to display s
|
||||
func TerminalDisplayWidth(s string) int {
|
||||
width := 0
|
||||
for _, r := range s {
|
||||
width += terminalDisplayRuneWidth(r)
|
||||
}
|
||||
|
||||
return width
|
||||
}
|
||||
|
||||
func terminalDisplayRuneWidth(r rune) int {
|
||||
switch width.LookupRune(r).Kind() {
|
||||
case width.EastAsianWide, width.EastAsianFullwidth:
|
||||
return 2
|
||||
case width.EastAsianNarrow, width.EastAsianHalfwidth, width.EastAsianAmbiguous, width.Neutral:
|
||||
return 1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,3 +84,21 @@ func TestParseBytesInvalid(t *testing.T) {
|
|||
test.Equals(t, int64(0), v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTerminalDisplayWidth(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
input string
|
||||
want int
|
||||
}{
|
||||
{"foo", 3},
|
||||
{"aéb", 3},
|
||||
{"ab", 3},
|
||||
{"a’b", 3},
|
||||
{"aあb", 4},
|
||||
} {
|
||||
if got := TerminalDisplayWidth(c.input); got != c.want {
|
||||
t.Errorf("wrong display width for '%s', want %d, got %d", c.input, c.want, got)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"strings"
|
||||
|
||||
"text/template"
|
||||
|
||||
"github.com/restic/restic/internal/ui"
|
||||
)
|
||||
|
||||
// Table contains data for a table to be printed.
|
||||
|
@ -89,7 +91,7 @@ func printLine(w io.Writer, print func(io.Writer, string) error, sep string, dat
|
|||
}
|
||||
|
||||
// apply padding
|
||||
pad := widths[fieldNum] - len(v)
|
||||
pad := widths[fieldNum] - ui.TerminalDisplayWidth(v)
|
||||
if pad > 0 {
|
||||
v += strings.Repeat(" ", pad)
|
||||
}
|
||||
|
@ -139,16 +141,18 @@ func (t *Table) Write(w io.Writer) error {
|
|||
columnWidths := make([]int, columns)
|
||||
for i, desc := range t.columns {
|
||||
for _, line := range strings.Split(desc, "\n") {
|
||||
if columnWidths[i] < len(line) {
|
||||
columnWidths[i] = len(desc)
|
||||
width := ui.TerminalDisplayWidth(line)
|
||||
if columnWidths[i] < width {
|
||||
columnWidths[i] = width
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, line := range lines {
|
||||
for i, content := range line {
|
||||
for _, l := range strings.Split(content, "\n") {
|
||||
if columnWidths[i] < len(l) {
|
||||
columnWidths[i] = len(l)
|
||||
width := ui.TerminalDisplayWidth(l)
|
||||
if columnWidths[i] < width {
|
||||
columnWidths[i] = width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +163,7 @@ func (t *Table) Write(w io.Writer) error {
|
|||
for _, width := range columnWidths {
|
||||
totalWidth += width
|
||||
}
|
||||
totalWidth += (columns - 1) * len(t.CellSeparator)
|
||||
totalWidth += (columns - 1) * ui.TerminalDisplayWidth(t.CellSeparator)
|
||||
|
||||
// write header
|
||||
if len(t.columns) > 0 {
|
||||
|
|
|
@ -29,6 +29,21 @@ first column
|
|||
----------------------
|
||||
data: first data field
|
||||
----------------------
|
||||
`,
|
||||
},
|
||||
{
|
||||
func(t testing.TB) *Table {
|
||||
table := New()
|
||||
table.AddColumn("first\ncolumn", "{{.First}}")
|
||||
table.AddRow(struct{ First string }{"data"})
|
||||
return table
|
||||
},
|
||||
`
|
||||
first
|
||||
column
|
||||
------
|
||||
data
|
||||
------
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
@ -126,7 +141,7 @@ foo 2018-08-19 22:22:22 xxx other /home/user/other
|
|||
Time string
|
||||
Tags, Dirs []string
|
||||
}
|
||||
table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"work", "go"}, []string{"/home/user/work", "/home/user/go"}})
|
||||
table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"work", "go’s"}, []string{"/home/user/work", "/home/user/go"}})
|
||||
table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"other"}, []string{"/home/user/other"}})
|
||||
table.AddRow(data{"foo", "2018-08-19 22:22:22", []string{"other", "bar"}, []string{"/home/user/other"}})
|
||||
return table
|
||||
|
@ -135,7 +150,7 @@ foo 2018-08-19 22:22:22 xxx other /home/user/other
|
|||
host name time zz tags dirs
|
||||
------------------------------------------------------------
|
||||
foo 2018-08-19 22:22:22 xxx work /home/user/work
|
||||
go /home/user/go
|
||||
go’s /home/user/go
|
||||
foo 2018-08-19 22:22:22 xxx other /home/user/other
|
||||
foo 2018-08-19 22:22:22 xxx other /home/user/other
|
||||
bar
|
||||
|
|
Loading…
Reference in a new issue