Skip to content

Commit

Permalink
Merge pull request #180 from willmcgugan/newline-fix
Browse files Browse the repository at this point in the history
Newline fix
  • Loading branch information
willmcgugan committed Jul 27, 2020
2 parents cefafdc + dbdade8 commit 579a29c
Show file tree
Hide file tree
Showing 24 changed files with 421 additions and 137 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/pythonpackage.yml
@@ -1,14 +1,13 @@
name: Test Rich module

on: [push, pull_request]
on: [pull_request]

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
max-parallel: 4
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
os: [windows-latest, ubuntu-latest, macos-latest]
python-version: [3.6, 3.7, 3.8]

steps:
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,15 @@ 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).

## [4.2.0] - 2020-07-27

### Fixed

- Fixed missing new lines https://github.com/willmcgugan/rich/issues/178
- Fixed Progress.track https://github.com/willmcgugan/rich/issues/184
- Remove control codes from exported text https://github.com/willmcgugan/rich/issues/181
- Implemented auto-detection and color rendition of 16-color mode

## [4.1.0] - 2020-07-26

### Changed
Expand Down
4 changes: 2 additions & 2 deletions docs/source/reference/emoji.rst
@@ -1,5 +1,5 @@
rich.box
========
rich.emoji
==========

.. automodule:: rich.emoji
:members: Emoji
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Expand Up @@ -2,7 +2,7 @@
name = "rich"
homepage = "https://github.com/willmcgugan/rich"
documentation = "https://rich.readthedocs.io/en/latest/"
version = "4.1.0"
version = "4.2.0"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
authors = ["Will McGugan <willmcgugan@gmail.com>"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion rich/__main__.py
Expand Up @@ -75,7 +75,7 @@ def make_test_card() -> Table:
"Text",
RenderGroup(
Text.from_markup(
"""Word wrap text. Justify [green]left[/], [yellow]center[/], [blue]right[/] or [red]full[/].\n\n"""
"""Word wrap text. Justify [green]left[/], [yellow]center[/], [blue]right[/] or [red]full[/].\n"""
),
lorem_table,
),
Expand Down
36 changes: 30 additions & 6 deletions rich/_palettes.py
Expand Up @@ -2,19 +2,42 @@


# The standard ansi colors
WINDOWS_PALETTE = Palette(
[
(0, 0, 0),
(128, 0, 0),
(0, 128, 0),
(128, 128, 0),
(0, 0, 128),
(128, 0, 128),
(0, 128, 128),
(192, 192, 192),
]
)

# # The standard ansi colors (including bright variants)
STANDARD_PALETTE = Palette(
[
(0, 0, 0),
(255, 0, 0),
(0, 255, 0),
(255, 255, 0),
(0, 0, 255),
(255, 0, 255),
(0, 255, 255),
(170, 0, 0),
(0, 170, 0),
(170, 85, 0),
(0, 0, 170),
(170, 0, 170),
(0, 170, 170),
(170, 170, 170),
(85, 85, 85),
(255, 85, 85),
(85, 255, 85),
(255, 255, 85),
(85, 85, 255),
(255, 85, 255),
(85, 255, 255),
(255, 255, 255),
]
)


# The 256 color palette
EIGHT_BIT_PALETTE = Palette(
[
Expand Down Expand Up @@ -276,3 +299,4 @@
(238, 238, 238),
]
)

30 changes: 19 additions & 11 deletions rich/color.py
@@ -1,11 +1,11 @@
import platform
import re
from colorsys import rgb_to_hls
from enum import IntEnum
from functools import lru_cache
import platform
from typing import NamedTuple, Optional, Tuple, TYPE_CHECKING
from typing import TYPE_CHECKING, NamedTuple, Optional, Tuple

from ._palettes import STANDARD_PALETTE, EIGHT_BIT_PALETTE
from ._palettes import EIGHT_BIT_PALETTE, STANDARD_PALETTE, WINDOWS_PALETTE
from .color_triplet import ColorTriplet
from .terminal_theme import DEFAULT_TERMINAL_THEME

Expand Down Expand Up @@ -297,10 +297,7 @@ def get_truecolor(
return self.triplet
elif self.type == ColorType.EIGHT_BIT:
assert self.number is not None
if self.number <= 15:
return theme.ansi_colors[self.number]
else:
return EIGHT_BIT_PALETTE[self.number]
return EIGHT_BIT_PALETTE[self.number]
elif self.type == ColorType.STANDARD:
assert self.number is not None
return theme.ansi_colors[self.number]
Expand Down Expand Up @@ -347,7 +344,7 @@ def parse(cls, color: str) -> "Color":
color,
type=(
ColorType.STANDARD
if named_color_number < 8
if named_color_number < 16
else ColorType.EIGHT_BIT
),
number=named_color_number,
Expand All @@ -362,7 +359,11 @@ def parse(cls, color: str) -> "Color":
number = int(color_8)
if number > 255:
raise ColorParseError(f"8bit colors must be <= 255 in {color!r}")
return cls(color, ColorType.EIGHT_BIT, number=number)
return cls(
color,
ColorType.STANDARD if number < 16 else ColorType.EIGHT_BIT,
number=number,
)

elif color_24:
triplet = ColorTriplet(
Expand All @@ -387,11 +388,17 @@ def get_ansi_codes(self, foreground: bool = True) -> Tuple[str, ...]:
if _type == ColorType.DEFAULT:
return ("39" if foreground else "49",)

elif _type in (ColorType.STANDARD, ColorType.WINDOWS):
elif _type == ColorType.WINDOWS:
number = self.number
assert number is not None
return (str(30 + number if foreground else 40 + number),)

elif _type == ColorType.STANDARD:
number = self.number
assert number is not None
fore, back = (30, 40) if number < 8 else (82, 92)
return (str(fore + number if foreground else back + number),)

elif _type == ColorType.EIGHT_BIT:
assert self.number is not None
return ("38" if foreground else "48", "5", str(self.number))
Expand All @@ -410,6 +417,7 @@ def downgrade(self, system: ColorSystem) -> "Color":
# Convert to 8-bit color from truecolor color
if system == ColorSystem.EIGHT_BIT and self.system == ColorSystem.TRUECOLOR:
assert self.triplet is not None

red, green, blue = self.triplet.normalized
_h, l, s = rgb_to_hls(red, green, blue)

Expand Down Expand Up @@ -453,7 +461,7 @@ def downgrade(self, system: ColorSystem) -> "Color":
return Color(self.name, ColorType.WINDOWS, number=self.number - 8)
triplet = ColorTriplet(*EIGHT_BIT_PALETTE[self.number])

color_number = STANDARD_PALETTE.match(triplet)
color_number = WINDOWS_PALETTE.match(triplet)
return Color(self.name, ColorType.WINDOWS, number=color_number)

return self
Expand Down
23 changes: 16 additions & 7 deletions rich/console.py
Expand Up @@ -73,6 +73,8 @@
</html>
"""

_TERM_COLORS = {"256color": ColorSystem.EIGHT_BIT, "16color": ColorSystem.STANDARD}


@dataclass
class ConsoleOptions:
Expand Down Expand Up @@ -406,11 +408,12 @@ def _detect_color_system(self) -> Optional[ColorSystem]:
)
else:
color_term = self._environ.get("COLORTERM", "").strip().lower()
return (
ColorSystem.TRUECOLOR
if color_term in ("truecolor", "24bit")
else ColorSystem.EIGHT_BIT
)
if color_term in ("truecolor", "24bit"):
return ColorSystem.TRUECOLOR
term = self._environ.get("TERM", "").strip().lower()
_term_name, _hyphen, colors = term.partition("-")
color_system = _TERM_COLORS.get(colors, ColorSystem.STANDARD)
return color_system

def _enter_buffer(self) -> None:
"""Enter in to a buffer context, and buffer all output."""
Expand Down Expand Up @@ -784,6 +787,7 @@ def check_text() -> None:
append_text(_highlighter(str(renderable)))

check_text()

return renderables

def rule(
Expand Down Expand Up @@ -1046,7 +1050,7 @@ def export_text(self, *, clear: bool = True, styles: bool = False) -> str:
Args:
clear (bool, optional): Set to ``True`` to clear the record buffer after exporting.
styles (bool, optional): If ``True``, ansi style codes will be included. ``False`` for plain text.
styles (bool, optional): If ``True``, ansi escape codes will be included. ``False`` for plain text.
Defaults to ``False``.
Returns:
Expand All @@ -1064,7 +1068,11 @@ def export_text(self, *, clear: bool = True, styles: bool = False) -> str:
for text, style, _ in self._record_buffer
)
else:
text = "".join(text for text, _, _ in self._record_buffer)
text = "".join(
segment.text
for segment in self._record_buffer
if not segment.is_control
)
if clear:
del self._record_buffer[:]
return text
Expand Down Expand Up @@ -1196,6 +1204,7 @@ def save_html(

if __name__ == "__main__": # pragma: no cover
console = Console()

console.log(
"JSONRPC [i]request[/i]",
5,
Expand Down
6 changes: 4 additions & 2 deletions rich/markdown.py
Expand Up @@ -156,7 +156,7 @@ def __rich_console__(
else:
# Styled text for h2 and beyond
if self.level == 2:
yield Text("\n")
yield Text("")
yield text


Expand All @@ -180,7 +180,9 @@ def __rich_console__(
) -> RenderResult:
code = str(self.text).rstrip()
syntax = Panel(
Syntax(code, self.lexer_name, theme=self.theme), style="dim", box=box.SQUARE
Syntax(code, self.lexer_name, theme=self.theme),
border_style="dim",
box=box.SQUARE,
)
yield syntax

Expand Down
8 changes: 3 additions & 5 deletions rich/palette.py
Expand Up @@ -28,9 +28,9 @@ def match(self, color: Tuple[int, int, int]) -> int:
red1, green1, blue1 = color
_sqrt = sqrt

def get_color_distance(color: Tuple[int, int, int]) -> float:
def get_color_distance(index: int) -> float:
"""Get the distance to a color."""
red2, green2, blue2 = color
red2, green2, blue2 = self._colors[index]
red_mean = int((red1 + red2) / 2)
red = red1 - red2
green = green1 - green2
Expand All @@ -41,7 +41,5 @@ def get_color_distance(color: Tuple[int, int, int]) -> float:
+ (((767 - red_mean) * blue * blue) >> 8)
)

min_index, _min_color = min(
enumerate(self._colors), key=lambda _color: get_color_distance(_color[1]),
)
min_index = min(range(len(self._colors)), key=get_color_distance)
return min_index
13 changes: 8 additions & 5 deletions rich/progress.py
Expand Up @@ -55,7 +55,10 @@


def iter_track(
values: Iterable[ProgressType], total: int, update_period: float = 0.05
values: Iterable[ProgressType],
total: int,
update_period: float = 0.05,
get_time: Callable[[], float] = None,
) -> Iterable[Iterable[ProgressType]]:
"""Break a sequence in to chunks based on time.
Expand All @@ -71,7 +74,7 @@ def iter_track(
yield [value]
return

get_time = perf_counter
get_time = get_time or perf_counter
period_size = 1.0

def gen_values(
Expand All @@ -87,7 +90,7 @@ def gen_values(
value_count = 0

while value_count < total:
_count = int(period_size)
_count = min(int(period_size), total - value_count)
start_time = get_time()
yield gen_values(iter_values, _count)
time_taken = get_time() - start_time
Expand Down Expand Up @@ -649,7 +652,7 @@ def stop(self) -> None:
self._refresh_thread = None
if self.transient:
self.console.control(self._live_render.restore_cursor())
if self.ipy_widget is not None and self.transient:
if self.ipy_widget is not None and self.transient: # pragma: no cover
self.ipy_widget.clear_output()
self.ipy_widget.close()

Expand Down Expand Up @@ -707,7 +710,7 @@ def track(
advance_total += 1
advance(task_id, advance_total)
if not self.auto_refresh:
progress.refresh()
self.refresh()

def start_task(self, task_id: TaskID) -> None:
"""Start a task.
Expand Down
2 changes: 2 additions & 0 deletions rich/syntax.py
Expand Up @@ -229,6 +229,8 @@ def __rich_console__(
if self.dedent:
code = textwrap.dedent(code)
text = self._highlight(self.lexer_name)
if text.plain.endswith("\n"):
text.plain = text.plain[:-1]
if not self.line_numbers:
if self.code_width is None:
yield text
Expand Down

0 comments on commit 579a29c

Please sign in to comment.