项目文件夹

文件
2026-07-14 10:24:10 +08:00

70 行
2.2 KiB
Go

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
//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))