summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/llnl/util/tty/color.py58
-rw-r--r--lib/spack/spack/main.py4
2 files changed, 62 insertions, 0 deletions
diff --git a/lib/spack/llnl/util/tty/color.py b/lib/spack/llnl/util/tty/color.py
index 83e8316914..a468d19634 100644
--- a/lib/spack/llnl/util/tty/color.py
+++ b/lib/spack/llnl/util/tty/color.py
@@ -107,6 +107,64 @@ color_when_values = {"always": True, "auto": None, "never": False}
_force_color = None
+def try_enable_terminal_color_on_windows():
+ """Turns coloring in Windows terminal by enabling VTP in Windows consoles (CMD/PWSH/CONHOST)
+ Method based on the link below
+ https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#example-of-enabling-virtual-terminal-processing
+
+ Note: No-op on non windows platforms
+ """
+ if sys.platform == "win32":
+ import ctypes
+ import msvcrt
+ from ctypes import wintypes
+
+ try:
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+ DISABLE_NEWLINE_AUTO_RETURN = 0x0008
+ kernel32 = ctypes.WinDLL("kernel32")
+
+ def _err_check(result, func, args):
+ if not result:
+ raise ctypes.WinError(ctypes.get_last_error())
+ return args
+
+ kernel32.GetConsoleMode.errcheck = _err_check
+ kernel32.GetConsoleMode.argtypes = (
+ wintypes.HANDLE, # hConsoleHandle, i.e. GetStdHandle output type
+ ctypes.POINTER(wintypes.DWORD), # result of GetConsoleHandle
+ )
+ kernel32.SetConsoleMode.errcheck = _err_check
+ kernel32.SetConsoleMode.argtypes = (
+ wintypes.HANDLE, # hConsoleHandle, i.e. GetStdHandle output type
+ wintypes.DWORD, # result of GetConsoleHandle
+ )
+ # Use conout$ here to handle a redirectired stdout/get active console associated
+ # with spack
+ with open(r"\\.\CONOUT$", "w") as conout:
+ # Link above would use kernel32.GetStdHandle(-11) however this would not handle
+ # a redirected stdout appropriately, so we always refer to the current CONSOLE out
+ # which is defined as conout$ on Windows.
+ # linked example is follow more or less to the letter beyond this point
+ con_handle = msvcrt.get_osfhandle(conout.fileno())
+ dw_orig_mode = wintypes.DWORD()
+ kernel32.GetConsoleMode(con_handle, ctypes.byref(dw_orig_mode))
+ dw_new_mode_request = (
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN
+ )
+ dw_new_mode = dw_new_mode_request | dw_orig_mode.value
+ kernel32.SetConsoleMode(con_handle, wintypes.DWORD(dw_new_mode))
+ except OSError:
+ # We failed to enable color support for associated console
+ # report and move on but spack will no longer attempt to
+ # color
+ global _force_color
+ _force_color = False
+ from . import debug
+
+ debug("Unable to support color on Windows terminal")
+
+
def _color_when_value(when):
"""Raise a ValueError for an invalid color setting.
diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py
index b95a8562eb..8153839abc 100644
--- a/lib/spack/spack/main.py
+++ b/lib/spack/spack/main.py
@@ -605,6 +605,10 @@ def setup_main_options(args):
for config_var in args.config_vars or []:
spack.config.add(fullpath=config_var, scope="command_line")
+ # On Windows10 console handling for ASCI/VT100 sequences is not
+ # on by default. Turn on before we try to write to console
+ # with color
+ color.try_enable_terminal_color_on_windows()
# when to use color (takes always, auto, or never)
color.set_color_when(args.color)