mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Windows console output: Handle consoles with non black and white default colors correctly
This commit is contained in:
parent
8211335683
commit
a4ddfc4a58
@ -12,6 +12,17 @@ from itertools import izip
|
|||||||
|
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
|
|
||||||
|
if iswindows:
|
||||||
|
import ctypes.wintypes
|
||||||
|
class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
('dwSize', ctypes.wintypes._COORD),
|
||||||
|
('dwCursorPosition', ctypes.wintypes._COORD),
|
||||||
|
('wAttributes', ctypes.wintypes.WORD),
|
||||||
|
('srWindow', ctypes.wintypes._SMALL_RECT),
|
||||||
|
('dwMaximumWindowSize', ctypes.wintypes._COORD)
|
||||||
|
]
|
||||||
|
|
||||||
def fmt(code):
|
def fmt(code):
|
||||||
return ('\033[%dm'%code).encode('ascii')
|
return ('\033[%dm'%code).encode('ascii')
|
||||||
|
|
||||||
@ -111,9 +122,16 @@ class Detect(object):
|
|||||||
if f(self.file_handle, byref(mode)):
|
if f(self.file_handle, byref(mode)):
|
||||||
# Stream is a console
|
# Stream is a console
|
||||||
self.set_console = windll.kernel32.SetConsoleTextAttribute
|
self.set_console = windll.kernel32.SetConsoleTextAttribute
|
||||||
self.write_console = WinDLL('kernel32', use_last_error=True).WriteConsoleW
|
kernel32 = WinDLL('kernel32', use_last_error=True)
|
||||||
|
self.write_console = kernel32.WriteConsoleW
|
||||||
self.write_console.argtypes = [wintypes.HANDLE, wintypes.c_wchar_p, wintypes.DWORD, POINTER(wintypes.DWORD), wintypes.LPVOID]
|
self.write_console.argtypes = [wintypes.HANDLE, wintypes.c_wchar_p, wintypes.DWORD, POINTER(wintypes.DWORD), wintypes.LPVOID]
|
||||||
self.write_console.restype = wintypes.BOOL
|
self.write_console.restype = wintypes.BOOL
|
||||||
|
kernel32.GetConsoleScreenBufferInfo.argtypes = [wintypes.HANDLE, ctypes.POINTER(CONSOLE_SCREEN_BUFFER_INFO)]
|
||||||
|
kernel32.GetConsoleScreenBufferInfo.restype = wintypes.BOOL
|
||||||
|
csbi = CONSOLE_SCREEN_BUFFER_INFO()
|
||||||
|
self.default_console_text_attributes = WCOLORS['white']
|
||||||
|
if kernel32.GetConsoleScreenBufferInfo(self.file_handle, byref(csbi)):
|
||||||
|
self.default_console_text_attributes = csbi.wAttributes
|
||||||
self.is_console = True
|
self.is_console = True
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@ -131,7 +149,7 @@ class Detect(object):
|
|||||||
if not self.write_console(self.file_handle, wt, len(t), byref(written), None):
|
if not self.write_console(self.file_handle, wt, len(t), byref(written), None):
|
||||||
# Older versions of windows can fail to write large strings
|
# Older versions of windows can fail to write large strings
|
||||||
# to console with WriteConsoleW (seen it happen on Win XP)
|
# to console with WriteConsoleW (seen it happen on Win XP)
|
||||||
import ctypes, winerror
|
import winerror
|
||||||
err = ctypes.get_last_error()
|
err = ctypes.get_last_error()
|
||||||
if err == winerror.ERROR_NOT_ENOUGH_MEMORY and chunk >= 128:
|
if err == winerror.ERROR_NOT_ENOUGH_MEMORY and chunk >= 128:
|
||||||
# Retry with a smaller chunk size (give up if chunk < 128)
|
# Retry with a smaller chunk size (give up if chunk < 128)
|
||||||
@ -159,6 +177,8 @@ class ColoredStream(Detect):
|
|||||||
self.fg, self.bg, self.bold = fg, bg, bold
|
self.fg, self.bg, self.bold = fg, bg, bold
|
||||||
if self.set_console is not None:
|
if self.set_console is not None:
|
||||||
self.wval = to_flag(self.fg, self.bg, bold)
|
self.wval = to_flag(self.fg, self.bg, bold)
|
||||||
|
if not self.bg:
|
||||||
|
self.wval |= self.default_console_text_attributes & 0xF0
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
if not self.isatty:
|
if not self.isatty:
|
||||||
@ -183,7 +203,7 @@ class ColoredStream(Detect):
|
|||||||
if self.isansi:
|
if self.isansi:
|
||||||
self.stream.write(RESET)
|
self.stream.write(RESET)
|
||||||
elif self.set_console is not None:
|
elif self.set_console is not None:
|
||||||
self.set_console(self.file_handle, WCOLORS['white'])
|
self.set_console(self.file_handle, self.default_console_text_attributes)
|
||||||
|
|
||||||
class ANSIStream(Detect):
|
class ANSIStream(Detect):
|
||||||
|
|
||||||
@ -192,6 +212,7 @@ class ANSIStream(Detect):
|
|||||||
def __init__(self, stream=None):
|
def __init__(self, stream=None):
|
||||||
super(ANSIStream, self).__init__(stream)
|
super(ANSIStream, self).__init__(stream)
|
||||||
self.encoding = getattr(self.stream, 'encoding', 'utf-8') or 'utf-8'
|
self.encoding = getattr(self.stream, 'encoding', 'utf-8') or 'utf-8'
|
||||||
|
self.last_state = (None, None, False)
|
||||||
|
|
||||||
def write(self, text):
|
def write(self, text):
|
||||||
if isinstance(text, type(u'')):
|
if isinstance(text, type(u'')):
|
||||||
@ -217,7 +238,6 @@ class ANSIStream(Detect):
|
|||||||
sequences from the text, and optionally converting them into win32
|
sequences from the text, and optionally converting them into win32
|
||||||
calls.
|
calls.
|
||||||
'''
|
'''
|
||||||
self.last_state = (None, None, False)
|
|
||||||
cursor = 0
|
cursor = 0
|
||||||
for match in self.ANSI_RE.finditer(text):
|
for match in self.ANSI_RE.finditer(text):
|
||||||
start, end = match.span()
|
start, end = match.span()
|
||||||
@ -225,6 +245,7 @@ class ANSIStream(Detect):
|
|||||||
self.convert_ansi(*match.groups())
|
self.convert_ansi(*match.groups())
|
||||||
cursor = end
|
cursor = end
|
||||||
self.write_plain_text(text, cursor, len(text))
|
self.write_plain_text(text, cursor, len(text))
|
||||||
|
self.set_console(self.file_handle, self.default_console_text_attributes)
|
||||||
self.stream.flush()
|
self.stream.flush()
|
||||||
|
|
||||||
def write_plain_text(self, text, start, end):
|
def write_plain_text(self, text, start, end):
|
||||||
@ -263,14 +284,16 @@ class ANSIStream(Detect):
|
|||||||
elif param == 1:
|
elif param == 1:
|
||||||
bold = True
|
bold = True
|
||||||
elif param == 0:
|
elif param == 0:
|
||||||
fg = 'white'
|
fg, bg, bold = None, None, False
|
||||||
bg, bold = None, False
|
|
||||||
|
|
||||||
self.last_state = (fg, bg, bold)
|
self.last_state = (fg, bg, bold)
|
||||||
if fg or bg or bold:
|
if fg or bg or bold:
|
||||||
self.set_console(self.file_handle, to_flag(fg, bg, bold))
|
val = to_flag(fg, bg, bold)
|
||||||
|
if not bg:
|
||||||
|
val |= self.default_console_text_attributes & 0xF0
|
||||||
|
self.set_console(self.file_handle, val)
|
||||||
else:
|
else:
|
||||||
self.set_console(self.file_handle, WCOLORS['white'])
|
self.set_console(self.file_handle, self.default_console_text_attributes)
|
||||||
|
|
||||||
def windows_terminfo():
|
def windows_terminfo():
|
||||||
from ctypes import Structure, byref
|
from ctypes import Structure, byref
|
||||||
|
Loading…
x
Reference in New Issue
Block a user