diff --git a/README.md b/README.md index a333407..a46fe80 100644 --- a/README.md +++ b/README.md @@ -295,7 +295,7 @@ termenv.DisableMouseAllMotion() | Windows Terminal | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | [^vte]: This covers all vte-based terminals, including Gnome Terminal, guake, Pantheon Terminal, Terminator, Tilix, XFCE Terminal. -[^mux]: Unsupported as multiplexers (like tmux or screen) can be connected to multiple terminals (with different color settings) at the same time. +[^mux]: Unavailable as multiplexers (like tmux or screen) can be connected to multiple terminals (with different color settings) at the same time. You can help improve this list! Check out [how to](ansi_compat.md) and open an issue or pull request. @@ -305,6 +305,20 @@ You can help improve this list! Check out [how to](ansi_compat.md) and open an i - 8-bit (256): rxvt, screen, xterm, Apple Terminal - 4-bit (16): Linux Console +## Platform Support + +`termenv` works on Unix systems (like Linux, macOS, or BSD) and Windows. While +terminal applications on Unix support ANSI styling out-of-the-box, on Windows +you need to enable ANSI processing in your application first: + +```go + mode, err := termenv.EnableWindowsANSIConsole() + if err != nil { + panic(err) + } + defer termenv.RestoreWindowsConsole(mode) +``` + ## Color Chart ![ANSI color chart](https://github.com/muesli/termenv/raw/master/examples/color-chart/color-chart.png) diff --git a/termenv_windows.go b/termenv_windows.go index 2fb8ec5..496163b 100644 --- a/termenv_windows.go +++ b/termenv_windows.go @@ -1,7 +1,12 @@ +//go:build windows // +build windows package termenv +import ( + "golang.org/x/sys/windows" +) + func colorProfile() Profile { return TrueColor } @@ -15,3 +20,40 @@ func backgroundColor() Color { // default black return ANSIColor(0) } + +// EnableWindowsANSI enables virtual terminal processing on Windows platforms. +// This allows the use of ANSI escape sequences in Windows console applications. +// Ensure this gets called before anything gets rendered with termenv. +// Returns the original console mode and an error if one occurred. +func EnableWindowsANSIConsole() (uint32, error) { + handle, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) + if err != nil { + return 0, err + } + + var mode uint32 + err = windows.GetConsoleMode(handle, &mode) + if err != nil { + return 0, err + } + + // See https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences + if mode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING { + vtpmode := mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING + if err := windows.SetConsoleMode(handle, vtpmode); err != nil { + return 0, err + } + } + + return mode, nil +} + +// RestoreWindowsConsole restores the console mode to a previous state. +func RestoreWindowsConsole(mode uint32) error { + handle, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) + if err != nil { + return err + } + + return windows.SetConsoleMode(handle, mode) +}