github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/output/colorstyle/console_windows.go (about) 1 package colorstyle 2 3 /* 4 Sourced from: https://github.com/daviddengcn/go-colortext 5 See license.txt in same directory for license information 6 */ 7 8 import ( 9 "io" 10 "os" 11 "syscall" 12 "unsafe" 13 14 "github.com/ActiveState/cli/internal/logging" 15 "github.com/ActiveState/cli/internal/multilog" 16 "github.com/ActiveState/cli/internal/rollbar" 17 ) 18 19 var consoleStyleMap = map[Style]uint16{ 20 Black: 0, 21 Red: consoleRed, 22 Green: consoleGreen, 23 Yellow: consoleRed | consoleGreen | consoleIntensity, 24 Blue: consoleBlue, 25 Magenta: consoleRed | consoleBlue, 26 Cyan: consoleGreen | consoleBlue, 27 White: consoleRed | consoleGreen | consoleBlue, 28 Orange: consoleRed | consoleGreen, 29 } 30 31 const ( 32 consoleBlue = uint16(0x0001) 33 consoleGreen = uint16(0x0002) 34 consoleRed = uint16(0x0004) 35 consoleIntensity = uint16(0x0008) 36 37 consoleColorMask = consoleBlue | consoleGreen | consoleRed | consoleIntensity 38 ) 39 40 const ( 41 stdOutHandle = uint32(-11 & 0xFFFFFFFF) 42 ) 43 44 type consoleBufferDimensions struct { 45 X, Y int16 46 } 47 48 type consoleBuffer struct { 49 DwSize consoleBufferDimensions 50 DwCursorPosition consoleBufferDimensions 51 WAttributes uint16 52 SrWindow struct { 53 Left, Top, Right, Bottom int16 54 } 55 DwMaximumWindowSize consoleBufferDimensions 56 } 57 58 var ( 59 kernel32 = syscall.NewLazyDLL("kernel32.dll") 60 61 procGetStdHandle = kernel32.NewProc("GetStdHandle") 62 procSetconsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") 63 procGetconsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") 64 65 hStdout uintptr 66 bufferInfo *consoleBuffer 67 ) 68 69 func init() { 70 kernel32 := syscall.NewLazyDLL("kernel32.dll") 71 procGetStdHandle = kernel32.NewProc("GetStdHandle") 72 hStdout, _, _ = procGetStdHandle.Call(uintptr(stdOutHandle)) 73 bufferInfo = getConsoleScreenBufferInfo(hStdout) 74 _, _ = syscall.LoadDLL("") 75 } 76 77 type Styler struct { 78 } 79 80 func New(writer io.Writer) *Styler { 81 return &Styler{} 82 } 83 84 func (st *Styler) SetStyle(s Style, bright bool) { 85 if bufferInfo == nil { 86 return 87 } 88 89 defer func() { 90 if r := recover(); r != nil { 91 if os.Getenv("CI") == "" { 92 multilog.Log(logging.ErrorNoStacktrace, rollbar.Error)("colorstyle.SetStyle failed with: %v", r) 93 } 94 } 95 }() 96 97 if s == Bold || s == Underline { 98 return // underline/bold is not supported on windows 99 } 100 101 attr := uint16(0) 102 if s == Default || s == Reset { 103 attr = bufferInfo.WAttributes 104 } else if s == Dim { 105 attr = attr & ^consoleColorMask | consoleStyleMap[Black] 106 bright = true 107 } else { 108 if style, ok := consoleStyleMap[s]; ok { 109 attr = attr & ^consoleColorMask | style 110 } 111 } 112 if bright { 113 attr |= consoleIntensity 114 } 115 setConsoleTextAttribute(hStdout, attr) 116 } 117 118 func setConsoleTextAttribute(hconsoleOutput uintptr, wAttributes uint16) bool { 119 ret, _, _ := procSetconsoleTextAttribute.Call( 120 hconsoleOutput, 121 uintptr(wAttributes)) 122 return ret != 0 123 } 124 125 func getConsoleScreenBufferInfo(hconsoleOutput uintptr) *consoleBuffer { 126 var csbi consoleBuffer 127 if ret, _, _ := procGetconsoleScreenBufferInfo.Call(hconsoleOutput, uintptr(unsafe.Pointer(&csbi))); ret == 0 { 128 return nil 129 } 130 return &csbi 131 }