70 lines
2.2 KiB
Go
70 lines
2.2 KiB
Go
//go:build windows
|
||
|
||
package console
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"syscall"
|
||
"unsafe"
|
||
)
|
||
|
||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||
|
||
// 颜色映射:ANSI -> Windows控制台颜色
|
||
// 0 黑色, 1 蓝色, 2 绿色, 3 青色, 4 红色, 5 紫色, 6 黄色, 7 淡灰色
|
||
// 8 灰色, 9 亮蓝色, 10 亮绿色, 11 亮青色, 12 亮红色, 13 亮紫色, 14 亮黄色, 15 白色
|
||
var colorMap = map[string]uintptr{
|
||
"0;36": 11, // 青色 -> 亮青色
|
||
"0;37": 15, // 白色 -> 白色
|
||
"0;92": 10, // 亮绿色
|
||
"1;93": 14, // 亮黄色
|
||
"1;31": 12, // 亮红色
|
||
}
|
||
|
||
// printColor 彩色打印。
|
||
//
|
||
// 修复 M17:原实现对 syscall.Stdout 设置颜色、却把文本写到 c.output——
|
||
// 当 c.output 非 stdout(如 WithOutput 指向文件)时,颜色落到错误句柄、文本落文件,
|
||
// 二者分裂。现按 c.output 实际类型取句柄:*os.File 用其 Fd(),否则放弃着色只写文本。
|
||
func (c *Console) printColor(code, msg string) {
|
||
color := colorMap[code]
|
||
if color == 0 {
|
||
color = 7 // 默认淡灰色
|
||
}
|
||
|
||
handle, ok := consoleHandle(c.output)
|
||
if !ok {
|
||
// 非 *os.File(如 bytes.Buffer/文件),无法设置控制台属性,退化为纯文本。
|
||
fmt.Fprintln(c.output, msg)
|
||
return
|
||
}
|
||
|
||
proc := kernel32.NewProc("SetConsoleTextAttribute")
|
||
_, _, _ = proc.Call(handle, color)
|
||
fmt.Fprintln(c.output, msg)
|
||
_, _, _ = proc.Call(handle, 7) // 恢复默认颜色
|
||
}
|
||
|
||
// consoleHandle 从 io.Writer 取 Windows 控制台句柄;非 *os.File 返回 (0, false)。
|
||
func consoleHandle(w interface{ Write([]byte) (int, error) }) (uintptr, bool) {
|
||
f, ok := w.(*os.File)
|
||
if !ok {
|
||
return 0, false
|
||
}
|
||
fd := f.Fd()
|
||
switch fd {
|
||
case uintptr(syscall.Stdout), uintptr(syscall.Stderr), uintptr(syscall.Stdin):
|
||
return fd, true
|
||
default:
|
||
// 重定向到文件/管道的 *os.File,SetConsoleTextAttribute 无意义,退化为纯文本。
|
||
return 0, false
|
||
}
|
||
}
|
||
|
||
// (M17:原 EnableVirtualTerminal 为死代码且从未被调用,已移除。
|
||
// Windows 10+ 默认支持 ANSI/VT 着色;需要 VT 的调用方应自行调 kernel32。)
|
||
|
||
// 保留 unsafe 引用以备将来 VT 扩展;当前 printColor 不再需要,故显式抑制未用告警。
|
||
var _ = unsafe.Sizeof(uintptr(0))
|