Spaces:
Runtime error
Runtime error
# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. | |
try: | |
from msvcrt import get_osfhandle | |
except ImportError: | |
def get_osfhandle(_): | |
raise OSError("This isn't windows!") | |
from . import win32 | |
# from wincon.h | |
class WinColor(object): | |
BLACK = 0 | |
BLUE = 1 | |
GREEN = 2 | |
CYAN = 3 | |
RED = 4 | |
MAGENTA = 5 | |
YELLOW = 6 | |
GREY = 7 | |
# from wincon.h | |
class WinStyle(object): | |
NORMAL = 0x00 # dim text, dim background | |
BRIGHT = 0x08 # bright text, dim background | |
BRIGHT_BACKGROUND = 0x80 # dim text, bright background | |
class WinTerm(object): | |
def __init__(self): | |
self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes | |
self.set_attrs(self._default) | |
self._default_fore = self._fore | |
self._default_back = self._back | |
self._default_style = self._style | |
# In order to emulate LIGHT_EX in windows, we borrow the BRIGHT style. | |
# So that LIGHT_EX colors and BRIGHT style do not clobber each other, | |
# we track them separately, since LIGHT_EX is overwritten by Fore/Back | |
# and BRIGHT is overwritten by Style codes. | |
self._light = 0 | |
def get_attrs(self): | |
return self._fore + self._back * 16 + (self._style | self._light) | |
def set_attrs(self, value): | |
self._fore = value & 7 | |
self._back = (value >> 4) & 7 | |
self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) | |
def reset_all(self, on_stderr=None): | |
self.set_attrs(self._default) | |
self.set_console(attrs=self._default) | |
self._light = 0 | |
def fore(self, fore=None, light=False, on_stderr=False): | |
if fore is None: | |
fore = self._default_fore | |
self._fore = fore | |
# Emulate LIGHT_EX with BRIGHT Style | |
if light: | |
self._light |= WinStyle.BRIGHT | |
else: | |
self._light &= ~WinStyle.BRIGHT | |
self.set_console(on_stderr=on_stderr) | |
def back(self, back=None, light=False, on_stderr=False): | |
if back is None: | |
back = self._default_back | |
self._back = back | |
# Emulate LIGHT_EX with BRIGHT_BACKGROUND Style | |
if light: | |
self._light |= WinStyle.BRIGHT_BACKGROUND | |
else: | |
self._light &= ~WinStyle.BRIGHT_BACKGROUND | |
self.set_console(on_stderr=on_stderr) | |
def style(self, style=None, on_stderr=False): | |
if style is None: | |
style = self._default_style | |
self._style = style | |
self.set_console(on_stderr=on_stderr) | |
def set_console(self, attrs=None, on_stderr=False): | |
if attrs is None: | |
attrs = self.get_attrs() | |
handle = win32.STDOUT | |
if on_stderr: | |
handle = win32.STDERR | |
win32.SetConsoleTextAttribute(handle, attrs) | |
def get_position(self, handle): | |
position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition | |
# Because Windows coordinates are 0-based, | |
# and win32.SetConsoleCursorPosition expects 1-based. | |
position.X += 1 | |
position.Y += 1 | |
return position | |
def set_cursor_position(self, position=None, on_stderr=False): | |
if position is None: | |
# I'm not currently tracking the position, so there is no default. | |
# position = self.get_position() | |
return | |
handle = win32.STDOUT | |
if on_stderr: | |
handle = win32.STDERR | |
win32.SetConsoleCursorPosition(handle, position) | |
def cursor_adjust(self, x, y, on_stderr=False): | |
handle = win32.STDOUT | |
if on_stderr: | |
handle = win32.STDERR | |
position = self.get_position(handle) | |
adjusted_position = (position.Y + y, position.X + x) | |
win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) | |
def erase_screen(self, mode=0, on_stderr=False): | |
# 0 should clear from the cursor to the end of the screen. | |
# 1 should clear from the cursor to the beginning of the screen. | |
# 2 should clear the entire screen, and move cursor to (1,1) | |
handle = win32.STDOUT | |
if on_stderr: | |
handle = win32.STDERR | |
csbi = win32.GetConsoleScreenBufferInfo(handle) | |
# get the number of character cells in the current buffer | |
cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y | |
# get number of character cells before current cursor position | |
cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X | |
if mode == 0: | |
from_coord = csbi.dwCursorPosition | |
cells_to_erase = cells_in_screen - cells_before_cursor | |
elif mode == 1: | |
from_coord = win32.COORD(0, 0) | |
cells_to_erase = cells_before_cursor | |
elif mode == 2: | |
from_coord = win32.COORD(0, 0) | |
cells_to_erase = cells_in_screen | |
else: | |
# invalid mode | |
return | |
# fill the entire screen with blanks | |
win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) | |
# now set the buffer's attributes accordingly | |
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) | |
if mode == 2: | |
# put the cursor where needed | |
win32.SetConsoleCursorPosition(handle, (1, 1)) | |
def erase_line(self, mode=0, on_stderr=False): | |
# 0 should clear from the cursor to the end of the line. | |
# 1 should clear from the cursor to the beginning of the line. | |
# 2 should clear the entire line. | |
handle = win32.STDOUT | |
if on_stderr: | |
handle = win32.STDERR | |
csbi = win32.GetConsoleScreenBufferInfo(handle) | |
if mode == 0: | |
from_coord = csbi.dwCursorPosition | |
cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X | |
elif mode == 1: | |
from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) | |
cells_to_erase = csbi.dwCursorPosition.X | |
elif mode == 2: | |
from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) | |
cells_to_erase = csbi.dwSize.X | |
else: | |
# invalid mode | |
return | |
# fill the entire screen with blanks | |
win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) | |
# now set the buffer's attributes accordingly | |
win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) | |
def set_title(self, title): | |
win32.SetConsoleTitle(title) | |
def enable_vt_processing(fd): | |
if win32.windll is None or not win32.winapi_test(): | |
return False | |
try: | |
handle = get_osfhandle(fd) | |
mode = win32.GetConsoleMode(handle) | |
win32.SetConsoleMode( | |
handle, | |
mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING, | |
) | |
mode = win32.GetConsoleMode(handle) | |
if mode & win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING: | |
return True | |
# Can get TypeError in testsuite where 'fd' is a Mock() | |
except (OSError, TypeError): | |
return False | |