-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsupportscolor.go
147 lines (127 loc) · 3.38 KB
/
supportscolor.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
143
144
145
146
147
// Package supportscolor provides information on the level of color support
// found in a given terminal, obeying OS-specific color flags.
// Testing currently has been done via. iTerm2 manual testing.
package supportscolor
// TODO: Unit Tests, Windows Testing + Different popular terminal testing.
import (
"os"
"strconv"
// TODO: Remove this later.
"github.com/mattn/go-isatty"
)
var (
colorFlags = []string{"colors", "color=true", "color=always"}
noColorFlags = []string{"no-color", "no-colors", "color=false"}
cistrings = []string{"TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI"}
flagMap = make(map[string]bool)
// ForcedColor determines if there are flags in place forcing color.
// This should never really change during the lifetime of a given program.
ForcedColor *bool
)
// init() in this case simply adds the flags to a given map to make lookup easier.
func init() {
for _, elem := range os.Args[1:] {
flagMap[elem] = true
}
}
// ColorSupport represents the given colors the terminal supports.
type ColorSupport struct {
Level int
HasBasic bool
Has256 bool
Has1m bool
}
// checkForcedColor checks to see if the terminal color is set
// to be explicitly a given support level.
func checkForcedColor() {
var boolean bool
if item, envcolor := os.LookupEnv("FORCE_COLOR"); envcolor {
num, _ := strconv.Atoi(item)
boolean = len(item) == 0 || num != 0
ForcedColor = &boolean
return
}
for _, elem := range colorFlags {
if flagMap[elem] {
boolean = true
ForcedColor = &boolean
return
}
}
for _, elem := range noColorFlags {
if flagMap[elem] {
boolean = false
ForcedColor = &boolean
return
}
}
ForcedColor = nil
}
// supportsColor finds the given support level of the temrinal,
// and returns it as an int representing a given level of support.
// TODO: Turn that level into a semi-enum via. iota.
func supportsColor() int {
if ForcedColor == nil {
checkForcedColor()
}
if ForcedColor != nil && *ForcedColor == false {
return 0
}
if flagMap["color=16m"] || flagMap["color=full"] || flagMap["color=truecolor"] {
return 3
}
if flagMap["color=256"] {
return 2
}
if !isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()) {
return 0
}
var min = func() int {
if ForcedColor != nil {
return 1
}
return 0
}
// Are we in a CI that supports colored text?
if _, suc := os.LookupEnv("CI"); suc {
for _, elem := range cistrings {
if res, suc := os.LookupEnv(elem); suc && res != "" {
return 1
}
}
if res, suc := os.LookupEnv("CI_NAME"); suc && res == "codeship" {
return 1
}
return min()
}
// Check to see if our terminal is truecolour
if res, suc := os.LookupEnv("COLORTERM"); suc && res == "truecolor" {
return 3
}
return min()
}
// TranslateLevel translates the given integer support level into a struct
// holding the general levels of support available in the given terminal.
func translateLevel(c int) *ColorSupport {
var support = &ColorSupport{Level: c}
switch {
case c >= 1:
support.HasBasic = true
fallthrough
case c >= 2:
support.Has256 = true
fallthrough
case c == 3:
support.Has1m = true
break
}
return support
}
// GetSupportLevel returns a struct containing whether or not certain
// color sizes are supported in a given terminal.
func GetSupportLevel() *ColorSupport {
if ForcedColor == nil {
checkForcedColor()
}
return translateLevel(supportsColor())
}