OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / go-kit / kit / log / term / colorwriter_windows.go
1 // The code in this file is adapted from github.com/mattn/go-colorable.
2
3 // +build windows
4
5 package term
6
7 import (
8         "bytes"
9         "fmt"
10         "io"
11         "strconv"
12         "strings"
13         "syscall"
14         "unsafe"
15 )
16
17 type colorWriter struct {
18         out     io.Writer
19         handle  syscall.Handle
20         lastbuf bytes.Buffer
21         oldattr word
22 }
23
24 // NewColorWriter returns an io.Writer that writes to w and provides cross
25 // platform support for ANSI color codes. If w is not a terminal it is
26 // returned unmodified.
27 func NewColorWriter(w io.Writer) io.Writer {
28         if !IsConsole(w) {
29                 return w
30         }
31
32         var csbi consoleScreenBufferInfo
33         handle := syscall.Handle(w.(fder).Fd())
34         procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
35
36         return &colorWriter{
37                 out:     w,
38                 handle:  handle,
39                 oldattr: csbi.attributes,
40         }
41 }
42
43 func (w *colorWriter) Write(data []byte) (n int, err error) {
44         var csbi consoleScreenBufferInfo
45         procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
46
47         er := bytes.NewBuffer(data)
48 loop:
49         for {
50                 r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
51                 if r1 == 0 {
52                         break loop
53                 }
54
55                 c1, _, err := er.ReadRune()
56                 if err != nil {
57                         break loop
58                 }
59                 if c1 != 0x1b {
60                         fmt.Fprint(w.out, string(c1))
61                         continue
62                 }
63                 c2, _, err := er.ReadRune()
64                 if err != nil {
65                         w.lastbuf.WriteRune(c1)
66                         break loop
67                 }
68                 if c2 != 0x5b {
69                         w.lastbuf.WriteRune(c1)
70                         w.lastbuf.WriteRune(c2)
71                         continue
72                 }
73
74                 var buf bytes.Buffer
75                 var m rune
76                 for {
77                         c, _, err := er.ReadRune()
78                         if err != nil {
79                                 w.lastbuf.WriteRune(c1)
80                                 w.lastbuf.WriteRune(c2)
81                                 w.lastbuf.Write(buf.Bytes())
82                                 break loop
83                         }
84                         if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
85                                 m = c
86                                 break
87                         }
88                         buf.Write([]byte(string(c)))
89                 }
90
91                 switch m {
92                 case 'm':
93                         attr := csbi.attributes
94                         cs := buf.String()
95                         if cs == "" {
96                                 procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
97                                 continue
98                         }
99                         token := strings.Split(cs, ";")
100                         intensityMode := word(0)
101                         for _, ns := range token {
102                                 if n, err = strconv.Atoi(ns); err == nil {
103                                         switch {
104                                         case n == 0:
105                                                 attr = w.oldattr
106                                         case n == 1:
107                                                 attr |= intensityMode
108                                         case 30 <= n && n <= 37:
109                                                 attr = (attr & backgroundMask)
110                                                 if (n-30)&1 != 0 {
111                                                         attr |= foregroundRed
112                                                 }
113                                                 if (n-30)&2 != 0 {
114                                                         attr |= foregroundGreen
115                                                 }
116                                                 if (n-30)&4 != 0 {
117                                                         attr |= foregroundBlue
118                                                 }
119                                                 intensityMode = foregroundIntensity
120                                         case n == 39: // reset foreground color
121                                                 attr &= backgroundMask
122                                                 attr |= w.oldattr & foregroundMask
123                                         case 40 <= n && n <= 47:
124                                                 attr = (attr & foregroundMask)
125                                                 if (n-40)&1 != 0 {
126                                                         attr |= backgroundRed
127                                                 }
128                                                 if (n-40)&2 != 0 {
129                                                         attr |= backgroundGreen
130                                                 }
131                                                 if (n-40)&4 != 0 {
132                                                         attr |= backgroundBlue
133                                                 }
134                                                 intensityMode = backgroundIntensity
135                                         case n == 49: // reset background color
136                                                 attr &= foregroundMask
137                                                 attr |= w.oldattr & backgroundMask
138                                         }
139                                         procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
140                                 }
141                         }
142                 }
143         }
144         return len(data) - w.lastbuf.Len(), nil
145 }
146
147 var (
148         procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
149         procSetConsoleTextAttribute    = kernel32.NewProc("SetConsoleTextAttribute")
150 )
151
152 const (
153         foregroundBlue      = 0x1
154         foregroundGreen     = 0x2
155         foregroundRed       = 0x4
156         foregroundIntensity = 0x8
157         foregroundMask      = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
158         backgroundBlue      = 0x10
159         backgroundGreen     = 0x20
160         backgroundRed       = 0x40
161         backgroundIntensity = 0x80
162         backgroundMask      = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
163 )
164
165 type (
166         wchar uint16
167         short int16
168         dword uint32
169         word  uint16
170 )
171
172 type coord struct {
173         x short
174         y short
175 }
176
177 type smallRect struct {
178         left   short
179         top    short
180         right  short
181         bottom short
182 }
183
184 type consoleScreenBufferInfo struct {
185         size              coord
186         cursorPosition    coord
187         attributes        word
188         window            smallRect
189         maximumWindowSize coord
190 }