// +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, Height: int(info.dwSizeY) - 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:], TerminalColors.Reset): i += len(TerminalColors.Reset) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE case strings.HasPrefix(text[i:], TerminalColors.Red): i += len(TerminalColors.Red) attributes = FOREGROUND_RED case strings.HasPrefix(text[i:], TerminalColors.Green): i += len(TerminalColors.Green) attributes = FOREGROUND_GREEN case strings.HasPrefix(text[i:], TerminalColors.Blue): i += len(TerminalColors.Blue) attributes = FOREGROUND_BLUE case strings.HasPrefix(text[i:], TerminalColors.Cyan): i += len(TerminalColors.Cyan) attributes = FOREGROUND_GREEN | FOREGROUND_BLUE case strings.HasPrefix(text[i:], TerminalColors.Magenta): i += len(TerminalColors.Magenta) attributes = FOREGROUND_RED | FOREGROUND_BLUE case strings.HasPrefix(text[i:], TerminalColors.Yellow): i += len(TerminalColors.Yellow) attributes = FOREGROUND_RED | FOREGROUND_GREEN case strings.HasPrefix(text[i:], TerminalColors.Dim): i += len(TerminalColors.Dim) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE case strings.HasPrefix(text[i:], TerminalColors.Bold): i += len(TerminalColors.Bold) attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY // Apparently underlines only work with the CJK locale on Windows :( case strings.HasPrefix(text[i:], TerminalColors.Underline): i += len(TerminalColors.Underline) 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) }