// +build windows package logger import ( "os" "strings" "syscall" "unsafe" ) const SupportsColorEscapes = true var kernel32 = syscall.NewLazyDLL("kernel32.dll") var getConsoleMode = kernel32.NewProc("GetConsoleMode") var setConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") var getConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo") type consoleScreenBufferInfo struct { dwSizeX int16 dwSizeY int16 dwCursorPositionX int16 dwCursorPositionY int16 wAttributes uint16 srWindowLeft int16 srWindowTop int16 srWindowRight int16 srWindowBottom int16 dwMaximumWindowSizeX int16 dwMaximumWindowSizeY int16 } func GetTerminalInfo(file *os.File) TerminalInfo { fd := file.Fd() // Is this file descriptor a terminal? var unused uint32 isTTY, _, _ := syscall.Syscall(getConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&unused)), 0) // Get the width of the window var info consoleScreenBufferInfo syscall.Syscall(getConsoleScreenBufferInfo.Addr(), 2, fd, uintptr(unsafe.Pointer(&info)), 0) return TerminalInfo{ IsTTY: isTTY != 0, Width: int(info.dwSizeX) - 1, UseColorEscapes: true, } } func writeStringWithColor(file *os.File, text string) { const FOREGROUND_BLUE = 1 const FOREGROUND_GREEN = 2 const FOREGROUND_RED = 4 const FOREGROUND_INTENSITY = 8 fd := file.Fd() i := 0 for i < len(text) { var attributes uintptr end := i switch { case text[i] != 033: i++ continue case strings.HasPrefix(text[i:], colorReset): i += len(colorReset) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE case strings.HasPrefix(text[i:], colorRed): i += len(colorRed) attributes = FOREGROUND_RED case strings.HasPrefix(text[i:], colorGreen): i += len(colorGreen) attributes = FOREGROUND_GREEN case strings.HasPrefix(text[i:], colorBlue): i += len(colorBlue) attributes = FOREGROUND_BLUE case strings.HasPrefix(text[i:], colorCyan): i += len(colorCyan) attributes = FOREGROUND_GREEN | FOREGROUND_BLUE case strings.HasPrefix(text[i:], colorMagenta): i += len(colorMagenta) attributes = FOREGROUND_RED | FOREGROUND_BLUE case strings.HasPrefix(text[i:], colorYellow): i += len(colorYellow) attributes = FOREGROUND_RED | FOREGROUND_GREEN case strings.HasPrefix(text[i:], colorResetDim): i += len(colorResetDim) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE case strings.HasPrefix(text[i:], colorBold): i += len(colorBold) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY case strings.HasPrefix(text[i:], colorResetBold): i += len(colorResetBold) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY // Apparently underlines only work with the CJK locale on Windows :( case strings.HasPrefix(text[i:], colorResetUnderline): i += len(colorResetUnderline) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE default: i++ continue } file.WriteString(text[:end]) text = text[i:] i = 0 setConsoleTextAttribute.Call(fd, attributes) } file.WriteString(text) }