Skip to content

Commit

Permalink
Heatmap header (#74)
Browse files Browse the repository at this point in the history
* Fix panic in arg splitter

* Fix header bugs and better handling of edge cases

* Fix overflow, and use writeRepeat
  • Loading branch information
zix99 committed Aug 17, 2022
1 parent 7ed61a4 commit 3fc3fe8
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 16 deletions.
41 changes: 26 additions & 15 deletions pkg/multiterm/termrenderers/heatmap.go
Expand Up @@ -33,7 +33,7 @@ func (s *Heatmap) WriteTable(agg *aggregation.TableAggregator) {

// Write header
colNames := agg.OrderedColumnsByName() // TODO: Smart? eg. by number?
colCount := s.WriteHeader(colNames)
colCount := s.WriteHeader(colNames...)

// Each row...
rows := agg.OrderedRowsByName()
Expand Down Expand Up @@ -98,30 +98,35 @@ func (s *Heatmap) UpdateMinMax(min, max int64) {
s.term.WriteForLine(0, sb.String())
}

func (s *Heatmap) WriteHeader(colNames []string) (colCount int) {
func (s *Heatmap) WriteHeader(colNames ...string) (colCount int) {
colCount = mini(len(colNames), s.colCount)

var sb strings.Builder
sb.WriteString(strings.Repeat(" ", s.maxRowKeyWidth+1))
const headerDelim = ".."
writeRepeat(&sb, ' ', s.maxRowKeyWidth+1)
const delim = '.'
const delimCount = 2

for i := 0; i < colCount; {
name := colNames[i]

if i != 0 {
sb.WriteString(headerDelim)
i += len(headerDelim)
count := mini(colCount-i, delimCount)
writeRepeat(&sb, delim, count)
i += count
if i >= colCount {
break
}
}

if i+len(name)+len(headerDelim) > colCount {
// Too long, jump to last key
last := colNames[colCount-1]
indent := colCount - i - len(last)
name := colNames[i]

if i != 0 && i+len(name)+delimCount >= colCount {
// Too long, jump to last displayable key
name = colNames[colCount-1]
indent := colCount - i - len(name)
if indent > 0 { // Align last name with last col
sb.WriteString(strings.Repeat(headerDelim[0:1], indent))
writeRepeat(&sb, delim, indent)
i += indent
}
sb.WriteString(underlineHeaderChar(last, colCount-i-1))
sb.WriteString(underlineHeaderChar(name, colCount-i-1))
break
}

Expand All @@ -144,7 +149,7 @@ func (s *Heatmap) WriteRow(idx int, row *aggregation.TableRow, cols []string) {

var sb strings.Builder
sb.WriteString(color.Wrap(color.Yellow, row.Name()))
sb.WriteString(strings.Repeat(" ", s.maxRowKeyWidth-len(row.Name())+1))
writeRepeat(&sb, ' ', s.maxRowKeyWidth-len(row.Name())+1)

for i := 0; i < len(cols); i++ {
val := row.Value(cols[i])
Expand All @@ -161,6 +166,12 @@ func mini(i, j int) int {
return j
}

func writeRepeat(sb *strings.Builder, r rune, count int) {
for i := 0; i < count; i++ {
sb.WriteRune(r)
}
}

func underlineHeaderChar(word string, letter int) string {
if !color.Enabled {
return word
Expand Down
45 changes: 44 additions & 1 deletion pkg/multiterm/termrenderers/heatmap_test.go
Expand Up @@ -46,13 +46,56 @@ func TestCompressedHeatmap(t *testing.T) {

assert.Equal(t, 6, vt.LineCount())
assert.Equal(t, " - 0 - 0 9 1", vt.Get(0))
assert.Equal(t, " test1 (2 more)", vt.Get(1))
assert.Equal(t, " test (2 more)", vt.Get(1))
assert.Equal(t, "abc 99", vt.Get(2))
assert.Equal(t, "abc1 9-", vt.Get(3))
assert.Equal(t, "(3 more)", vt.Get(4))
assert.Equal(t, "footer", vt.Get(5))
}

func TestHeatmapHeader(t *testing.T) {
vt := multiterm.NewVirtualTerm()
hm := NewHeatmap(vt, 1, 10)

hm.WriteHeader()
assert.Equal(t, " ", vt.Get(1))

hm.WriteHeader("abc")
assert.Equal(t, " abc", vt.Get(1))

hm.WriteHeader("abc", "efg")
assert.Equal(t, " abc", vt.Get(1))

hm.WriteHeader("abc", "fi0", "fi1", "fi2", "fi3", "fi4", "fi5", "fi6", "fi7", "efg")
assert.Equal(t, " abc....efg", vt.Get(1))

hm.WriteHeader("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")
assert.Equal(t, " a..d..g..j", vt.Get(1))

hm.WriteHeader("a", "b", "c", "d", "e", "f", "g", "h", "i", "jack")
assert.Equal(t, " a..d..g..jack", vt.Get(1))

hm.WriteHeader("a", "b", "c", "d", "e", "f", "gar", "h", "i", "jack")
assert.Equal(t, " a..d..jack", vt.Get(1))

hm.WriteHeader("a", "b", "c", "d", "e", "f", "ga", "h", "i", "j")
assert.Equal(t, " a..d.....j", vt.Get(1))

hm.WriteHeader("aa", "bb", "cc", "dd", "ee", "ff", "gg", "hh", "ii", "jj")
assert.Equal(t, " aa..ee..jj", vt.Get(1))

// 2 more
hm.WriteHeader("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l")
assert.Equal(t, " a..d..g..j (2 more)", vt.Get(1))

// short, by slightly more
hm.WriteHeader("abc", "d", "e", "f", "g")
assert.Equal(t, " abc..", vt.Get(1))

hm.WriteHeader("abc", "d", "e", "f")
assert.Equal(t, " abc.", vt.Get(1))
}

func TestUnderlineHeaderChar(t *testing.T) {
color.Enabled = true
assert.Equal(t, "\x1b[34;1m\x1b[0m", underlineHeaderChar("", 0))
Expand Down

0 comments on commit 3fc3fe8

Please sign in to comment.