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

Extract text package from gh #69

Merged
merged 2 commits into from Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -18,6 +18,7 @@ require (
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1
golang.org/x/text v0.3.7
gopkg.in/h2non/gock.v1 v1.1.2
gopkg.in/yaml.v3 v3.0.1
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -92,6 +92,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
24 changes: 4 additions & 20 deletions pkg/tableprinter/table.go
Expand Up @@ -9,8 +9,7 @@ import (
"io"
"strings"

"github.com/muesli/reflow/ansi"
"github.com/muesli/reflow/truncate"
"github.com/cli/go-gh/pkg/text"
)

type fieldOption func(*tableField)
Expand Down Expand Up @@ -72,7 +71,7 @@ func (t *ttyTablePrinter) AddField(s string, opts ...fieldOption) {
rowI := len(t.rows) - 1
field := tableField{
text: s,
truncateFunc: truncateText,
truncateFunc: text.Truncate,
}
for _, opt := range opts {
opt(&field)
Expand Down Expand Up @@ -107,7 +106,7 @@ func (t *ttyTablePrinter) Render() error {
}
if col < numCols-1 {
// pad value with spaces on the right
if padWidth := colWidths[col] - displayWidth(field.text); padWidth > 0 {
if padWidth := colWidths[col] - text.DisplayWidth(field.text); padWidth > 0 {
truncVal += strings.Repeat(" ", padWidth)
}
}
Expand Down Expand Up @@ -136,7 +135,7 @@ func (t *ttyTablePrinter) calculateColumnWidths(delimSize int) []int {

for _, row := range t.rows {
for col, field := range row {
w := displayWidth(field.text)
w := text.DisplayWidth(field.text)
if w > maxColWidths[col] {
maxColWidths[col] = w
}
Expand Down Expand Up @@ -230,18 +229,3 @@ func (t *tsvTablePrinter) EndRow() {
func (t *tsvTablePrinter) Render() error {
return nil
}

func truncateText(maxWidth int, s string) string {
rw := ansi.PrintableRuneWidth(s)
if rw <= maxWidth {
return s
}
if maxWidth < 5 {
return truncate.String(s, uint(maxWidth))
}
return truncate.StringWithTail(s, uint(maxWidth), "...")
}

func displayWidth(s string) int {
return ansi.PrintableRuneWidth(s)
}
92 changes: 0 additions & 92 deletions pkg/tableprinter/table_test.go
Expand Up @@ -95,95 +95,3 @@ func Test_tsvTablePrinter(t *testing.T) {
t.Errorf("expected: %q, got: %q", expected, buf.String())
}
}

func Test_truncateText(t *testing.T) {
type args struct {
maxWidth int
s string
}
tests := []struct {
name string
args args
want string
}{
{
name: "empty",
args: args{
s: "",
maxWidth: 10,
},
want: "",
},
{
name: "short",
args: args{
s: "hello",
maxWidth: 3,
},
want: "hel",
},
{
name: "long",
args: args{
s: "hello world",
maxWidth: 5,
},
want: "he...",
},
{
name: "no truncate",
args: args{
s: "hello world",
maxWidth: 11,
},
want: "hello world",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := truncateText(tt.args.maxWidth, tt.args.s); got != tt.want {
t.Errorf("truncateText() = %v, want %v", got, tt.want)
}
})
}
}

func Test_displayWidth(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
args args
want int
}{
{
name: "empty",
args: args{
s: "",
},
want: 0,
},
{
name: "Latin",
args: args{
s: "hello world 123$#!",
},
want: 18,
},
{
name: "Asian",
args: args{
s: "つのだ☆HIRO",
},
want: 11,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := displayWidth(tt.args.s); got != tt.want {
t.Errorf("displayWidth() = %v, want %v", got, tt.want)
}
})
}
}
44 changes: 8 additions & 36 deletions pkg/template/template.go
Expand Up @@ -14,9 +14,8 @@ import (
"time"

"github.com/cli/go-gh/pkg/tableprinter"
"github.com/cli/go-gh/pkg/text"
color "github.com/mgutz/ansi"
"github.com/muesli/reflow/ansi"
"github.com/muesli/reflow/truncate"
)

// Template is the representation of a template.
Expand Down Expand Up @@ -148,7 +147,7 @@ func truncateFunc(maxWidth int, v interface{}) (string, error) {
return "", nil
}
if s, ok := v.(string); ok {
return truncateText(maxWidth, s), nil
return text.Truncate(maxWidth, s), nil
}
return "", fmt.Errorf("invalid value; expected string, got %T", v)
}
Expand All @@ -166,7 +165,7 @@ func tableRowFunc(tp tableprinter.TablePrinter, fields ...interface{}) (string,
if err != nil {
return "", fmt.Errorf("failed to write table row: %v", err)
}
tp.AddField(s, tableprinter.WithTruncate(truncateColumn))
tp.AddField(s, tableprinter.WithTruncate(text.TruncateMultiline))
}
tp.EndRow()
return "", nil
Expand Down Expand Up @@ -207,43 +206,16 @@ func timeAgo(ago time.Duration) string {
return "just now"
Copy link
Contributor Author

@samcoe samcoe Aug 25, 2022

Choose a reason for hiding this comment

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

Kind of weird that we don't use FuzzyAgo instead of this entire function. Perhaps we should be? The current functionality was brought over from gh.

}
if ago < time.Hour {
return pluralize(int(ago.Minutes()), "minute") + " ago"
return text.Pluralize(int(ago.Minutes()), "minute") + " ago"
}
if ago < 24*time.Hour {
return pluralize(int(ago.Hours()), "hour") + " ago"
return text.Pluralize(int(ago.Hours()), "hour") + " ago"
}
if ago < 30*24*time.Hour {
return pluralize(int(ago.Hours())/24, "day") + " ago"
return text.Pluralize(int(ago.Hours())/24, "day") + " ago"
}
if ago < 365*24*time.Hour {
return pluralize(int(ago.Hours())/24/30, "month") + " ago"
return text.Pluralize(int(ago.Hours())/24/30, "month") + " ago"
}
return pluralize(int(ago.Hours()/24/365), "year") + " ago"
}

func pluralize(num int, thing string) string {
if num == 1 {
return fmt.Sprintf("%d %s", num, thing)
}
return fmt.Sprintf("%d %ss", num, thing)
}

// TruncateColumn replaces the first new line character with an ellipsis
// and shortens a string to fit the maximum display width.
func truncateColumn(maxWidth int, s string) string {
if i := strings.IndexAny(s, "\r\n"); i >= 0 {
s = s[:i] + "..."
}
return truncateText(maxWidth, s)
}

func truncateText(maxWidth int, s string) string {
rw := ansi.PrintableRuneWidth(s)
if rw <= maxWidth {
return s
}
if maxWidth < 5 {
return truncate.String(s, uint(maxWidth))
}
return truncate.StringWithTail(s, uint(maxWidth), "...")
return text.Pluralize(int(ago.Hours()/24/365), "year") + " ago"
}