Codebase list golang-pault-go-technicolor / 0c976fa
Merge tag 'upstream/0.0_git20170523.0.048edec' Upstream version 0.0~git20170523.0.048edec * tag 'upstream/0.0_git20170523.0.048edec': New upstream version 0.0~git20170523.0.048edec Tianon Gravi 6 years ago
3 changed file(s) with 299 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 package main
1
2 import (
3 "os"
4
5 "pault.ag/go/technicolor"
6 )
7
8 func main() {
9 output := technicolor.NewWriter(os.Stdout)
10 output.Bold().Red().Printf("U")
11 output.White().Printf("S")
12 output.Cyan().Printf("A\n")
13 output.ResetColor().Write([]byte{})
14 }
0 package technicolor
1
2 func (w Writer) Red() Writer {
3 return w.Add(RedFg)
4 }
5
6 func (w Writer) Black() Writer {
7 return w.Add(BlackFg)
8 }
9
10 func (w Writer) Green() Writer {
11 return w.Add(GreenFg)
12 }
13
14 func (w Writer) Yellow() Writer {
15 return w.Add(YellowFg)
16 }
17
18 func (w Writer) Blue() Writer {
19 return w.Add(BlueFg)
20 }
21
22 func (w Writer) Magenta() Writer {
23 return w.Add(MagentaFg)
24 }
25
26 func (w Writer) White() Writer {
27 return w.Add(WhiteFg)
28 }
29
30 func (w Writer) ResetColor() Writer {
31 return w.Reset().White()
32 }
33
34 func (w Writer) Cyan() Writer {
35 return w.Add(CyanFg)
36 }
37
38 func Color(color string) ANSISequence {
39 return NewANSISequence([]string{color}, 'm')
40 }
41
42 func ResetColor() ANSISequence {
43 return Color("0")
44 }
45
46 func XTermColor(color string) ANSISequence {
47 return NewANSISequence([]string{"38", "5", color}, 'm')
48 }
49
50 func XTermBackgroundColor(color string) ANSISequence {
51 return NewANSISequence([]string{"48", "5", color}, 'm')
52 }
53
54 func XTermTheme(fg, bg string) ANSISequences {
55 return ANSISequences{XTermColor(fg), XTermBackgroundColor(bg)}
56 }
57
58 var Primary = "025"
59 var PrimaryDarker = "024"
60 var PrimaryDarkest = "017"
61
62 var Base = "016"
63
64 var White = "231"
65
66 var PrimaryAlt = "038"
67 var PrimaryAltDarkest = "024"
68 var PrimaryAltDark = "038"
69 var PrimaryAltLight = "153"
70 var PrimaryAltLightest = "195"
71
72 var Secondary = "161"
73 var SecondaryDarkest = "088"
74 var SecondaryDark = "160"
75 var SecondaryLight = "174"
76 var SecondaryLightest = "224"
77
78 var GrayDark = "059"
79 var Gray = "059"
80 var GrayLight = "145"
81 var GrayLighter = "188"
82 var GrayLightest = "231"
83
84 var GrayWarmDark = "059"
85 var GrayWarmLight = "188"
86
87 var GrayCoolLight = "189"
88
89 var Gold = "214"
90 var GoldLight = "221"
91 var GoldLighter = "222"
92 var GoldLightest = "230"
93
94 var Green = "029"
95 var GreenLight = "071"
96 var GreenLighter = "109"
97 var GreenLightest = "194"
98
99 var CoolBlue = "024"
100 var CoolBlueLight = "067"
101 var CoolBlueLighter = "110"
102 var CoolBlueLightest = "189"
103
104 var Focus = "068"
105 var Visited = "054"
106
107 var BlackFg = XTermColor(Base)
108 var RedFg = XTermColor(SecondaryDark)
109 var GreenFg = XTermColor(GreenLight)
110 var YellowFg = XTermColor(GoldLight)
111 var BlueFg = XTermColor(PrimaryAltLightest)
112 var MagentaFg = XTermColor(Visited)
113 var CyanFg = XTermColor(Focus)
114 var WhiteFg = Color("0")
115
116 var PrimaryDarkestOnWhite = XTermTheme(PrimaryDarkest, White)
117 var PrimaryDarkerOnWhite = XTermTheme(PrimaryDarker, White)
118 var PrimaryOnWhite = XTermTheme(Primary, White)
119 var CoolBlueLightOnWhite = XTermTheme(CoolBlueLight, White)
120 var PrimaryAltDarkestOnWhite = XTermTheme(PrimaryAltDarkest, White)
121 var GreenOnWhite = XTermTheme(Green, White)
122 var VisitedOnWhite = XTermTheme(Visited, White)
123 var BaseOnWhite = XTermTheme(Base, White)
124 var GrayDarkOnWhite = XTermTheme(GrayDark, White)
125 var GrayOnWhite = XTermTheme(Gray, White)
126 var GrayWarmDarkOnWhite = XTermTheme(GrayWarmDark, White)
127 var SecondaryDarkestOnWhite = XTermTheme(SecondaryDarkest, White)
128 var SecondaryDarkOnWhite = XTermTheme(SecondaryDark, White)
129 var SecondaryOnWhite = XTermTheme(Secondary, White)
130
131 var WhiteOnBase = XTermTheme(White, Base)
132 var WhiteOnGrayWarmDark = XTermTheme(White, GrayWarmDark)
133 var WhiteOnGrayDark = XTermTheme(White, GrayDark)
134 var WhiteOnGray = XTermTheme(White, Gray)
135 var WhiteOnPrimaryDarkest = XTermTheme(White, PrimaryDarkest)
136 var WhiteOnPrimaryDarker = XTermTheme(White, PrimaryDarker)
137 var WhiteOnPrimary = XTermTheme(White, Primary)
138 var WhiteOnCoolBlueLight = XTermTheme(White, CoolBlueLight)
139 var WhiteOnPrimaryAltDarkest = XTermTheme(White, PrimaryAltDarkest)
140 var BaseOnPrimaryAltDark = XTermTheme(Base, PrimaryAltDark)
141 var BaseOnPrimaryAlt = XTermTheme(Base, PrimaryAlt)
142 var WhiteOnGreen = XTermTheme(White, Green)
143 var BaseOnGreenLight = XTermTheme(Base, GreenLight)
144 var BaseOnGold = XTermTheme(Base, Gold)
145 var BaseOnGoldLight = XTermTheme(Base, GoldLight)
146 var WhiteOnSecondaryDarkest = XTermTheme(White, SecondaryDarkest)
147 var WhiteOnSecondaryDark = XTermTheme(White, SecondaryDark)
148 var WhiteOnSecondary = XTermTheme(White, Secondary)
149
150 var BaseOnGrayLight = XTermTheme(Base, GrayLight)
151 var BaseOnGrayLighter = XTermTheme(Base, GrayLighter)
152 var BaseOnGrayWarmLight = XTermTheme(Base, GrayWarmLight)
153 var BaseOnCoolBlueLighter = XTermTheme(Base, CoolBlueLighter)
154 var BaseOnCoolBlueLightest = XTermTheme(Base, CoolBlueLightest)
155 var BaseOnPrimaryAltLightest = XTermTheme(Base, PrimaryAltLightest)
156 var BaseOnGreenLighter = XTermTheme(Base, GreenLighter)
157 var BaseOnGreenLightest = XTermTheme(Base, GreenLightest)
158 var BaseOnGoldLighter = XTermTheme(Base, GoldLighter)
159 var BaseOnGoldLightest = XTermTheme(Base, GoldLightest)
160 var BaseOnSecondaryLightest = XTermTheme(Base, SecondaryLightest)
0 package technicolor
1
2 import (
3 "fmt"
4 "io"
5 "os"
6 "strings"
7 "syscall"
8 "unsafe"
9 )
10
11 type ANSISequence []byte
12
13 type ANSISequences []ANSISequence
14
15 // "Flatten" the ANSI Sequences into a single byte stream
16 func (a ANSISequences) Sequence() []byte {
17 out := []byte{}
18 for _, seq := range a {
19 out = append(out, seq...)
20 }
21 return out
22 }
23
24 func NewANSISequence(arguments []string, ansiType byte) ANSISequence {
25 return ANSISequence(append(append([]byte{0x1b, 0x5b},
26 []byte(strings.Join(arguments, ";"))...,
27 ), ansiType))
28 }
29
30 func NewTerminalWriter(file *os.File) Writer {
31 output := NewWriter(file)
32 if IsFileTerminal(file) {
33 output = output.EnableColor()
34 } else {
35 output = output.DisableColor()
36 }
37 return output
38 }
39
40 func NewWriter(o io.Writer) Writer {
41 return Writer{
42 aNSISequences: ANSISequences{},
43 output: o,
44 enableColor: false,
45 }
46 }
47
48 type Writer struct {
49 aNSISequences ANSISequences
50 output io.Writer
51 enableColor bool
52 }
53
54 func (w Writer) DisableColor() Writer {
55 return Writer{
56 aNSISequences: w.aNSISequences,
57 output: w.output,
58 enableColor: false,
59 }
60 }
61
62 func (w Writer) EnableColor() Writer {
63 return Writer{
64 aNSISequences: w.aNSISequences,
65 output: w.output,
66 enableColor: true,
67 }
68 }
69
70 func (w Writer) Bold() Writer {
71 return w.Add(NewANSISequence([]string{"1"}, 'm'))
72 }
73
74 func (w Writer) Add(seqs ...ANSISequence) Writer {
75 return Writer{
76 aNSISequences: append(w.aNSISequences, seqs...),
77 output: w.output,
78 enableColor: w.enableColor,
79 }
80 }
81
82 func (w Writer) Reset(seqs ...ANSISequence) Writer {
83 return Writer{
84 aNSISequences: ANSISequences{},
85 output: w.output,
86 enableColor: w.enableColor,
87 }
88 }
89
90 func (w Writer) Printf(format string, args ...interface{}) (int, error) {
91 return fmt.Fprintf(w, format, args...)
92 }
93
94 func (w Writer) Write(out []byte) (int, error) {
95 if w.enableColor {
96 return w.output.Write(append(w.aNSISequences.Sequence(), out...))
97 }
98 return w.output.Write(out)
99 }
100
101 // This is some yanked nasty shaz that will check to see if a file descriptor
102 // we have is a terminal or something else. This is handy for color stuff,
103 // since we want to be able to pipe things without seeing colors in the
104 // processing pipeline, but also make things sane for a user.
105 func IsTerminal(fd uintptr) bool {
106 var termios syscall.Termios
107 var ioctlReadTermios uintptr = 0x5401 // syscall.TCGETS
108 _, _, err := syscall.Syscall6(
109 syscall.SYS_IOCTL,
110 fd,
111 ioctlReadTermios,
112 uintptr(unsafe.Pointer(&termios)),
113 0, 0, 0,
114 )
115 return err == 0
116 }
117
118 // Check to see if a given os.File is a Terminal. Notibly, `os.Stdout` is
119 // one of these, as is `os.Stderr`.
120 func IsFileTerminal(file *os.File) bool {
121 return IsTerminal(file.Fd())
122 }