13
"github.com/mattn/go-isatty"
20
foregroundIntensity = 0x8
21
foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
23
backgroundGreen = 0x20
25
backgroundIntensity = 0x80
26
backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
39
type smallRect struct {
46
type consoleScreenBufferInfo struct {
51
maximumWindowSize coord
55
kernel32 = syscall.NewLazyDLL("kernel32.dll")
56
procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
57
procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
67
func NewColorableStdout() io.Writer {
68
var csbi consoleScreenBufferInfo
70
if !isatty.IsTerminal(out.Fd()) {
73
handle := syscall.Handle(out.Fd())
74
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
75
return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
78
func NewColorableStderr() io.Writer {
79
var csbi consoleScreenBufferInfo
81
if !isatty.IsTerminal(out.Fd()) {
84
handle := syscall.Handle(out.Fd())
85
procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
86
return &Writer{out: out, handle: handle, oldattr: csbi.attributes}
89
var color256 = map[int]int{
348
func (w *Writer) Write(data []byte) (n int, err error) {
349
var csbi consoleScreenBufferInfo
350
procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
352
er := bytes.NewBuffer(data)
355
r1, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
360
c1, _, err := er.ReadRune()
365
fmt.Fprint(w.out, string(c1))
368
c2, _, err := er.ReadRune()
370
w.lastbuf.WriteRune(c1)
374
w.lastbuf.WriteRune(c1)
375
w.lastbuf.WriteRune(c2)
382
c, _, err := er.ReadRune()
384
w.lastbuf.WriteRune(c1)
385
w.lastbuf.WriteRune(c2)
386
w.lastbuf.Write(buf.Bytes())
389
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
393
buf.Write([]byte(string(c)))
398
attr := csbi.attributes
401
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr))
404
token := strings.Split(cs, ";")
405
for i, ns := range token {
406
if n, err = strconv.Atoi(ns); err == nil {
408
case n == 0 || n == 100:
410
case 1 <= n && n <= 5:
411
attr |= foregroundIntensity
413
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
414
case 22 == n || n == 25 || n == 25:
415
attr |= foregroundIntensity
417
attr = ((attr & foregroundMask) << 4) | ((attr & backgroundMask) >> 4)
418
case 30 <= n && n <= 37:
419
attr = (attr & backgroundMask)
421
attr |= foregroundRed
424
attr |= foregroundGreen
427
attr |= foregroundBlue
429
case n == 38: // set foreground color.
430
if i < len(token)-2 && token[i+1] == "5" {
431
if n256, err := strconv.Atoi(token[i+2]); err == nil {
432
if n256foreAttr == nil {
435
attr &= backgroundMask
436
attr |= n256foreAttr[n256]
440
attr = attr & (w.oldattr & backgroundMask)
442
case n == 39: // reset foreground color.
443
attr &= backgroundMask
444
attr |= w.oldattr & foregroundMask
445
case 40 <= n && n <= 47:
446
attr = (attr & foregroundMask)
448
attr |= backgroundRed
451
attr |= backgroundGreen
454
attr |= backgroundBlue
456
case n == 48: // set background color.
457
if i < len(token)-2 && token[i+1] == "5" {
458
if n256, err := strconv.Atoi(token[i+2]); err == nil {
459
if n256backAttr == nil {
462
attr &= foregroundMask
463
attr |= n256backAttr[n256]
467
attr = attr & (w.oldattr & foregroundMask)
469
case n == 49: // reset foreground color.
470
attr &= foregroundMask
471
attr |= w.oldattr & backgroundMask
473
procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr))
478
return len(data) - w.lastbuf.Len(), nil
481
type consoleColor struct {
488
func minmax3(a, b, c int) (min, max int) {
508
func toConsoleColor(rgb int) (c consoleColor) {
509
r, g, b := (rgb&0xFF0000)>>16, (rgb&0x00FF00)>>8, rgb&0x0000FF
510
min, max := minmax3(r, g, b)
512
if r < 128 && g < 128 && b < 128 {
522
// non-intensed white is lighter than intensed black, so swap those.
523
if c.red && c.green && c.blue {
524
c.red, c.green, c.blue = false, false, false
542
// intensed black is darker than non-intensed white, so swap those.
543
if !c.red && !c.green && !c.blue {
544
c.red, c.green, c.blue = true, true, true
551
func (c consoleColor) foregroundAttr() (attr word) {
553
attr |= foregroundRed
556
attr |= foregroundGreen
559
attr |= foregroundBlue
562
attr |= foregroundIntensity
567
func (c consoleColor) backgroundAttr() (attr word) {
569
attr |= backgroundRed
572
attr |= backgroundGreen
575
attr |= backgroundBlue
578
attr |= backgroundIntensity
583
var n256foreAttr []word
584
var n256backAttr []word
587
n256foreAttr = make([]word, 256)
588
n256backAttr = make([]word, 256)
589
for i, rgb := range color256 {
590
c := toConsoleColor(rgb)
591
n256foreAttr[i] = c.foregroundAttr()
592
n256backAttr[i] = c.backgroundAttr()