summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Parent <john.parent@kitware.com>2022-11-30 18:45:06 -0500
committerPeter Scheibel <scheibel1@llnl.gov>2023-01-09 09:14:17 -0800
commit9f0bb4301f0514a9367ca9289ceb6a5cf2b3bfa0 (patch)
tree10a7508248afb7983153c93f5526caa98e3793e8
parent288e72814491c9ea579f5baa4c039c69ba2a0ca2 (diff)
downloadspack-9f0bb4301f0514a9367ca9289ceb6a5cf2b3bfa0.tar.gz
spack-9f0bb4301f0514a9367ca9289ceb6a5cf2b3bfa0.tar.bz2
spack-9f0bb4301f0514a9367ca9289ceb6a5cf2b3bfa0.tar.xz
spack-9f0bb4301f0514a9367ca9289ceb6a5cf2b3bfa0.zip
Support ASCI control
Windows CMD prompt does not automatically support ASCI color control characters on the console from Python. Enable this behavior by accessing the current console and allowing the interpreation of ASCI control characters from Python via the win32 API.
-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)