mirror of https://github.com/Textualize/rich.git
commit
038e22eb98
|
@ -1,5 +1,6 @@
|
|||
[run]
|
||||
omit = rich/jupyter.py
|
||||
rich/_windows.py
|
||||
|
||||
[report]
|
||||
exclude_lines =
|
||||
|
|
|
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [3.0.4] - 2020-07-07
|
||||
|
||||
### Changed
|
||||
|
||||
- More precise detection of Windows console https://github.com/willmcgugan/rich/issues/140
|
||||
|
||||
## [3.0.3] - 2020-07-03
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
name = "rich"
|
||||
homepage = "https://github.com/willmcgugan/rich"
|
||||
documentation = "https://rich.readthedocs.io/en/latest/"
|
||||
version = "3.0.3"
|
||||
version = "3.0.4"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
authors = ["Will McGugan <willmcgugan@gmail.com>"]
|
||||
license = "MIT"
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
import sys
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class WindowsConsoleFeatures:
|
||||
"""Windows features available."""
|
||||
|
||||
vt: bool = False
|
||||
truecolor: bool = False
|
||||
|
||||
|
||||
try:
|
||||
import ctypes
|
||||
from ctypes import wintypes
|
||||
from ctypes import LibraryLoader
|
||||
|
||||
windll = LibraryLoader(ctypes.WinDLL) # type: ignore
|
||||
except (AttributeError, ImportError, ValueError):
|
||||
|
||||
# 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 features.
|
||||
|
||||
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__":
|
||||
import platform
|
||||
|
||||
features = get_windows_console_features()
|
||||
from rich import print
|
||||
|
||||
print(f'platform="{platform.system()}"')
|
||||
print(repr(features))
|
||||
|
|
@ -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": # pragma: no cover
|
||||
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:
|
||||
return None
|
||||
if self.legacy_windows: # pragma: no cover
|
||||
return ColorSystem.WINDOWS
|
||||
if "WT_SESSION" in os.environ:
|
||||
# Exception for Windows terminal
|
||||
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
|
||||
)
|
||||
if not self.is_terminal or "NO_COLOR" in os.environ:
|
||||
return None
|
||||
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:
|
||||
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."""
|
||||
|
@ -921,7 +944,7 @@ class Console:
|
|||
"""Check if the buffer may be rendered."""
|
||||
with self._lock:
|
||||
if self._buffer_index == 0:
|
||||
if self.is_jupyter:
|
||||
if self.is_jupyter: # pragma: no cover
|
||||
from .jupyter import display
|
||||
|
||||
display(self._buffer)
|
||||
|
|
|
@ -73,7 +73,7 @@ class ReprHighlighter(RegexHighlighter):
|
|||
highlights = [
|
||||
r"(?P<brace>[\{\[\(\)\]\}])",
|
||||
r"(?P<tag_start>\<)(?P<tag_name>\w*)(?P<tag_contents>.*?)(?P<tag_end>\>)",
|
||||
r"(?P<attrib_name>\w+?)=(?P<attrib_value>\"?\S+\"?)",
|
||||
r"(?P<attrib_name>\w+?)=(?P<attrib_value>\"?[\w_]+\"?)",
|
||||
r"(?P<bool_true>True)|(?P<bool_false>False)|(?P<none>None)",
|
||||
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*\b)",
|
||||
r"(?P<number>0x[0-9a-f]*)",
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
from rich.console import Console
|
||||
|
||||
|
||||
def test_jupyter():
|
||||
console = Console(force_jupyter=True)
|
||||
assert console.width == 93
|
||||
assert console.color_system == "truecolor"
|
Loading…
Reference in New Issue