]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/mattn/go-colorable/colorable_windows.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / mattn / go-colorable / colorable_windows.go
1 // +build windows
2 // +build !appengine
3
4 package colorable
5
6 import (
7 "bytes"
8 "io"
9 "math"
10 "os"
11 "strconv"
12 "strings"
13 "syscall"
14 "unsafe"
15
16 "github.com/mattn/go-isatty"
17 )
18
19 const (
20 foregroundBlue = 0x1
21 foregroundGreen = 0x2
22 foregroundRed = 0x4
23 foregroundIntensity = 0x8
24 foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
25 backgroundBlue = 0x10
26 backgroundGreen = 0x20
27 backgroundRed = 0x40
28 backgroundIntensity = 0x80
29 backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
30 )
31
32 const (
33 genericRead = 0x80000000
34 genericWrite = 0x40000000
35 )
36
37 const (
38 consoleTextmodeBuffer = 0x1
39 )
40
41 type wchar uint16
42 type short int16
43 type dword uint32
44 type word uint16
45
46 type coord struct {
47 x short
48 y short
49 }
50
51 type smallRect struct {
52 left short
53 top short
54 right short
55 bottom short
56 }
57
58 type consoleScreenBufferInfo struct {
59 size coord
60 cursorPosition coord
61 attributes word
62 window smallRect
63 maximumWindowSize coord
64 }
65
66 type consoleCursorInfo struct {
67 size dword
68 visible int32
69 }
70
71 var (
72 kernel32 = syscall.NewLazyDLL("kernel32.dll")
73 procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
74 procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
75 procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
76 procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
77 procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
78 procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
79 procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
80 procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
81 procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
82 )
83
84 // Writer provide colorable Writer to the console
85 type Writer struct {
86 out io.Writer
87 handle syscall.Handle
88 althandle syscall.Handle
89 oldattr word
90 oldpos coord
91 rest bytes.Buffer
92 }
93
94 // NewColorable return new instance of Writer which handle escape sequence from File.
95 func NewColorable(file *os.File) io.Writer {
96 if file == nil {
97 panic("nil passed instead of *os.File to NewColorable()")
98 }
99
100 if isatty.IsTerminal(file.Fd()) {
101 var csbi consoleScreenBufferInfo
102 handle := syscall.Handle(file.Fd())
103 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
104 return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
105 }
106 return file
107 }
108
109 // NewColorableStdout return new instance of Writer which handle escape sequence for stdout.
110 func NewColorableStdout() io.Writer {
111 return NewColorable(os.Stdout)
112 }
113
114 // NewColorableStderr return new instance of Writer which handle escape sequence for stderr.
115 func NewColorableStderr() io.Writer {
116 return NewColorable(os.Stderr)
117 }
118
119 var color256 = map[int]int{
120 0: 0x000000,
121 1: 0x800000,
122 2: 0x008000,
123 3: 0x808000,
124 4: 0x000080,
125 5: 0x800080,
126 6: 0x008080,
127 7: 0xc0c0c0,
128 8: 0x808080,
129 9: 0xff0000,
130 10: 0x00ff00,
131 11: 0xffff00,
132 12: 0x0000ff,
133 13: 0xff00ff,
134 14: 0x00ffff,
135 15: 0xffffff,
136 16: 0x000000,
137 17: 0x00005f,
138 18: 0x000087,
139 19: 0x0000af,
140 20: 0x0000d7,
141 21: 0x0000ff,
142 22: 0x005f00,
143 23: 0x005f5f,
144 24: 0x005f87,
145 25: 0x005faf,
146 26: 0x005fd7,
147 27: 0x005fff,
148 28: 0x008700,
149 29: 0x00875f,
150 30: 0x008787,
151 31: 0x0087af,
152 32: 0x0087d7,
153 33: 0x0087ff,
154 34: 0x00af00,
155 35: 0x00af5f,
156 36: 0x00af87,
157 37: 0x00afaf,
158 38: 0x00afd7,
159 39: 0x00afff,
160 40: 0x00d700,
161 41: 0x00d75f,
162 42: 0x00d787,
163 43: 0x00d7af,
164 44: 0x00d7d7,
165 45: 0x00d7ff,
166 46: 0x00ff00,
167 47: 0x00ff5f,
168 48: 0x00ff87,
169 49: 0x00ffaf,
170 50: 0x00ffd7,
171 51: 0x00ffff,
172 52: 0x5f0000,
173 53: 0x5f005f,
174 54: 0x5f0087,
175 55: 0x5f00af,
176 56: 0x5f00d7,
177 57: 0x5f00ff,
178 58: 0x5f5f00,
179 59: 0x5f5f5f,
180 60: 0x5f5f87,
181 61: 0x5f5faf,
182 62: 0x5f5fd7,
183 63: 0x5f5fff,
184 64: 0x5f8700,
185 65: 0x5f875f,
186 66: 0x5f8787,
187 67: 0x5f87af,
188 68: 0x5f87d7,
189 69: 0x5f87ff,
190 70: 0x5faf00,
191 71: 0x5faf5f,
192 72: 0x5faf87,
193 73: 0x5fafaf,
194 74: 0x5fafd7,
195 75: 0x5fafff,
196 76: 0x5fd700,
197 77: 0x5fd75f,
198 78: 0x5fd787,
199 79: 0x5fd7af,
200 80: 0x5fd7d7,
201 81: 0x5fd7ff,
202 82: 0x5fff00,
203 83: 0x5fff5f,
204 84: 0x5fff87,
205 85: 0x5fffaf,
206 86: 0x5fffd7,
207 87: 0x5fffff,
208 88: 0x870000,
209 89: 0x87005f,
210 90: 0x870087,
211 91: 0x8700af,
212 92: 0x8700d7,
213 93: 0x8700ff,
214 94: 0x875f00,
215 95: 0x875f5f,
216 96: 0x875f87,
217 97: 0x875faf,
218 98: 0x875fd7,
219 99: 0x875fff,
220 100: 0x878700,
221 101: 0x87875f,
222 102: 0x878787,
223 103: 0x8787af,
224 104: 0x8787d7,
225 105: 0x8787ff,
226 106: 0x87af00,
227 107: 0x87af5f,
228 108: 0x87af87,
229 109: 0x87afaf,
230 110: 0x87afd7,
231 111: 0x87afff,
232 112: 0x87d700,
233 113: 0x87d75f,
234 114: 0x87d787,
235 115: 0x87d7af,
236 116: 0x87d7d7,
237 117: 0x87d7ff,
238 118: 0x87ff00,
239 119: 0x87ff5f,
240 120: 0x87ff87,
241 121: 0x87ffaf,
242 122: 0x87ffd7,
243 123: 0x87ffff,
244 124: 0xaf0000,
245 125: 0xaf005f,
246 126: 0xaf0087,
247 127: 0xaf00af,
248 128: 0xaf00d7,
249 129: 0xaf00ff,
250 130: 0xaf5f00,
251 131: 0xaf5f5f,
252 132: 0xaf5f87,
253 133: 0xaf5faf,
254 134: 0xaf5fd7,
255 135: 0xaf5fff,
256 136: 0xaf8700,
257 137: 0xaf875f,
258 138: 0xaf8787,
259 139: 0xaf87af,
260 140: 0xaf87d7,
261 141: 0xaf87ff,
262 142: 0xafaf00,
263 143: 0xafaf5f,
264 144: 0xafaf87,
265 145: 0xafafaf,
266 146: 0xafafd7,
267 147: 0xafafff,
268 148: 0xafd700,
269 149: 0xafd75f,
270 150: 0xafd787,
271 151: 0xafd7af,
272 152: 0xafd7d7,
273 153: 0xafd7ff,
274 154: 0xafff00,
275 155: 0xafff5f,
276 156: 0xafff87,
277 157: 0xafffaf,
278 158: 0xafffd7,
279 159: 0xafffff,
280 160: 0xd70000,
281 161: 0xd7005f,
282 162: 0xd70087,
283 163: 0xd700af,
284 164: 0xd700d7,
285 165: 0xd700ff,
286 166: 0xd75f00,
287 167: 0xd75f5f,
288 168: 0xd75f87,
289 169: 0xd75faf,
290 170: 0xd75fd7,
291 171: 0xd75fff,
292 172: 0xd78700,
293 173: 0xd7875f,
294 174: 0xd78787,
295 175: 0xd787af,
296 176: 0xd787d7,
297 177: 0xd787ff,
298 178: 0xd7af00,
299 179: 0xd7af5f,
300 180: 0xd7af87,
301 181: 0xd7afaf,
302 182: 0xd7afd7,
303 183: 0xd7afff,
304 184: 0xd7d700,
305 185: 0xd7d75f,
306 186: 0xd7d787,
307 187: 0xd7d7af,
308 188: 0xd7d7d7,
309 189: 0xd7d7ff,
310 190: 0xd7ff00,
311 191: 0xd7ff5f,
312 192: 0xd7ff87,
313 193: 0xd7ffaf,
314 194: 0xd7ffd7,
315 195: 0xd7ffff,
316 196: 0xff0000,
317 197: 0xff005f,
318 198: 0xff0087,
319 199: 0xff00af,
320 200: 0xff00d7,
321 201: 0xff00ff,
322 202: 0xff5f00,
323 203: 0xff5f5f,
324 204: 0xff5f87,
325 205: 0xff5faf,
326 206: 0xff5fd7,
327 207: 0xff5fff,
328 208: 0xff8700,
329 209: 0xff875f,
330 210: 0xff8787,
331 211: 0xff87af,
332 212: 0xff87d7,
333 213: 0xff87ff,
334 214: 0xffaf00,
335 215: 0xffaf5f,
336 216: 0xffaf87,
337 217: 0xffafaf,
338 218: 0xffafd7,
339 219: 0xffafff,
340 220: 0xffd700,
341 221: 0xffd75f,
342 222: 0xffd787,
343 223: 0xffd7af,
344 224: 0xffd7d7,
345 225: 0xffd7ff,
346 226: 0xffff00,
347 227: 0xffff5f,
348 228: 0xffff87,
349 229: 0xffffaf,
350 230: 0xffffd7,
351 231: 0xffffff,
352 232: 0x080808,
353 233: 0x121212,
354 234: 0x1c1c1c,
355 235: 0x262626,
356 236: 0x303030,
357 237: 0x3a3a3a,
358 238: 0x444444,
359 239: 0x4e4e4e,
360 240: 0x585858,
361 241: 0x626262,
362 242: 0x6c6c6c,
363 243: 0x767676,
364 244: 0x808080,
365 245: 0x8a8a8a,
366 246: 0x949494,
367 247: 0x9e9e9e,
368 248: 0xa8a8a8,
369 249: 0xb2b2b2,
370 250: 0xbcbcbc,
371 251: 0xc6c6c6,
372 252: 0xd0d0d0,
373 253: 0xdadada,
374 254: 0xe4e4e4,
375 255: 0xeeeeee,
376 }
377
378 // `\033]0;TITLESTR\007`
379 func doTitleSequence(er *bytes.Reader) error {
380 var c byte
381 var err error
382
383 c, err = er.ReadByte()
384 if err != nil {
385 return err
386 }
387 if c != '0' && c != '2' {
388 return nil
389 }
390 c, err = er.ReadByte()
391 if err != nil {
392 return err
393 }
394 if c != ';' {
395 return nil
396 }
397 title := make([]byte, 0, 80)
398 for {
399 c, err = er.ReadByte()
400 if err != nil {
401 return err
402 }
403 if c == 0x07 || c == '\n' {
404 break
405 }
406 title = append(title, c)
407 }
408 if len(title) > 0 {
409 title8, err := syscall.UTF16PtrFromString(string(title))
410 if err == nil {
411 procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
412 }
413 }
414 return nil
415 }
416
417 // Write write data on console
418 func (w *Writer) Write(data []byte) (n int, err error) {
419 var csbi consoleScreenBufferInfo
420 procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
421
422 handle := w.handle
423
424 var er *bytes.Reader
425 if w.rest.Len() > 0 {
426 var rest bytes.Buffer
427 w.rest.WriteTo(&rest)
428 w.rest.Reset()
429 rest.Write(data)
430 er = bytes.NewReader(rest.Bytes())
431 } else {
432 er = bytes.NewReader(data)
433 }
434 var bw [1]byte
435 loop:
436 for {
437 c1, err := er.ReadByte()
438 if err != nil {
439 break loop
440 }
441 if c1 != 0x1b {
442 bw[0] = c1
443 w.out.Write(bw[:])
444 continue
445 }
446 c2, err := er.ReadByte()
447 if err != nil {
448 break loop
449 }
450
451 switch c2 {
452 case '>':
453 continue
454 case ']':
455 w.rest.WriteByte(c1)
456 w.rest.WriteByte(c2)
457 er.WriteTo(&w.rest)
458 if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 {
459 break loop
460 }
461 er = bytes.NewReader(w.rest.Bytes()[2:])
462 err := doTitleSequence(er)
463 if err != nil {
464 break loop
465 }
466 w.rest.Reset()
467 continue
468 // https://github.com/mattn/go-colorable/issues/27
469 case '7':
470 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
471 w.oldpos = csbi.cursorPosition
472 continue
473 case '8':
474 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
475 continue
476 case 0x5b:
477 // execute part after switch
478 default:
479 continue
480 }
481
482 w.rest.WriteByte(c1)
483 w.rest.WriteByte(c2)
484 er.WriteTo(&w.rest)
485
486 var buf bytes.Buffer
487 var m byte
488 for i, c := range w.rest.Bytes()[2:] {
489 if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
490 m = c
491 er = bytes.NewReader(w.rest.Bytes()[2+i+1:])
492 w.rest.Reset()
493 break
494 }
495 buf.Write([]byte(string(c)))
496 }
497 if m == 0 {
498 break loop
499 }
500
501 switch m {
502 case 'A':
503 n, err = strconv.Atoi(buf.String())
504 if err != nil {
505 continue
506 }
507 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
508 csbi.cursorPosition.y -= short(n)
509 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
510 case 'B':
511 n, err = strconv.Atoi(buf.String())
512 if err != nil {
513 continue
514 }
515 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
516 csbi.cursorPosition.y += short(n)
517 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
518 case 'C':
519 n, err = strconv.Atoi(buf.String())
520 if err != nil {
521 continue
522 }
523 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
524 csbi.cursorPosition.x += short(n)
525 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
526 case 'D':
527 n, err = strconv.Atoi(buf.String())
528 if err != nil {
529 continue
530 }
531 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
532 csbi.cursorPosition.x -= short(n)
533 if csbi.cursorPosition.x < 0 {
534 csbi.cursorPosition.x = 0
535 }
536 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
537 case 'E':
538 n, err = strconv.Atoi(buf.String())
539 if err != nil {
540 continue
541 }
542 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
543 csbi.cursorPosition.x = 0
544 csbi.cursorPosition.y += short(n)
545 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
546 case 'F':
547 n, err = strconv.Atoi(buf.String())
548 if err != nil {
549 continue
550 }
551 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
552 csbi.cursorPosition.x = 0
553 csbi.cursorPosition.y -= short(n)
554 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
555 case 'G':
556 n, err = strconv.Atoi(buf.String())
557 if err != nil {
558 continue
559 }
560 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
561 csbi.cursorPosition.x = short(n - 1)
562 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
563 case 'H', 'f':
564 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
565 if buf.Len() > 0 {
566 token := strings.Split(buf.String(), ";")
567 switch len(token) {
568 case 1:
569 n1, err := strconv.Atoi(token[0])
570 if err != nil {
571 continue
572 }
573 csbi.cursorPosition.y = short(n1 - 1)
574 case 2:
575 n1, err := strconv.Atoi(token[0])
576 if err != nil {
577 continue
578 }
579 n2, err := strconv.Atoi(token[1])
580 if err != nil {
581 continue
582 }
583 csbi.cursorPosition.x = short(n2 - 1)
584 csbi.cursorPosition.y = short(n1 - 1)
585 }
586 } else {
587 csbi.cursorPosition.y = 0
588 }
589 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
590 case 'J':
591 n := 0
592 if buf.Len() > 0 {
593 n, err = strconv.Atoi(buf.String())
594 if err != nil {
595 continue
596 }
597 }
598 var count, written dword
599 var cursor coord
600 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
601 switch n {
602 case 0:
603 cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
604 count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
605 case 1:
606 cursor = coord{x: csbi.window.left, y: csbi.window.top}
607 count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x)
608 case 2:
609 cursor = coord{x: csbi.window.left, y: csbi.window.top}
610 count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
611 }
612 procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
613 procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
614 case 'K':
615 n := 0
616 if buf.Len() > 0 {
617 n, err = strconv.Atoi(buf.String())
618 if err != nil {
619 continue
620 }
621 }
622 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
623 var cursor coord
624 var count, written dword
625 switch n {
626 case 0:
627 cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
628 count = dword(csbi.size.x - csbi.cursorPosition.x)
629 case 1:
630 cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
631 count = dword(csbi.size.x - csbi.cursorPosition.x)
632 case 2:
633 cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
634 count = dword(csbi.size.x)
635 }
636 procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
637 procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
638 case 'm':
639 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
640 attr := csbi.attributes
641 cs := buf.String()
642 if cs == "" {
643 procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr))
644 continue
645 }
646 token := strings.Split(cs, ";")
647 for i := 0; i < len(token); i++ {
648 ns := token[i]
649 if n, err = strconv.Atoi(ns); err == nil {
650 switch {
651 case n == 0 || n == 100:
652 attr = w.oldattr
653 case 1 <= n && n <= 5:
654 attr |= foregroundIntensity
655 case n == 7:
656 attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
657 case n == 22 || n == 25:
658 attr |= foregroundIntensity
659 case n == 27:
660 attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
661 case 30 <= n && n <= 37:
662 attr &= backgroundMask
663 if (n-30)&1 != 0 {
664 attr |= foregroundRed
665 }
666 if (n-30)&2 != 0 {
667 attr |= foregroundGreen
668 }
669 if (n-30)&4 != 0 {
670 attr |= foregroundBlue
671 }
672 case n == 38: // set foreground color.
673 if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
674 if n256, err := strconv.Atoi(token[i+2]); err == nil {
675 if n256foreAttr == nil {
676 n256setup()
677 }
678 attr &= backgroundMask
679 attr |= n256foreAttr[n256]
680 i += 2
681 }
682 } else if len(token) == 5 && token[i+1] == "2" {
683 var r, g, b int
684 r, _ = strconv.Atoi(token[i+2])
685 g, _ = strconv.Atoi(token[i+3])
686 b, _ = strconv.Atoi(token[i+4])
687 i += 4
688 if r > 127 {
689 attr |= foregroundRed
690 }
691 if g > 127 {
692 attr |= foregroundGreen
693 }
694 if b > 127 {
695 attr |= foregroundBlue
696 }
697 } else {
698 attr = attr & (w.oldattr & backgroundMask)
699 }
700 case n == 39: // reset foreground color.
701 attr &= backgroundMask
702 attr |= w.oldattr & foregroundMask
703 case 40 <= n && n <= 47:
704 attr &= foregroundMask
705 if (n-40)&1 != 0 {
706 attr |= backgroundRed
707 }
708 if (n-40)&2 != 0 {
709 attr |= backgroundGreen
710 }
711 if (n-40)&4 != 0 {
712 attr |= backgroundBlue
713 }
714 case n == 48: // set background color.
715 if i < len(token)-2 && token[i+1] == "5" {
716 if n256, err := strconv.Atoi(token[i+2]); err == nil {
717 if n256backAttr == nil {
718 n256setup()
719 }
720 attr &= foregroundMask
721 attr |= n256backAttr[n256]
722 i += 2
723 }
724 } else if len(token) == 5 && token[i+1] == "2" {
725 var r, g, b int
726 r, _ = strconv.Atoi(token[i+2])
727 g, _ = strconv.Atoi(token[i+3])
728 b, _ = strconv.Atoi(token[i+4])
729 i += 4
730 if r > 127 {
731 attr |= backgroundRed
732 }
733 if g > 127 {
734 attr |= backgroundGreen
735 }
736 if b > 127 {
737 attr |= backgroundBlue
738 }
739 } else {
740 attr = attr & (w.oldattr & foregroundMask)
741 }
742 case n == 49: // reset foreground color.
743 attr &= foregroundMask
744 attr |= w.oldattr & backgroundMask
745 case 90 <= n && n <= 97:
746 attr = (attr & backgroundMask)
747 attr |= foregroundIntensity
748 if (n-90)&1 != 0 {
749 attr |= foregroundRed
750 }
751 if (n-90)&2 != 0 {
752 attr |= foregroundGreen
753 }
754 if (n-90)&4 != 0 {
755 attr |= foregroundBlue
756 }
757 case 100 <= n && n <= 107:
758 attr = (attr & foregroundMask)
759 attr |= backgroundIntensity
760 if (n-100)&1 != 0 {
761 attr |= backgroundRed
762 }
763 if (n-100)&2 != 0 {
764 attr |= backgroundGreen
765 }
766 if (n-100)&4 != 0 {
767 attr |= backgroundBlue
768 }
769 }
770 procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
771 }
772 }
773 case 'h':
774 var ci consoleCursorInfo
775 cs := buf.String()
776 if cs == "5>" {
777 procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
778 ci.visible = 0
779 procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
780 } else if cs == "?25" {
781 procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
782 ci.visible = 1
783 procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
784 } else if cs == "?1049" {
785 if w.althandle == 0 {
786 h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0)
787 w.althandle = syscall.Handle(h)
788 if w.althandle != 0 {
789 handle = w.althandle
790 }
791 }
792 }
793 case 'l':
794 var ci consoleCursorInfo
795 cs := buf.String()
796 if cs == "5>" {
797 procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
798 ci.visible = 1
799 procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
800 } else if cs == "?25" {
801 procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
802 ci.visible = 0
803 procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
804 } else if cs == "?1049" {
805 if w.althandle != 0 {
806 syscall.CloseHandle(w.althandle)
807 w.althandle = 0
808 handle = w.handle
809 }
810 }
811 case 's':
812 procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
813 w.oldpos = csbi.cursorPosition
814 case 'u':
815 procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
816 }
817 }
818
819 return len(data), nil
820 }
821
822 type consoleColor struct {
823 rgb int
824 red bool
825 green bool
826 blue bool
827 intensity bool
828 }
829
830 func (c consoleColor) foregroundAttr() (attr word) {
831 if c.red {
832 attr |= foregroundRed
833 }
834 if c.green {
835 attr |= foregroundGreen
836 }
837 if c.blue {
838 attr |= foregroundBlue
839 }
840 if c.intensity {
841 attr |= foregroundIntensity
842 }
843 return
844 }
845
846 func (c consoleColor) backgroundAttr() (attr word) {
847 if c.red {
848 attr |= backgroundRed
849 }
850 if c.green {
851 attr |= backgroundGreen
852 }
853 if c.blue {
854 attr |= backgroundBlue
855 }
856 if c.intensity {
857 attr |= backgroundIntensity
858 }
859 return
860 }
861
862 var color16 = []consoleColor{
863 {0x000000, false, false, false, false},
864 {0x000080, false, false, true, false},
865 {0x008000, false, true, false, false},
866 {0x008080, false, true, true, false},
867 {0x800000, true, false, false, false},
868 {0x800080, true, false, true, false},
869 {0x808000, true, true, false, false},
870 {0xc0c0c0, true, true, true, false},
871 {0x808080, false, false, false, true},
872 {0x0000ff, false, false, true, true},
873 {0x00ff00, false, true, false, true},
874 {0x00ffff, false, true, true, true},
875 {0xff0000, true, false, false, true},
876 {0xff00ff, true, false, true, true},
877 {0xffff00, true, true, false, true},
878 {0xffffff, true, true, true, true},
879 }
880
881 type hsv struct {
882 h, s, v float32
883 }
884
885 func (a hsv) dist(b hsv) float32 {
886 dh := a.h - b.h
887 switch {
888 case dh > 0.5:
889 dh = 1 - dh
890 case dh < -0.5:
891 dh = -1 - dh
892 }
893 ds := a.s - b.s
894 dv := a.v - b.v
895 return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
896 }
897
898 func toHSV(rgb int) hsv {
899 r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
900 float32((rgb&0x00FF00)>>8)/256.0,
901 float32(rgb&0x0000FF)/256.0
902 min, max := minmax3f(r, g, b)
903 h := max - min
904 if h > 0 {
905 if max == r {
906 h = (g - b) / h
907 if h < 0 {
908 h += 6
909 }
910 } else if max == g {
911 h = 2 + (b-r)/h
912 } else {
913 h = 4 + (r-g)/h
914 }
915 }
916 h /= 6.0
917 s := max - min
918 if max != 0 {
919 s /= max
920 }
921 v := max
922 return hsv{h: h, s: s, v: v}
923 }
924
925 type hsvTable []hsv
926
927 func toHSVTable(rgbTable []consoleColor) hsvTable {
928 t := make(hsvTable, len(rgbTable))
929 for i, c := range rgbTable {
930 t[i] = toHSV(c.rgb)
931 }
932 return t
933 }
934
935 func (t hsvTable) find(rgb int) consoleColor {
936 hsv := toHSV(rgb)
937 n := 7
938 l := float32(5.0)
939 for i, p := range t {
940 d := hsv.dist(p)
941 if d < l {
942 l, n = d, i
943 }
944 }
945 return color16[n]
946 }
947
948 func minmax3f(a, b, c float32) (min, max float32) {
949 if a < b {
950 if b < c {
951 return a, c
952 } else if a < c {
953 return a, b
954 } else {
955 return c, b
956 }
957 } else {
958 if a < c {
959 return b, c
960 } else if b < c {
961 return b, a
962 } else {
963 return c, a
964 }
965 }
966 }
967
968 var n256foreAttr []word
969 var n256backAttr []word
970
971 func n256setup() {
972 n256foreAttr = make([]word, 256)
973 n256backAttr = make([]word, 256)
974 t := toHSVTable(color16)
975 for i, rgb := range color256 {
976 c := t.find(rgb)
977 n256foreAttr[i] = c.foregroundAttr()
978 n256backAttr[i] = c.backgroundAttr()
979 }
980 }