Skip to content

Commit

Permalink
windows color support
Browse files Browse the repository at this point in the history
  • Loading branch information
willmcgugan committed Feb 2, 2020
1 parent 37c511f commit df88f78
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

## [0.3.3] - Unreleased

### Fixed

- Fixed Windows color support

## [0.3.2] - 2020-01-26

### Added
Expand Down
25 changes: 24 additions & 1 deletion rich/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from enum import IntEnum
from functools import lru_cache
from math import sqrt
import platform
from typing import Iterable, List, NamedTuple, Optional, Sequence, Tuple, TYPE_CHECKING

from ._palettes import STANDARD_PALETTE, EIGHT_BIT_PALETTE
Expand All @@ -13,12 +14,16 @@
from .theme import Theme


WINDOWS = platform.system() == "Windows"


class ColorSystem(IntEnum):
"""One of the 3 color system supported by terminals."""

STANDARD = 1
EIGHT_BIT = 2
TRUECOLOR = 3
WINDOWS = 4


class ColorType(IntEnum):
Expand All @@ -28,6 +33,7 @@ class ColorType(IntEnum):
STANDARD = 1
EIGHT_BIT = 2
TRUECOLOR = 3
WINDOWS = 4


ANSI_COLOR_NAMES = {
Expand Down Expand Up @@ -291,6 +297,8 @@ def get_truecolor(self, theme: "Theme", foreground=True) -> ColorTriplet:
elif self.type == ColorType.STANDARD:
assert self.number is not None
return theme.ansi_colors[self.number]
elif self.type == ColorType.WINDOWS:
return STANDARD_PALETTE[self.number]
else: # self.type == ColorType.DEFAULT:
assert self.number is None
return theme.foreground_color if foreground else theme.background_color
Expand Down Expand Up @@ -371,7 +379,7 @@ def get_ansi_codes(self, foreground: bool = True) -> List[str]:
if _type == ColorType.DEFAULT:
return ["39" if foreground else "49"]

elif _type == ColorType.STANDARD:
elif _type in (ColorType.STANDARD, ColorType.WINDOWS):
number = self.number
assert number is not None
return [str(30 + number if foreground else 40 + number)]
Expand Down Expand Up @@ -423,6 +431,21 @@ def downgrade(self, system: ColorSystem) -> "Color":
color_number = STANDARD_PALETTE.match(triplet)
return Color(self.name, ColorType.STANDARD, number=color_number)

elif system == ColorSystem.WINDOWS:
if self.system == ColorSystem.TRUECOLOR:
assert self.triplet is not None
triplet = self.triplet
else: # self.system == ColorSystem.EIGHT_BIT
assert self.number is not None
if self.number < 8:
return Color(self.name, ColorType.WINDOWS, number=self.number)
elif self.number < 16:
return Color(self.name, ColorType.WINDOWS, number=self.number - 8)
triplet = ColorTriplet(*EIGHT_BIT_PALETTE[self.number])

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

return self


Expand Down
15 changes: 11 additions & 4 deletions rich/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from itertools import chain
import os
from operator import itemgetter
import platform
import re
import shutil
import sys
Expand Down Expand Up @@ -48,8 +49,9 @@
if TYPE_CHECKING: # pragma: no cover
from .text import Text

HighlighterType = Callable[[Union[str, "Text"]], "Text"]
WINDOWS = platform.system() == "Windows"

HighlighterType = Callable[[Union[str, "Text"]], "Text"]
JustifyValues = Optional[Literal["left", "center", "right", "full"]]


Expand Down Expand Up @@ -151,6 +153,7 @@ def __exit__(self, exc_type, exc_value, traceback) -> None:
"standard": ColorSystem.STANDARD,
"256": ColorSystem.EIGHT_BIT,
"truecolor": ColorSystem.TRUECOLOR,
"windows": ColorSystem.WINDOWS,
}


Expand Down Expand Up @@ -179,7 +182,7 @@ class Console:
def __init__(
self,
color_system: Optional[
Literal["auto", "standard", "256", "truecolor"]
Literal["auto", "standard", "256", "truecolor", "windows"]
] = "auto",
styles: Dict[str, Style] = None,
file: IO = None,
Expand Down Expand Up @@ -226,6 +229,8 @@ def _detect_color_system(self,) -> Optional[ColorSystem]:
"""Detect color system from env vars."""
if not self.is_terminal:
return None
if WINDOWS:
return ColorSystem.WINDOWS
if os.environ.get("COLORTERM", "").strip().lower() == "truecolor":
return ColorSystem.TRUECOLOR
# 256 can be considered standard nowadays
Expand Down Expand Up @@ -311,6 +316,8 @@ def size(self) -> ConsoleDimensions:
return ConsoleDimensions(self._width, self._height)

width, height = shutil.get_terminal_size()
if WINDOWS:
width -= 1
return ConsoleDimensions(
width if self._width is None else self._width,
height if self._height is None else self._height,
Expand Down Expand Up @@ -796,7 +803,7 @@ def save_text(self, path: str, clear: bool = True, styles: bool = False) -> None
"""
text = self.export_text(clear=clear, styles=styles)
with open(path, "wt") as write_file:
with open(path, "wt", encoding="utf-8") as write_file:
write_file.write(text)

def export_html(
Expand Down Expand Up @@ -899,7 +906,7 @@ def save_html(
code_format=code_format,
inline_styles=inline_styles,
)
with open(path, "wt") as write_file:
with open(path, "wt", encoding="utf-8") as write_file:
write_file.write(html)


Expand Down
46 changes: 39 additions & 7 deletions rich/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
inlines = self.inlines
new_line = False
for current, entering in nodes:
print(current, current.literal)
# print(current, current.literal)
node_type = current.t
if node_type in ("html_inline", "html_block", "text"):
context.on_text(current.literal)
Expand Down Expand Up @@ -433,12 +433,44 @@ def __console__(self, console: Console, options: ConsoleOptions) -> RenderResult
markup = """
An h1 header
============
| Syntax | Description |
| --- | ----------- |
| Header | Title |
| Paragraph | Text |
Paragraphs are separated by a blank line.
2nd paragraph. *Italic*, **bold**, and `monospace`. Itemized lists look like:
* this one
* that one
* the other one
Note that --- not considering the asterisk --- the actual text content starts at 4-columns in.
> Block quotes are
> written like so.
>
> They can span multiple paragraphs,
> if you like.
Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., "it's all in chapters 12--14"). Three dots ... will be converted to an ellipsis. Unicode is supported. ☺
An h2 header
------------
```python
@classmethod
def adjust_line_length(
cls, line: List[Segment], length: int, style: Style = None
) -> List[Segment]:
line_length = sum(len(text) for text, _style in line)
if line_length < length:
return line[:] + [Segment(" " * (length - line_length), style)]
elif line_length > length:
line_length = 0
new_line: List[Segment] = []
append = new_line.append
for segment in line:
segment_length = len(segment.text)
if line_length + segment_length < length:
append(segment)
line_length += segment_length
else:
text, style = segment
append(Segment(text[: length - line_length], style))
break
return new_line
return line
```
"""

import commonmark
Expand Down

0 comments on commit df88f78

Please sign in to comment.