Fixes #161, CPU names are sorted strictly as strings rather than lexographically.
This commit is contained in:
parent
4cea91b9a1
commit
2f0eca1cc6
@ -3,6 +3,8 @@ package termui
|
||||
import (
|
||||
"image"
|
||||
"sort"
|
||||
"strconv"
|
||||
"unicode"
|
||||
|
||||
. "github.com/gizak/termui/v3"
|
||||
drawille "github.com/xxxserxxx/gotop/v4/termui/drawille-go"
|
||||
@ -27,6 +29,8 @@ type LineGraph struct {
|
||||
LineColors map[string]Color
|
||||
LabelStyles map[string]Modifier
|
||||
DefaultLineColor Color
|
||||
|
||||
seriesList numbered
|
||||
}
|
||||
|
||||
func NewLineGraph() *LineGraph {
|
||||
@ -54,18 +58,20 @@ func (self *LineGraph) Draw(buf *Buffer) {
|
||||
colors[i] = make([]Color, self.Inner.Dy()+2)
|
||||
}
|
||||
|
||||
// sort the series so that overlapping data will overlap the same way each time
|
||||
seriesList := make([]string, len(self.Data))
|
||||
i := 0
|
||||
for seriesName := range self.Data {
|
||||
seriesList[i] = seriesName
|
||||
i++
|
||||
if len(self.seriesList) != len(self.Data) {
|
||||
// sort the series so that overlapping data will overlap the same way each time
|
||||
self.seriesList = make(numbered, len(self.Data))
|
||||
i := 0
|
||||
for seriesName := range self.Data {
|
||||
self.seriesList[i] = seriesName
|
||||
i++
|
||||
}
|
||||
sort.Sort(self.seriesList)
|
||||
}
|
||||
sort.Strings(seriesList)
|
||||
|
||||
// draw lines in reverse order so that the first color defined in the colorscheme is on top
|
||||
for i := len(seriesList) - 1; i >= 0; i-- {
|
||||
seriesName := seriesList[i]
|
||||
for i := len(self.seriesList) - 1; i >= 0; i-- {
|
||||
seriesName := self.seriesList[i]
|
||||
seriesData := self.Data[seriesName]
|
||||
seriesLineColor, ok := self.LineColors[seriesName]
|
||||
if !ok {
|
||||
@ -128,7 +134,7 @@ func (self *LineGraph) Draw(buf *Buffer) {
|
||||
maxWid := 0
|
||||
xoff := 0 // X offset for additional columns of text
|
||||
yoff := 0 // Y offset for resetting column to top of widget
|
||||
for i, seriesName := range seriesList {
|
||||
for i, seriesName := range self.seriesList {
|
||||
if yoff+i+2 > self.Inner.Dy() {
|
||||
xoff += maxWid + 2
|
||||
yoff = -i
|
||||
@ -159,3 +165,63 @@ func (self *LineGraph) Draw(buf *Buffer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// A string containing an integer
|
||||
type numbered []string
|
||||
|
||||
func (n numbered) Len() int { return len(n) }
|
||||
func (n numbered) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
|
||||
func (n numbered) Less(i, j int) bool {
|
||||
a := n[i]
|
||||
b := n[j]
|
||||
for i := 0; i < len(a); i++ {
|
||||
ac := a[i]
|
||||
if unicode.IsDigit(rune(ac)) {
|
||||
j := i + 1
|
||||
for ; j < len(a); j++ {
|
||||
if !unicode.IsDigit(rune(a[j])) {
|
||||
break
|
||||
}
|
||||
if j >= len(b) {
|
||||
return false
|
||||
}
|
||||
if !unicode.IsDigit(rune(b[j])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
an, err := strconv.Atoi(a[i:j])
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
if j > len(b) {
|
||||
return false
|
||||
}
|
||||
for ; j < len(b); j++ {
|
||||
if !unicode.IsDigit(rune(b[j])) {
|
||||
break
|
||||
}
|
||||
}
|
||||
bn, err := strconv.Atoi(b[i:j])
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
if an < bn {
|
||||
return true
|
||||
} else if bn < an {
|
||||
return false
|
||||
}
|
||||
i = j
|
||||
}
|
||||
if i >= len(a) {
|
||||
return true
|
||||
} else if i >= len(b) {
|
||||
return false
|
||||
}
|
||||
if ac < b[i] {
|
||||
return true
|
||||
} else if b[i] < ac {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
60
termui/linegraph_test.go
Normal file
60
termui/linegraph_test.go
Normal file
@ -0,0 +1,60 @@
|
||||
package termui
|
||||
|
||||
import "testing"
|
||||
import "sort"
|
||||
|
||||
func TestLess(t *testing.T) {
|
||||
tests := []struct {
|
||||
a, b string
|
||||
e bool
|
||||
}{
|
||||
{a: "abc", b: "def", e: true},
|
||||
{a: "abc", b: "abc", e: true},
|
||||
{a: "def", b: "abc", e: false},
|
||||
{a: "1", b: "10", e: true},
|
||||
{a: "1", b: "2", e: true},
|
||||
{a: "a2", b: "2", e: false},
|
||||
{a: "a2", b: "a10", e: true},
|
||||
{a: "a20", b: "a2", e: false},
|
||||
{a: "abc20", b: "def2", e: true},
|
||||
{a: "abc20", b: "abc2", e: false},
|
||||
{a: "abc20", b: "abc20", e: true},
|
||||
{a: "abc30", b: "abc20", e: false},
|
||||
{a: "abc20a", b: "abc20", e: false},
|
||||
{a: "abc20", b: "abc20a", e: true},
|
||||
{a: "abc20", b: "abc2a", e: false},
|
||||
{a: "abc20", b: "abc3a", e: false},
|
||||
{a: "abc20", b: "abc2abc", e: false},
|
||||
}
|
||||
for _, k := range tests {
|
||||
n := numbered([]string{k.a, k.b})
|
||||
g := n.Less(0, 1)
|
||||
if g != k.e {
|
||||
t.Errorf("%s < %s: expected %v, got %v", k.a, k.b, k.e, g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSort(t *testing.T) {
|
||||
tests := []struct {
|
||||
in, ex numbered
|
||||
}{
|
||||
{
|
||||
in: numbered{"abc", "def", "abc", "abc", "def", "abc", "1", "10", "1", "2", "a2", "2", "a2", "a10", "a20", "a2", "abc20", "def2", "abc20", "abc2", "abc20", "abc20", "abc30", "abc20", "abc20a", "abc20", "abc20", "abc20a", "abc20", "abc2a"},
|
||||
ex: numbered{"1", "1", "2", "2", "10", "a2", "a2", "a2", "a10", "a20", "abc", "abc", "abc", "abc", "abc2", "abc2a", "abc20", "abc20", "abc20", "abc20", "abc20", "abc20", "abc20", "abc20", "abc20a", "abc20a", "abc30", "def", "def", "def2"},
|
||||
},
|
||||
{
|
||||
in: numbered{"CPU12", "CPU11", "CPU9", "CPU3", "CPU4", "CPU0", "CPU6", "CPU7", "CPU8", "CPU5", "CPU10", "CPU1", "CPU2"},
|
||||
ex: numbered{"CPU0", "CPU1", "CPU2", "CPU3", "CPU4", "CPU5", "CPU6", "CPU7", "CPU8", "CPU9", "CPU10", "CPU11", "CPU12"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, k := range tests {
|
||||
sort.Sort(k.in)
|
||||
for i, v := range k.in {
|
||||
if v != k.ex[i] {
|
||||
t.Errorf("failed to properly sort\n\texpected: %v\n\tgot: %v", k.ex, k.in)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user