As Windows 10 and 11 terminals support ANSI escape sequences natively, correct processing requires the so-called Virtual Terminal Processing Mode to be enabled. Unfortunately, it's not guaranteed that the VT mode is on by default.
This is a minimalistic package with a single function – enable the VT mode on Windows.
$ go get github.com/flexits/vt-enable@latestJust call Enable() before outputting any escape sequences:
package main
import (
// ...
"github.com/flexits/vt-enable"
)
func main() {
// Enable VT mode for Windows; a no-op on other OSes.
vt.Enable()
// ...
}Alternatively, put the call into the init() function.
The operation is based on the WinAPI SetConsoleMode call. The pure implementation is provided below,however, the golang.org/x/sys/windows package provides convenient wrappers, and the resulting code is much shorter.
const (
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
STD_OUTPUT_HANDLE = 0xFFFF_FFFF - 10
)
func EnableAnsi() error {
modKernel32 := windows.NewLazyDLL("kernel32.dll")
procGetStdHandle := modKernel32.NewProc("GetStdHandle")
procGetConsoleMode := modKernel32.NewProc("GetConsoleMode")
procSetConsoleMode := modKernel32.NewProc("SetConsoleMode")
// sets all bits to 1, resuting in the maximum posiible value
maxUintptr := ^uintptr(0)
h, _, err := procGetStdHandle.Call(uintptr(STD_OUTPUT_HANDLE))
if h == maxUintptr {
return err
// TODO use windows.GetLastError() to get the actual code
}
if h == 0 {
return errors.New("no associated standard handles")
}
var mode uint32
r, _, err := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode)))
if r == 0 {
return err
// TODO use windows.GetLastError() to get the actual code
}
newMode := mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING
r, _, err = procSetConsoleMode.Call(h, uintptr(newMode))
if r == 0 {
return err
// TODO use windows.GetLastError() to get the actual code
}
return nil
}