Skip to content

Commit 2be0b3c

Browse files
authored
Merge pull request #7 from noborus/add-align
Add align option
2 parents c9581d8 + d8ab917 commit 2be0b3c

File tree

3 files changed

+123
-3
lines changed

3 files changed

+123
-3
lines changed

cmd/root.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"fmt"
55
"os"
6+
"strings"
67

78
"github.com/noborus/guesswidth"
89
"github.com/spf13/cobra"
@@ -16,7 +17,7 @@ var rootCmd = &cobra.Command{
1617
split them, insert fences and output.`,
1718
Version: guesswidth.Version(),
1819
Run: func(cmd *cobra.Command, args []string) {
19-
writeTable(args)
20+
writeTable()
2021
},
2122
}
2223

@@ -25,16 +26,21 @@ var (
2526
header int
2627
limitSplit int
2728
scanNum int
29+
align bool
2830
)
2931

30-
func writeTable(args []string) {
32+
func writeTable() {
3133
g := guesswidth.NewReader(os.Stdin)
3234
g.Header = header - 1
3335
g.LimitSplit = limitSplit
3436
g.TrimSpace = false
3537
if scanNum > 0 {
3638
g.ScanNum = scanNum
3739
}
40+
if align {
41+
writeAlign(g)
42+
return
43+
}
3844
write(g)
3945
}
4046

@@ -54,6 +60,27 @@ func write(g *guesswidth.GuessWidth) {
5460
}
5561
}
5662

63+
func writeAlign(g *guesswidth.GuessWidth) {
64+
for _, row := range g.ReadAll() {
65+
for n, col := range row {
66+
if n > 0 {
67+
fmt.Print(fence)
68+
}
69+
col = strings.TrimSpace(col)
70+
if g.Widths[n].Justified == guesswidth.Right {
71+
fmt.Printf("%*s", g.Widths[n].Width, col)
72+
} else {
73+
if len(g.Widths)-1 == n {
74+
fmt.Printf("%s", col)
75+
} else {
76+
fmt.Printf("%-*s", g.Widths[n].Width, col)
77+
}
78+
}
79+
}
80+
fmt.Println()
81+
}
82+
}
83+
5784
// Execute adds all child commands to the root command and sets flags appropriately.
5885
// This is called by main.main(). It only needs to happen once to the rootCmd.
5986
func Execute() {
@@ -66,7 +93,7 @@ func init() {
6693
rootCmd.PersistentFlags().IntVar(&header, "header", 1, "header line number")
6794
rootCmd.PersistentFlags().IntVar(&limitSplit, "split", -1, "maximum number of splits")
6895
rootCmd.PersistentFlags().IntVar(&scanNum, "scannum", 100, "number of line to scan")
69-
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
96+
rootCmd.PersistentFlags().BoolVarP(&align, "align", "a", false, "align the output")
7097
}
7198

7299
// initConfig reads in config file and ENV variables if set.

guesswidth.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ type GuessWidth struct {
2121
reader *bufio.Reader
2222
// pos is a list of separator positions.
2323
pos []int
24+
// Widths is the width of the column.
25+
Widths []Cols
2426
// preLines stores the lines read for scan.
2527
preLines []string
2628
// preCount is the number returned by read.
@@ -39,6 +41,17 @@ type GuessWidth struct {
3941
TrimSpace bool
4042
}
4143

44+
type Cols struct {
45+
Width int
46+
Justified int
47+
rightCount int
48+
}
49+
50+
const (
51+
Left = iota
52+
Right
53+
)
54+
4255
// NewReader returns a new Reader that reads from r.
4356
func NewReader(r io.Reader) *GuessWidth {
4457
reader := bufio.NewReader(r)
@@ -61,17 +74,69 @@ func (g *GuessWidth) ReadAll() [][]string {
6174
g.Scan(g.ScanNum)
6275
}
6376

77+
g.Widths = make([]Cols, len(g.pos)+1)
6478
var rows [][]string
6579
for {
6680
columns, err := g.Read()
6781
if err != nil {
6882
break
6983
}
84+
g.UpdateMaxWidth(columns)
7085
rows = append(rows, columns)
7186
}
87+
88+
g.SetJustified(len(rows) / 2)
7289
return rows
7390
}
7491

92+
// UpdateMaxWidth updates the maximum width of the column.
93+
func (g *GuessWidth) UpdateMaxWidth(columns []string) []Cols {
94+
if len(g.Widths) < len(columns) {
95+
for n := len(g.Widths); n < len(columns); n++ {
96+
g.Widths = append(g.Widths, Cols{})
97+
}
98+
}
99+
100+
for n, col := range columns {
101+
width := runewidth.StringWidth(col)
102+
if width > g.Widths[n].Width {
103+
g.Widths[n].Width = width
104+
}
105+
if isRightAlign(col) {
106+
g.Widths[n].rightCount++
107+
}
108+
}
109+
return g.Widths
110+
}
111+
112+
// SetJustified sets the justification of the column.
113+
func (g *GuessWidth) SetJustified(threshold int) []Cols {
114+
for n, col := range g.Widths {
115+
if col.rightCount < threshold {
116+
col.Justified = Left
117+
} else {
118+
col.Justified = Right
119+
}
120+
g.Widths[n] = col
121+
}
122+
return g.Widths
123+
}
124+
125+
func isRightAlign(str string) bool {
126+
if str == "" {
127+
return false
128+
}
129+
for n := 0; n < len(str); n++ {
130+
if str[n] != ' ' {
131+
return false
132+
}
133+
if str[len(str)-n-1] != ' ' {
134+
return true
135+
}
136+
}
137+
return false
138+
}
139+
75140
// Scan preReads and parses the lines.
76141
func (g *GuessWidth) Scan(num int) {
77142
for i := 0; i < num; i++ {

guesswidth_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ func TestGuessWidth_ReadAll(t *testing.T) {
2323
name string
2424
fields fields
2525
want [][]string
26+
want2 []Cols
2627
}{
2728
{
2829
name: "ps",
@@ -38,6 +39,12 @@ func TestGuessWidth_ReadAll(t *testing.T) {
3839
{"302965", " pts/3 ", " 00:00:11", "zsh"},
3940
{"709737", " pts/3 ", " 00:00:00", "ps"},
4041
},
42+
want2: []Cols{
43+
{6, 1, 1},
44+
{9, 0, 0},
45+
{9, 1, 3},
46+
{3, 0, 0},
47+
},
4148
},
4249
{
4350
name: "ps overflow",
@@ -55,6 +62,19 @@ noborus 721971 0.0 0.0 13716 3524 pts/3 R+ 10:39 0:00 ps aux`)),
5562
{"noborus ", " 703052", " 2.1", " 0.7", " 1184814400", " 230920", " ? ", " Sl ", " 10:03 ", " 0:45", "/opt/google/chrome/chrome"},
5663
{"noborus ", " 721971", " 0.0", " 0.0", " 13716", " 3524", " pts/3 ", " R+ ", " 10:39 ", " 0:00", "ps aux"},
5764
},
65+
want2: []Cols{
66+
{9, 0, 0},
67+
{7, 1, 4},
68+
{5, 1, 4},
69+
{5, 1, 4},
70+
{11, 1, 4},
71+
{7, 1, 4},
72+
{9, 0, 0},
73+
{5, 0, 1},
74+
{8, 0, 0},
75+
{5, 1, 4},
76+
{25, 0, 0},
77+
},
5878
},
5979
{
6080
name: "ps limit",
@@ -71,6 +91,11 @@ noborus 721971 0.0 0.0 13716 3524 pts/3 R+ 10:39 0:00 ps aux`)),
7191
{"302965", " pts/3 ", "00:00:11 zsh"},
7292
{"709737", " pts/3 ", "00:00:00 ps"},
7393
},
94+
want2: []Cols{
95+
{6, 1, 1},
96+
{9, 0, 0},
97+
{12, 1, 1},
98+
},
7499
},
75100
}
76101
for _, tt := range tests {
@@ -89,6 +114,9 @@ noborus 721971 0.0 0.0 13716 3524 pts/3 R+ 10:39 0:00 ps aux`)),
89114
if got := g.ReadAll(); !reflect.DeepEqual(got, tt.want) {
90115
t.Errorf("GuessWidth.ReadAll() = \n%#v, want \n%#v", got, tt.want)
91116
}
117+
if got2 := g.Widths; !reflect.DeepEqual(got2, tt.want2) {
118+
t.Errorf("GuessWidth.ReadAll() = \n%v, want \n%v", got2, tt.want2)
119+
}
92120
})
93121
}
94122
}

0 commit comments

Comments
 (0)