diff --git a/pre_commit/color.py b/pre_commit/color.py index 686d85bf..25fbb256 100644 --- a/pre_commit/color.py +++ b/pre_commit/color.py @@ -1,7 +1,15 @@ from __future__ import unicode_literals +import os import sys +if os.name == 'nt': # pragma: no cover (windows) + from pre_commit.color_windows import enable_virtual_terminal_processing + try: + enable_virtual_terminal_processing() + except WindowsError: + pass + RED = '\033[41m' GREEN = '\033[42m' YELLOW = '\033[43;30m' diff --git a/pre_commit/color_windows.py b/pre_commit/color_windows.py new file mode 100644 index 00000000..d44e0b80 --- /dev/null +++ b/pre_commit/color_windows.py @@ -0,0 +1,49 @@ +from __future__ import unicode_literals + +from ctypes import POINTER +from ctypes import windll +from ctypes import WinError +from ctypes import WINFUNCTYPE +from ctypes.wintypes import BOOL +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE + +STD_OUTPUT_HANDLE = -11 +ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4 + + +def bool_errcheck(result, func, args): + if not result: + raise WinError() + return args + + +GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)( + ("GetStdHandle", windll.kernel32), + ((1, "nStdHandle"), ) +) + +GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))( + ("GetConsoleMode", windll.kernel32), + ((1, "hConsoleHandle"), (2, "lpMode")) +) +GetConsoleMode.errcheck = bool_errcheck + +SetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, DWORD)( + ("SetConsoleMode", windll.kernel32), + ((1, "hConsoleHandle"), (1, "dwMode")) +) +SetConsoleMode.errcheck = bool_errcheck + + +def enable_virtual_terminal_processing(): + """As of Windows 10, the Windows console supports (some) ANSI escape + sequences, but it needs to be enabled using `SetConsoleMode` first. + + More info on the escape sequences supported: + https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx + + """ + stdout = GetStdHandle(STD_OUTPUT_HANDLE) + flags = GetConsoleMode(stdout) + SetConsoleMode(stdout, flags | ENABLE_VIRTUAL_TERMINAL_PROCESSING)