/
test_detail.go
133 lines (115 loc) · 2.8 KB
/
test_detail.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package fancy
import (
"strings"
"sync"
"github.com/ricardomaraschini/crebain/tui"
ui "github.com/gizak/termui/v3"
"github.com/gizak/termui/v3/widgets"
)
// NewTestDetail returns a new widget capable of rendering a test output.
func NewTestDetail(y0, x1, y1 int) *TestDetail {
box := widgets.NewParagraph()
box.SetRect(0, y0, x1, y1)
return &TestDetail{
box: box,
maxRows: y1 - y0 - 2,
maxCols: x1 - 2,
}
}
// TestDetail the box where we add the text.
type TestDetail struct {
sync.Mutex
firstRenderedRow int
firstRenderedCol int
maxRows int
maxCols int
fullContent []string
renderedContent []string
box *widgets.Paragraph
}
// Event is called everytime the user generates an event, e.g. presses a key.
func (r *TestDetail) Event(event string) {
r.Lock()
defer r.Unlock()
switch event {
case "J":
r.down()
case "K":
r.up()
case "H":
r.left()
case "L":
r.right()
}
}
// up moves box content one row up.
func (r *TestDetail) up() {
if r.firstRenderedRow == 0 {
return
}
r.firstRenderedRow--
r.writeContent()
}
// left moves the box content one char to the left.
func (r *TestDetail) left() {
if r.firstRenderedCol == 0 {
return
}
r.firstRenderedCol--
r.writeContent()
}
// right moves the box content one char to the right.
func (r *TestDetail) right() {
r.firstRenderedCol++
r.writeContent()
}
// down moves the box content one row down.
func (r *TestDetail) down() {
r.firstRenderedRow++
r.writeContent()
}
// Update sets the title and text to be rendered.
func (r *TestDetail) Update(res tui.Drawable) {
r.Lock()
defer r.Unlock()
r.fullContent = make([]string, 0)
for _, line := range res.Content() {
line = strings.Replace(line, "\t", " ", -1)
r.fullContent = append(r.fullContent, line)
}
r.box.Title = res.Title()
r.firstRenderedRow = 0
r.firstRenderedCol = 0
r.writeContent()
}
// writeContent writes content on the screen.
//
// Takes care to render only the portion of the output we can present on the interface.
func (r *TestDetail) writeContent() {
lastLine := r.firstRenderedRow + r.maxRows
r.renderedContent = make([]string, 0)
for i := r.firstRenderedRow; i < lastLine; i++ {
// nothing more to write.
if i >= len(r.fullContent) {
break
}
r.renderedContent = append(
r.renderedContent,
r.cutLine(r.fullContent[i]),
)
}
r.box.Text = strings.Join(r.renderedContent, "\n")
ui.Render(r.box)
}
// cutLine returns the part of the line from firstRenderedCol with maxCols columns.
func (r *TestDetail) cutLine(line string) string {
// we are rendering beyond the end of this line.
if r.firstRenderedCol >= len(line) {
return ""
}
lastRenderedCol := r.firstRenderedCol + r.maxCols
if lastRenderedCol >= len(line) {
return line[r.firstRenderedCol:]
}
return line[r.firstRenderedCol:lastRenderedCol]
}