mirror of
https://github.com/Textualize/rich.git
synced 2025-08-04 01:58:24 +00:00
ansi and tests
This commit is contained in:
parent
d88a08eaf6
commit
8294fee361
7 changed files with 65 additions and 13 deletions
|
@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Added tracebacks_show_locals parameter to RichHandler
|
||||
- Applied dim=True to indent guide styles
|
||||
- Added max_string to Pretty
|
||||
- Added rich.ansi.AnsiDecoder
|
||||
|
||||
## [9.1.0] - 2020-10-23
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ Reference
|
|||
reference/measure.rst
|
||||
reference/padding.rst
|
||||
reference/panel.rst
|
||||
reference/pretty.rst
|
||||
reference/progress.rst
|
||||
reference/progress_bar.rst
|
||||
reference/prompt.rst
|
||||
|
|
6
docs/source/reference/pretty.rst
Normal file
6
docs/source/reference/pretty.rst
Normal file
|
@ -0,0 +1,6 @@
|
|||
rich.pretty
|
||||
===========
|
||||
|
||||
.. automodule:: rich.pretty
|
||||
:members:
|
||||
|
|
@ -146,12 +146,13 @@ class AnsiDecoder:
|
|||
if osc.startswith("8;"):
|
||||
_params, semicolon, link = osc[2:].partition(";")
|
||||
if semicolon:
|
||||
self.style = self.style.update_link(link)
|
||||
self.style = self.style.update_link(link or None)
|
||||
elif sgr:
|
||||
# Translate in to semi-colon separated codes
|
||||
# Ignore invalid codes, because we want to be lenient
|
||||
codes = [int(_code) for _code in sgr.split(";") if _code.isdigit()]
|
||||
codes = [code for code in codes if code <= 255]
|
||||
codes = [
|
||||
min(255, int(_code)) for _code in sgr.split(";") if _code.isdigit()
|
||||
]
|
||||
iter_codes = iter(codes)
|
||||
for code in iter_codes:
|
||||
if code == 0:
|
||||
|
@ -163,15 +164,21 @@ class AnsiDecoder:
|
|||
color_type = next(iter_codes)
|
||||
if color_type == 5:
|
||||
color = from_ansi(next(iter_codes))
|
||||
self.style += (
|
||||
_Style(color=color)
|
||||
if code == 38
|
||||
else _Style(bgcolor=color)
|
||||
)
|
||||
elif color_type == 2:
|
||||
color = from_rgb(
|
||||
next(iter_codes), next(iter_codes), next(iter_codes)
|
||||
)
|
||||
else:
|
||||
continue
|
||||
self.style += (
|
||||
_Style(color=color) if code == 38 else _Style(bgcolor=color)
|
||||
)
|
||||
self.style += (
|
||||
_Style(color=color)
|
||||
if code == 38
|
||||
else _Style(bgcolor=color)
|
||||
)
|
||||
|
||||
return text
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ from typing import (
|
|||
)
|
||||
|
||||
from . import filesize, get_console
|
||||
from .progress_bar import ProgressBar
|
||||
from .ansi import AnsiDecoder
|
||||
from .console import (
|
||||
Console,
|
||||
ConsoleRenderable,
|
||||
|
@ -40,6 +40,7 @@ from .control import Control
|
|||
from .highlighter import Highlighter
|
||||
from .jupyter import JupyterMixin
|
||||
from .live_render import LiveRender
|
||||
from .progress_bar import ProgressBar
|
||||
from .style import StyleType
|
||||
from .table import Table
|
||||
from .text import Text
|
||||
|
@ -480,6 +481,7 @@ class _FileProxy(io.TextIOBase):
|
|||
self.__console = console
|
||||
self.__file = file
|
||||
self.__buffer: List[str] = []
|
||||
self.__ansi_decoder = AnsiDecoder()
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
return getattr(self.__file, name)
|
||||
|
@ -498,7 +500,9 @@ class _FileProxy(io.TextIOBase):
|
|||
if lines:
|
||||
console = self.__console
|
||||
with console:
|
||||
output = "\n".join(lines)
|
||||
output = Text("\n").join(
|
||||
self.__ansi_decoder.decode_line(line) for line in lines
|
||||
)
|
||||
console.print(output, markup=False, emoji=False, highlight=False)
|
||||
return len(text)
|
||||
|
||||
|
@ -846,8 +850,8 @@ class Progress(JupyterMixin, RenderHook):
|
|||
"""Refresh (render) the progress information."""
|
||||
if self.console.is_jupyter: # pragma: no cover
|
||||
try:
|
||||
from ipywidgets import Output
|
||||
from IPython.display import display
|
||||
from ipywidgets import Output
|
||||
except ImportError:
|
||||
import warnings
|
||||
|
||||
|
@ -974,13 +978,13 @@ class Progress(JupyterMixin, RenderHook):
|
|||
|
||||
if __name__ == "__main__": # pragma: no coverage
|
||||
|
||||
import time
|
||||
import random
|
||||
import time
|
||||
|
||||
from .panel import Panel
|
||||
from .rule import Rule
|
||||
from .syntax import Syntax
|
||||
from .table import Table
|
||||
from .rule import Rule
|
||||
|
||||
syntax = Syntax(
|
||||
'''def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:
|
||||
|
|
29
tests/test_ansi.py
Normal file
29
tests/test_ansi.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
import io
|
||||
|
||||
from rich.ansi import AnsiDecoder
|
||||
from rich.console import Console
|
||||
from rich.style import Style
|
||||
from rich.text import Span, Text
|
||||
|
||||
|
||||
def test_decode():
|
||||
console = Console(force_terminal=True, color_system="truecolor")
|
||||
console.begin_capture()
|
||||
console.print("Hello")
|
||||
console.print("[b]foo[/b]")
|
||||
console.print("[link http://example.org]bar")
|
||||
console.print("[#ff0000 on color(200)]red")
|
||||
terminal_codes = console.end_capture()
|
||||
|
||||
decoder = AnsiDecoder()
|
||||
lines = list(decoder.decode(terminal_codes))
|
||||
|
||||
parse = Style.parse
|
||||
expected = [
|
||||
Text("Hello"),
|
||||
Text("foo", spans=[Span(0, 3, parse("bold"))]),
|
||||
Text("bar", spans=[Span(0, 3, parse("link http://example.org"))]),
|
||||
Text("red", spans=[Span(0, 3, parse("#ff0000 on color(200)"))]),
|
||||
]
|
||||
|
||||
assert lines == expected
|
|
@ -73,6 +73,10 @@ def test_from_rgb() -> None:
|
|||
)
|
||||
|
||||
|
||||
def test_from_ansi() -> None:
|
||||
assert Color.from_ansi(1) == Color("color(1)", ColorType.STANDARD, 1)
|
||||
|
||||
|
||||
def test_default() -> None:
|
||||
assert Color.default() == Color("default", ColorType.DEFAULT, None, None)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue