Skip to content

Commit

Permalink
Merge pull request #4 from noborus/positions-public
Browse files Browse the repository at this point in the history
Made Positions public
  • Loading branch information
noborus authored Mar 20, 2023
2 parents c9340fd + 9ce2c63 commit 231c7c5
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 13 deletions.
30 changes: 19 additions & 11 deletions guesswidth.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type GuessWidth struct {
Header int
// limitSplit is the maximum number of columns to split.
LimitSplit int
// MinLines is the minimum number of lines to recognize as a separator.
// 1 if only the header, 2 or more if there is a blank in the body.
MinLines int
// TrimSpace is whether to trim the space in the value.
TrimSpace bool
}
Expand All @@ -45,6 +48,7 @@ func NewReader(r io.Reader) *GuessWidth {
preCount: 0,
Header: 0,
LimitSplit: 0,
MinLines: 2,
TrimSpace: true,
}
return g
Expand Down Expand Up @@ -78,7 +82,7 @@ func (g *GuessWidth) Scan(num int) {
g.preLines = append(g.preLines, string(buf))
}

g.pos = widthPositions(g.preLines, g.Header)
g.pos = Positions(g.preLines, g.Header, g.MinLines)

if g.LimitSplit > 0 {
if len(g.pos) > g.LimitSplit {
Expand Down Expand Up @@ -109,24 +113,27 @@ func (g *GuessWidth) Read() ([]string, error) {
return split(line, g.pos, g.TrimSpace), nil
}

// ToTable parses a slice of rows and returns a table.
// ToTable parses a slice of lines and returns a table.
func ToTable(lines []string, header int, trimSpace bool) [][]string {
pos := widthPositions(lines, header)
pos := Positions(lines, header, 2)
return toRows(lines, pos, trimSpace)
}

// ToTableN parses a slice of rows and returns a table, but limits the number of splits.
// ToTableN parses a slice of lines and returns a table, but limits the number of splits.
func ToTableN(lines []string, header int, numSplit int, trimSpace bool) [][]string {
pos := widthPositions(lines, header)
pos := Positions(lines, header, 2)
if len(pos) > numSplit {
pos = pos[:numSplit]
}
return toRows(lines, pos, trimSpace)
}

func widthPositions(lines []string, header int) []int {
// Positions returns separator positions
// from multiple lines and header line number.
// Lines before the header line are ignored.
func Positions(lines []string, header int, minLines int) []int {
var blanks []int
limit := 2

if header < 0 {
header = 0
}
Expand All @@ -140,7 +147,7 @@ func widthPositions(lines []string, header int) []int {
}
blanks = countBlanks(blanks, strings.TrimSuffix(line, " "))
}
return positions(blanks, limit)
return positions(blanks, minLines)
}

func separatorPosition(lr []rune, p int, pos []int, n int) int {
Expand Down Expand Up @@ -216,6 +223,7 @@ func split(line string, pos []int, trimSpace bool) []string {
return columns
}

// roRows returns rows separated by columns.
func toRows(lines []string, pos []int, trimSpace bool) [][]string {
rows := make([][]string, 0, len(lines))
for _, line := range lines {
Expand Down Expand Up @@ -269,8 +277,8 @@ func countBlanks(blanks []int, line string) []int {
}

// Generates a list of separator positions from a blank slice.
func positions(blanks []int, limit int) []int {
max := limit
func positions(blanks []int, minLines int) []int {
max := minLines
p := 0
var pos []int
for n, v := range blanks {
Expand All @@ -279,7 +287,7 @@ func positions(blanks []int, limit int) []int {
p = n
}
if v == 0 {
max = limit
max = minLines
if p > 0 {
pos = append(pos, p)
p = 0
Expand Down
24 changes: 22 additions & 2 deletions guesswidth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func TestGuessWidth_ReadAll(t *testing.T) {
ScanNum int
Header int
LimitSplit int
MinLines int
TrimSpace bool
}
tests := []struct {
Expand All @@ -29,7 +30,8 @@ func TestGuessWidth_ReadAll(t *testing.T) {
reader: bufio.NewReader(strings.NewReader(` PID TTY TIME CMD
302965 pts/3 00:00:11 zsh
709737 pts/3 00:00:00 ps`)),
ScanNum: 100,
ScanNum: 100,
MinLines: 2,
},
want: [][]string{
{" PID", " TTY ", " TIME", "CMD"},
Expand All @@ -44,7 +46,8 @@ func TestGuessWidth_ReadAll(t *testing.T) {
root 1 0.0 0.0 168576 13788 ? Ss Mar11 0:49 /sbin/init splash
noborus 703052 2.1 0.7 1184814400 230920 ? Sl 10:03 0:45 /opt/google/chrome/chrome
noborus 721971 0.0 0.0 13716 3524 pts/3 R+ 10:39 0:00 ps aux`)),
ScanNum: 100,
ScanNum: 100,
MinLines: 2,
},
want: [][]string{
{"USER ", " PID", " %CPU", " %MEM", " VSZ", " RSS", " TTY ", " STAT", " START ", " TIME", "COMMAND"},
Expand All @@ -53,6 +56,22 @@ noborus 721971 0.0 0.0 13716 3524 pts/3 R+ 10:39 0:00 ps aux`)),
{"noborus ", " 721971", " 0.0", " 0.0", " 13716", " 3524", " pts/3 ", " R+ ", " 10:39 ", " 0:00", "ps aux"},
},
},
{
name: "ps limit",
fields: fields{
reader: bufio.NewReader(strings.NewReader(` PID TTY TIME CMD
302965 pts/3 00:00:11 zsh
709737 pts/3 00:00:00 ps`)),
ScanNum: 100,
MinLines: 2,
LimitSplit: 2,
},
want: [][]string{
{" PID", " TTY ", " TIME CMD"},
{"302965", " pts/3 ", "00:00:11 zsh"},
{"709737", " pts/3 ", "00:00:00 ps"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -64,6 +83,7 @@ noborus 721971 0.0 0.0 13716 3524 pts/3 R+ 10:39 0:00 ps aux`)),
ScanNum: tt.fields.ScanNum,
Header: tt.fields.Header,
LimitSplit: tt.fields.LimitSplit,
MinLines: tt.fields.MinLines,
TrimSpace: tt.fields.TrimSpace,
}
if got := g.ReadAll(); !reflect.DeepEqual(got, tt.want) {
Expand Down

0 comments on commit 231c7c5

Please sign in to comment.