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:
parent
288e728144
commit
9f0bb4301f
2 changed files with 62 additions and 0 deletions
|
@ -107,6 +107,64 @@ def __init__(self, message):
|
|||
_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.
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue