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.
This commit is contained in:
John Parent 2022-11-30 18:45:06 -05:00 committed by Peter Scheibel
parent 288e728144
commit 9f0bb4301f
2 changed files with 62 additions and 0 deletions

View file

@ -107,6 +107,64 @@ def __init__(self, message):
_force_color = None _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): def _color_when_value(when):
"""Raise a ValueError for an invalid color setting. """Raise a ValueError for an invalid color setting.

View file

@ -605,6 +605,10 @@ def setup_main_options(args):
for config_var in args.config_vars or []: for config_var in args.config_vars or []:
spack.config.add(fullpath=config_var, scope="command_line") 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) # when to use color (takes always, auto, or never)
color.set_color_when(args.color) color.set_color_when(args.color)