forked from buildkite/terminal-to-html
-
Notifications
You must be signed in to change notification settings - Fork 0
/
output.go
108 lines (96 loc) · 2.18 KB
/
output.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
package terminal
import (
"bytes"
"fmt"
"sort"
"strings"
)
type outputBuffer struct {
buf bytes.Buffer
}
func (b *outputBuffer) appendNodeStyle(n node) {
b.buf.Write([]byte(`<span class="`))
for idx, class := range n.style.asClasses() {
if idx > 0 {
b.buf.Write([]byte(" "))
}
b.buf.Write([]byte(class))
}
b.buf.Write([]byte(`">`))
}
func (b *outputBuffer) closeStyle() {
b.buf.Write([]byte("</span>"))
}
func (b *outputBuffer) appendMeta(namespace string, data map[string]string) {
// We pre-sort the keys to guarantee alphabetical output,
// because Golang `map`s have guaranteed disorder
keys := make([]string, len(data))
// Make a list of the map's keys
i := 0
for key := range data {
keys[i] = key
i++
}
sort.Strings(keys)
b.buf.WriteString("<?" + namespace)
for i := range keys {
key := keys[i]
value := strings.Replace(data[key], `"`, """, -1)
fmt.Fprintf(&b.buf, ` %s="%s"`, key, value)
}
b.buf.WriteString("?>")
}
// Append a character to our outputbuffer, escaping HTML bits as necessary.
func (b *outputBuffer) appendChar(char rune) {
switch char {
case '&':
b.buf.WriteString("&")
case '\'':
b.buf.WriteString("'")
case '<':
b.buf.WriteString("<")
case '>':
b.buf.WriteString(">")
case '"':
b.buf.WriteString(""")
case '/':
b.buf.WriteString("/")
default:
b.buf.WriteRune(char)
}
}
func outputLineAsHTML(line screenLine) string {
var spanOpen bool
var lineBuf outputBuffer
if data, ok := line.metadata[bkNamespace]; ok {
lineBuf.appendMeta(bkNamespace, data)
}
for idx, node := range line.nodes {
if idx == 0 && !node.style.isEmpty() {
lineBuf.appendNodeStyle(node)
spanOpen = true
} else if idx > 0 {
previous := line.nodes[idx-1]
if !node.hasSameStyle(previous) {
if spanOpen {
lineBuf.closeStyle()
spanOpen = false
}
if !node.style.isEmpty() {
lineBuf.appendNodeStyle(node)
spanOpen = true
}
}
}
if elem := node.elem; elem != nil {
lineBuf.buf.WriteString(elem.asHTML())
}
if r, ok := node.getRune(); ok {
lineBuf.appendChar(r)
}
}
if spanOpen {
lineBuf.closeStyle()
}
return strings.TrimRight(lineBuf.buf.String(), " \t")
}