detect windows

This commit is contained in:
Will McGugan 2020-07-07 15:33:58 +01:00
parent d3bd98712c
commit fb158f81a2
3 changed files with 102 additions and 15 deletions

64
rich/_windows.py Normal file
View File

@ -0,0 +1,64 @@
import sys
from dataclasses import dataclass
@dataclass
class WindowsConsoleFeatures:
"""Windows features available."""
vt: bool
truecolor: bool
try:
import ctypes
from ctypes import wintypes
from ctypes import LibraryLoader
windll = LibraryLoader(ctypes.WinDLL)
except (AttributeError, ImportError):
# Fallback if we can't load the Windows DLL
def get_windows_console_features() -> WindowsConsoleFeatures:
features = WindowsConsoleFeatures()
return features
else:
STDOUT = -11
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
_GetConsoleMode = windll.kernel32.GetConsoleMode
_GetConsoleMode.argtypes = [wintypes.HANDLE, wintypes.LPDWORD]
_GetConsoleMode.restype = wintypes.BOOL
_GetStdHandle = windll.kernel32.GetStdHandle
_GetStdHandle.argtypes = [
wintypes.DWORD,
]
_GetStdHandle.restype = wintypes.HANDLE
def get_windows_console_features() -> WindowsConsoleFeatures:
"""Get windows console fatures.
Returns:
WindowsConsoleFeatures: An instance of WindowsConsoleFeatures.
"""
handle = _GetStdHandle(STDOUT)
console_mode = wintypes.DWORD()
result = _GetConsoleMode(handle, console_mode)
vt = bool(result and console_mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
truecolor = False
if vt:
win_version = sys.getwindowsversion()
truecolor = win_version.major > 10 or (
win_version.major == 10 and win_version.build > 15063
)
features = WindowsConsoleFeatures(vt=vt, truecolor=truecolor)
return features
if __name__ == "__main__":
print(get_windows_console_features())

View File

@ -21,6 +21,7 @@ from typing import (
Iterable,
List,
Optional,
TYPE_CHECKING,
NamedTuple,
Union,
)
@ -44,6 +45,8 @@ from .segment import Segment
from .text import Text, TextType
from .theme import Theme
if TYPE_CHECKING:
from ._windows import WindowsConsoleFeatures
WINDOWS = platform.system() == "Windows"
@ -244,9 +247,22 @@ class RenderHook:
return renderables
_windows_console_features: Optional["WindowsConsoleFeatures"] = None
def get_windows_console_features() -> "WindowsConsoleFeatures":
global _windows_console_features
if _windows_console_features is not None:
return _windows_console_features
from ._windows import get_windows_console_features
_windows_console_features = get_windows_console_features()
return _windows_console_features
def detect_legacy_windows() -> bool:
"""Detect legacy Windows."""
return "WINDIR" in os.environ and "WT_SESSION" not in os.environ
return WINDOWS and not get_windows_console_features().vt
if detect_legacy_windows(): # pragma: no cover
@ -364,19 +380,26 @@ class Console:
def _detect_color_system(self) -> Optional[ColorSystem]:
"""Detect color system from env vars."""
if not self.is_terminal:
if not self.is_terminal or "NO_COLOR" in os.environ:
return None
if self.legacy_windows: # pragma: no cover
return ColorSystem.WINDOWS
if "WT_SESSION" in os.environ:
# Exception for Windows terminal
return ColorSystem.TRUECOLOR
color_term = os.environ.get("COLORTERM", "").strip().lower()
return (
ColorSystem.TRUECOLOR
if color_term in ("truecolor", "24bit")
else ColorSystem.EIGHT_BIT
)
if WINDOWS: # pragma: no cover
if self.legacy_windows: # pragma: no cover
return ColorSystem.WINDOWS
windows_console_features = get_windows_console_features()
return (
ColorSystem.TRUECOLOR
if windows_console_features.truecolor
else ColorSystem.EIGHT_BIT
)
else:
if self.is_jupyter:
return ColorSystem.TRUECOLOR
color_term = os.environ.get("COLORTERM", "").strip().lower()
return (
ColorSystem.TRUECOLOR
if color_term in ("truecolor", "24bit")
else ColorSystem.EIGHT_BIT
)
def _enter_buffer(self) -> None:
"""Enter in to a buffer context, and buffer all output."""

View File

@ -247,9 +247,9 @@ class Style:
for bit in range(9, 13):
if attributes & (1 << bit):
append(_style_map[bit])
if self._color is not None:
if self._color is not None and color_system:
sgr.extend(self._color.downgrade(color_system).get_ansi_codes())
if self._bgcolor is not None:
if self._bgcolor is not None and color_system:
sgr.extend(
self._bgcolor.downgrade(color_system).get_ansi_codes(
foreground=False