-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtext_encoders.go
142 lines (124 loc) · 4.05 KB
/
text_encoders.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
134
135
136
137
138
139
140
141
142
package main
import (
"bytes"
"github.com/johan-bolmsjo/errors"
"github.com/johan-bolmsjo/rainbow/internal/ansiterm"
"io"
)
// textEncoder writes escape codes to w according to props.
// The function is used to start encoding escape codes for a line. It may return
// a new function which will be used used to encode the next set of properties.
// This way it's possible to implement delta encoding schemes.
type textEncoder func(w io.Writer, props properties, text []byte) (textEncoder, error)
// textEncoderDummy does not emit any escape codes.
func textEncoderDummy(w io.Writer, props properties, text []byte) (textEncoder, error) {
_, err := w.Write(text)
return textEncoderDummy, err
}
var foregroundANSIColorCode = map[color]ansiterm.Code{
colorBlack: ansiterm.CodeFGBlack,
colorRed: ansiterm.CodeFGRed,
colorGreen: ansiterm.CodeFGGreen,
colorYellow: ansiterm.CodeFGYellow,
colorBlue: ansiterm.CodeFGBlue,
colorMagenta: ansiterm.CodeFGMagenta,
colorCyan: ansiterm.CodeFGCyan,
colorWhite: ansiterm.CodeFGWhite,
colorIBlack: ansiterm.CodeFGIBlack,
colorIRed: ansiterm.CodeFGIRed,
colorIGreen: ansiterm.CodeFGIGreen,
colorIYellow: ansiterm.CodeFGIYellow,
colorIBlue: ansiterm.CodeFGIBlue,
colorIMagenta: ansiterm.CodeFGIMagenta,
colorICyan: ansiterm.CodeFGICyan,
colorIWhite: ansiterm.CodeFGIWhite,
}
var backgroundANSIColorCode = map[color]ansiterm.Code{
colorBlack: ansiterm.CodeBGBlack,
colorRed: ansiterm.CodeBGRed,
colorGreen: ansiterm.CodeBGGreen,
colorYellow: ansiterm.CodeBGYellow,
colorBlue: ansiterm.CodeBGBlue,
colorMagenta: ansiterm.CodeBGMagenta,
colorCyan: ansiterm.CodeBGCyan,
colorWhite: ansiterm.CodeBGWhite,
colorIBlack: ansiterm.CodeBGIBlack,
colorIRed: ansiterm.CodeBGIRed,
colorIGreen: ansiterm.CodeBGIGreen,
colorIYellow: ansiterm.CodeBGIYellow,
colorIBlue: ansiterm.CodeBGIBlue,
colorIMagenta: ansiterm.CodeBGIMagenta,
colorICyan: ansiterm.CodeBGICyan,
colorIWhite: ansiterm.CodeBGIWhite,
}
// textEncoderANSI emits ANSI terminal escape codes.
// See https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
//
// NOTE: Delta encoding of escape codes is currently not performed. Probably not
// worth the complexity to save a couple of bytes of output.
func textEncoderANSI(w io.Writer, props properties, text []byte) (textEncoder, error) {
var es errors.Sink
doWriteCodes := props != properties{}
if doWriteCodes {
var codeBuf [10]ansiterm.Code
codes := codeBuf[:0]
props.modifiers.foreach(func(m modifier) {
code := ansiterm.CodeReset
switch m {
case modifierBold:
code = ansiterm.CodeBold
case modifierUnderline:
code = ansiterm.CodeUnderline
case modifierReverse:
code = ansiterm.CodeReverseVideo
case modifierBlink:
code = ansiterm.CodeSlowBlink
}
if code != ansiterm.CodeReset {
codes = append(codes, code)
}
})
if color := props.fgcolor; color != colorNone {
codes = append(codes, foregroundANSIColorCode[color])
}
if color := props.bgcolor; color != colorNone {
codes = append(codes, backgroundANSIColorCode[color])
}
es.Send(ansiterm.WriteCodes(w, codes...))
}
if es.Ok() {
_, err := w.Write(text)
es.Send(err)
}
if doWriteCodes && es.Ok() {
es.Send(ansiterm.WriteCodes(w, ansiterm.CodeReset))
}
return textEncoderANSI, es.Cause()
}
// textEncoderTest emits escape codes used for testing purpose.
func textEncoderTest(w io.Writer, props properties, text []byte) (textEncoder, error) {
var bb bytes.Buffer
bb.WriteString("fg:")
bb.WriteString(props.fgcolor.String())
bb.WriteString(",bg:")
bb.WriteString(props.bgcolor.String())
bb.WriteString(",mod:[")
emittedModifier := false
props.modifiers.foreach(func(m modifier) {
if emittedModifier {
bb.WriteString(",")
}
bb.WriteString(m.String())
emittedModifier = true
})
bb.WriteString("]")
if pad := 40 - bb.Len(); pad > 0 {
bb.Write(bytes.Repeat([]byte(" "), pad))
}
bb.WriteString("{")
bb.Write(text)
bb.WriteString("}")
bb.WriteString("\n")
_, err := w.Write(bb.Bytes())
return textEncoderTest, err
}