summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean E. Russell <ser@ser1.net>2021-01-26 11:13:45 -0600
committerSean E. Russell <ser@ser1.net>2021-01-26 11:13:45 -0600
commit2f0eca1cc6a59f786a475debce7811664ce7451c (patch)
tree2655f2270921aad6a132efddc6cba68c226684b7
parent4cea91b9a1483747de90c5527c9a7faa6d926cf5 (diff)
Fixes #161, CPU names are sorted strictly as strings rather than lexographically.
-rw-r--r--termui/linegraph.go86
-rw-r--r--termui/linegraph_test.go60
2 files changed, 136 insertions, 10 deletions
diff --git a/termui/linegraph.go b/termui/linegraph.go
index fa8a3ae..941183f 100644
--- a/termui/linegraph.go
+++ b/termui/linegraph.go
@@ -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
+}
diff --git a/termui/linegraph_test.go b/termui/linegraph_test.go
new file mode 100644
index 0000000..e8f8a6a
--- /dev/null
+++ b/termui/linegraph_test.go
@@ -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)
+ }
+ }
+ }
+}