summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBatuhan Taskaya <isidentical@gmail.com>2022-05-10 10:37:47 +0300
committerBatuhan Taskaya <isidentical@gmail.com>2022-05-10 10:51:31 +0300
commitad5f01635b7b06068b55dec72ff3dc35d38a9356 (patch)
treedfbaa17a08672ce6f37fe78d47960589796a004d
parent8173cb03378ae05239eedfca86baa2dbb492c26e (diff)
Refactor the color systemisidentical/refactors/color-system
-rw-r--r--httpie/context.py12
-rw-r--r--httpie/output/ui/palette/__init__.py3
-rw-r--r--httpie/output/ui/palette/custom_styles.py18
-rw-r--r--httpie/output/ui/palette/pie.py (renamed from httpie/output/ui/palette.py)77
-rw-r--r--httpie/output/ui/palette/rich.py111
-rw-r--r--httpie/output/ui/palette/utils.py23
-rw-r--r--httpie/output/ui/rich_help.py16
-rw-r--r--httpie/output/ui/rich_palette.py73
-rw-r--r--httpie/output/ui/rich_utils.py4
9 files changed, 175 insertions, 162 deletions
diff --git a/httpie/context.py b/httpie/context.py
index 086cfa4f..febf8c2e 100644
--- a/httpie/context.py
+++ b/httpie/context.py
@@ -18,7 +18,7 @@ from .config import DEFAULT_CONFIG_DIR, Config, ConfigFileError
from .encoding import UTF8
from .utils import repr_dict
-from .output.ui.palette import GenericColor
+from .output.ui.palette import RichColor
if TYPE_CHECKING:
from rich.console import Console
@@ -31,9 +31,9 @@ class LogLevel(str, Enum):
LOG_LEVEL_COLORS = {
- LogLevel.INFO: GenericColor.PINK,
- LogLevel.WARNING: GenericColor.ORANGE,
- LogLevel.ERROR: GenericColor.RED,
+ LogLevel.INFO: RichColor.PINK,
+ LogLevel.WARNING: RichColor.ORANGE,
+ LogLevel.ERROR: RichColor.RED,
}
LOG_LEVEL_DISPLAY_THRESHOLDS = {
@@ -191,10 +191,10 @@ class Environment:
force_terminal: bool
) -> 'Console':
from rich.console import Console
- from httpie.output.ui.rich_palette import _make_rich_color_theme
+ from httpie.output.ui.palette import make_rich_theme_from_style
style = getattr(self.args, 'style', None)
- theme = _make_rich_color_theme(style)
+ theme = make_rich_theme_from_style(style)
# Rich infers the rest of the knowledge (e.g encoding)
# dynamically by looking at the file/stderr.
return Console(
diff --git a/httpie/output/ui/palette/__init__.py b/httpie/output/ui/palette/__init__.py
new file mode 100644
index 00000000..e82b21fd
--- /dev/null
+++ b/httpie/output/ui/palette/__init__.py
@@ -0,0 +1,3 @@
+from httpie.output.ui.palette.pie import AUTO_STYLE, SHADE_TO_PIE_STYLE, PieStyle, PieColor, ColorString, get_color # noqa
+from httpie.output.ui.palette.rich import RichColor, make_rich_theme_from_style
+from httpie.output.ui.palette.utils import ColorString
diff --git a/httpie/output/ui/palette/custom_styles.py b/httpie/output/ui/palette/custom_styles.py
new file mode 100644
index 00000000..bc51bd7b
--- /dev/null
+++ b/httpie/output/ui/palette/custom_styles.py
@@ -0,0 +1,18 @@
+from httpie.output.ui.palette.rich import RichColor
+from httpie.output.ui.palette.utils import ColorString
+
+RICH_BOLD = ColorString('bold')
+
+# Rich-specific color code declarations
+# <https://github.com/Textualize/rich/blob/fcd684dd3a482977cab620e71ccaebb94bf13ac9/rich/default_styles.py>
+RICH_CUSTOM_STYLES = {
+ 'progress.description': RICH_BOLD | RichColor.WHITE,
+ 'progress.data.speed': RICH_BOLD | RichColor.GREEN,
+ 'progress.percentage': RICH_BOLD | RichColor.AQUA,
+ 'progress.download': RICH_BOLD | RichColor.AQUA,
+ 'progress.remaining': RICH_BOLD | RichColor.ORANGE,
+ 'bar.complete': RICH_BOLD | RichColor.PURPLE,
+ 'bar.finished': RICH_BOLD | RichColor.GREEN,
+ 'bar.pulse': RICH_BOLD | RichColor.PURPLE,
+ 'option': RICH_BOLD | RichColor.PINK,
+}
diff --git a/httpie/output/ui/palette.py b/httpie/output/ui/palette/pie.py
index 5666b21f..bceab589 100644
--- a/httpie/output/ui/palette.py
+++ b/httpie/output/ui/palette/pie.py
@@ -1,18 +1,12 @@
-from dataclasses import dataclass, field
-from enum import Enum, auto
-from typing import Optional, List
-
+from enum import Enum
+from typing import Optional
+from httpie.output.ui.palette.utils import ColorString
PYGMENTS_BRIGHT_BLACK = 'ansibrightblack'
AUTO_STYLE = 'auto' # Follows terminal ANSI color styles
-class Styles(Enum):
- PIE = auto()
- ANSI = auto()
-
-
class PieStyle(str, Enum):
UNIVERSAL = 'pie'
DARK = 'pie-dark'
@@ -24,34 +18,11 @@ PIE_STYLE_TO_SHADE = {
PieStyle.UNIVERSAL: '600',
PieStyle.LIGHT: '700',
}
+
SHADE_TO_PIE_STYLE = {
shade: style for style, shade in PIE_STYLE_TO_SHADE.items()
}
-
-class ColorString(str):
- def __or__(self, other: str) -> 'ColorString':
- """Combine a style with a property.
-
- E.g: PieColor.BLUE | BOLD | ITALIC
- """
- if isinstance(other, str):
- # In case of PieColor.BLUE | SOMETHING
- # we just create a new string.
- return ColorString(self + ' ' + other)
- elif isinstance(other, GenericColor):
- # If we see a GenericColor, then we'll wrap it
- # in with the desired property in a different class.
- return _StyledGenericColor(other, styles=self.split())
- elif isinstance(other, _StyledGenericColor):
- # And if it is already wrapped, we'll just extend the
- # list of properties.
- other.styles.extend(self.split())
- return other
- else:
- return NotImplemented
-
-
class PieColor(ColorString, Enum):
"""Styles that are available only in Pie themes."""
@@ -71,42 +42,6 @@ class PieColor(ColorString, Enum):
YELLOW = 'yellow'
-class GenericColor(Enum):
- """Generic colors that are safe to use everywhere."""
-
- # <https://rich.readthedocs.io/en/stable/appendix/colors.html>
-
- WHITE = {Styles.PIE: PieColor.WHITE, Styles.ANSI: 'white'}
- BLACK = {Styles.PIE: PieColor.BLACK, Styles.ANSI: 'black'}
- GREEN = {Styles.PIE: PieColor.GREEN, Styles.ANSI: 'green'}
- ORANGE = {Styles.PIE: PieColor.ORANGE, Styles.ANSI: 'yellow'}
- YELLOW = {Styles.PIE: PieColor.YELLOW, Styles.ANSI: 'bright_yellow'}
- BLUE = {Styles.PIE: PieColor.BLUE, Styles.ANSI: 'blue'}
- PINK = {Styles.PIE: PieColor.PINK, Styles.ANSI: 'bright_magenta'}
- PURPLE = {Styles.PIE: PieColor.PURPLE, Styles.ANSI: 'magenta'}
- RED = {Styles.PIE: PieColor.RED, Styles.ANSI: 'red'}
- AQUA = {Styles.PIE: PieColor.AQUA, Styles.ANSI: 'cyan'}
- GREY = {Styles.PIE: PieColor.GREY, Styles.ANSI: 'bright_black'}
-
- def apply_style(
- self, style: Styles, *, style_name: Optional[str] = None
- ) -> str:
- """Apply the given style to a particular value."""
- exposed_color = self.value[style]
- if style is Styles.PIE:
- assert style_name is not None
- shade = PIE_STYLE_TO_SHADE[PieStyle(style_name)]
- return get_color(exposed_color, shade)
- else:
- return exposed_color
-
-
-@dataclass
-class _StyledGenericColor:
- color: 'GenericColor'
- styles: List[str] = field(default_factory=list)
-
-
# noinspection PyDictCreation
COLOR_PALETTE = {
# Copy the brand palette
@@ -252,10 +187,6 @@ COLOR_PALETTE.update(
)
-def boldify(color: PieColor) -> str:
- return f'bold {color}'
-
-
# noinspection PyDefaultArgument
def get_color(
color: PieColor, shade: str, *, palette=COLOR_PALETTE
diff --git a/httpie/output/ui/palette/rich.py b/httpie/output/ui/palette/rich.py
new file mode 100644
index 00000000..ecc1799f
--- /dev/null
+++ b/httpie/output/ui/palette/rich.py
@@ -0,0 +1,111 @@
+from collections import ChainMap
+from typing import TYPE_CHECKING, Any, Optional, List
+from enum import Enum, auto
+from dataclasses import dataclass, field
+
+if TYPE_CHECKING:
+ from rich.theme import Theme
+
+from httpie.output.ui.palette.pie import (
+ PIE_STYLE_TO_SHADE,
+ PieStyle,
+ PieColor,
+ get_color,
+) # noqa
+
+
+class RichTheme(Enum):
+ """Represents the color theme to use within rich."""
+ PIE = auto()
+ ANSI = auto()
+
+ @classmethod
+ def from_style_name(cls, style_name: str) -> 'RichTheme':
+ try:
+ PieStyle(style_name)
+ except ValueError:
+ return RichTheme.ANSI
+ else:
+ return RichTheme.PIE
+
+
+class RichColor(Enum):
+ """Generic colors that are safe to use everywhere within rich."""
+
+ # <https://rich.readthedocs.io/en/stable/appendix/colors.html>
+
+ WHITE = {RichTheme.PIE: PieColor.WHITE, RichTheme.ANSI: 'white'}
+ BLACK = {RichTheme.PIE: PieColor.BLACK, RichTheme.ANSI: 'black'}
+ GREEN = {RichTheme.PIE: PieColor.GREEN, RichTheme.ANSI: 'green'}
+ ORANGE = {RichTheme.PIE: PieColor.ORANGE, RichTheme.ANSI: 'yellow'}
+ YELLOW = {RichTheme.PIE: PieColor.YELLOW, RichTheme.ANSI: 'bright_yellow'}
+ BLUE = {RichTheme.PIE: PieColor.BLUE, RichTheme.ANSI: 'blue'}
+ PINK = {RichTheme.PIE: PieColor.PINK, RichTheme.ANSI: 'bright_magenta'}
+ PURPLE = {RichTheme.PIE: PieColor.PURPLE, RichTheme.ANSI: 'magenta'}
+ RED = {RichTheme.PIE: PieColor.RED, RichTheme.ANSI: 'red'}
+ AQUA = {RichTheme.PIE: PieColor.AQUA, RichTheme.ANSI: 'cyan'}
+ GREY = {RichTheme.PIE: PieColor.GREY, RichTheme.ANSI: 'bright_black'}
+
+ def apply_theme(
+ self, style: RichTheme, *, style_name: Optional[str] = None
+ ) -> str:
+ """Apply the given style to a particular value."""
+ exposed_color = self.value[style]
+ if style is RichTheme.PIE:
+ assert style_name is not None
+ shade = PIE_STYLE_TO_SHADE[PieStyle(style_name)]
+ return get_color(exposed_color, shade)
+ else:
+ return exposed_color
+
+
+@dataclass
+class _StyledRichColor:
+ color: RichColor
+ styles: List[str] = field(default_factory=list)
+
+
+class _RichColorCaster(dict):
+ """
+ Translate RichColor to a regular string on the attribute access
+ phase.
+ """
+
+ def _translate(self, key: Any) -> Any:
+ if isinstance(key, RichColor):
+ return key.name.lower()
+ else:
+ return key
+
+ def __getitem__(self, key: Any) -> Any:
+ return super().__getitem__(self._translate(key))
+
+ def get(self, key: Any) -> Any:
+ return super().get(self._translate(key))
+
+
+def make_rich_theme_from_style(style_name: Optional[str] = None) -> 'Theme':
+ from rich.style import Style
+ from rich.theme import Theme
+ from httpie.output.ui.palette.custom_styles import RICH_CUSTOM_STYLES
+
+ rich_theme = RichTheme.from_style_name(style_name)
+
+ theme = Theme()
+ for color, color_set in ChainMap(
+ RichColor.__members__, RICH_CUSTOM_STYLES
+ ).items():
+ if isinstance(color_set, _StyledRichColor):
+ properties = dict.fromkeys(color_set.styles, True)
+ color_set = color_set.color
+ else:
+ properties = {}
+
+ theme.styles[color.lower()] = Style(
+ color=color_set.apply_theme(rich_theme, style_name=style_name),
+ **properties,
+ )
+
+ # E.g translate RichColor.BLUE into blue on key access
+ theme.styles = _RichColorCaster(theme.styles)
+ return theme
diff --git a/httpie/output/ui/palette/utils.py b/httpie/output/ui/palette/utils.py
new file mode 100644
index 00000000..47144cbc
--- /dev/null
+++ b/httpie/output/ui/palette/utils.py
@@ -0,0 +1,23 @@
+class ColorString(str):
+ def __or__(self, other: str) -> 'ColorString':
+ """Combine a style with a property.
+
+ E.g: PieColor.BLUE | BOLD | ITALIC
+ """
+ from httpie.output.ui.palette.rich import RichColor, _StyledRichColor
+
+ if isinstance(other, str):
+ # In case of PieColor.BLUE | SOMETHING
+ # we just create a new string.
+ return ColorString(self + ' ' + other)
+ elif isinstance(other, RichColor):
+ # If we see a GenericColor, then we'll wrap it
+ # in with the desired property in a different class.
+ return _StyledRichColor(other, styles=self.split())
+ elif isinstance(other, _StyledRichColor):
+ # And if it is already wrapped, we'll just extend the
+ # list of properties.
+ other.styles.extend(self.split())
+ return other
+ else:
+ return NotImplemented
diff --git a/httpie/output/ui/rich_help.py b/httpie/output/ui/rich_help.py
index 2b19f3e3..354d3b2a 100644
--- a/httpie/output/ui/rich_help.py
+++ b/httpie/output/ui/rich_help.py
@@ -10,17 +10,17 @@ from rich.text import Text
from httpie.cli.constants import SEPARATOR_GROUP_ALL_ITEMS
from httpie.cli.options import Argument, ParserSpec, Qualifiers
-from httpie.output.ui.palette import GenericColor
+from httpie.output.ui.palette import RichColor
SEPARATORS = '|'.join(map(re.escape, SEPARATOR_GROUP_ALL_ITEMS))
-STYLE_METAVAR = GenericColor.YELLOW
-STYLE_SWITCH = GenericColor.GREEN
-STYLE_PROGRAM_NAME = GenericColor.GREEN # .boldify()
-STYLE_USAGE_OPTIONAL = GenericColor.GREY
-STYLE_USAGE_REGULAR = GenericColor.WHITE
-STYLE_USAGE_ERROR = GenericColor.RED
-STYLE_USAGE_MISSING = GenericColor.YELLOW
+STYLE_METAVAR = RichColor.YELLOW
+STYLE_SWITCH = RichColor.GREEN
+STYLE_PROGRAM_NAME = RichColor.GREEN # .boldify()
+STYLE_USAGE_OPTIONAL = RichColor.GREY
+STYLE_USAGE_REGULAR = RichColor.WHITE
+STYLE_USAGE_ERROR = RichColor.RED
+STYLE_USAGE_MISSING = RichColor.YELLOW
STYLE_BOLD = 'bold'
MAX_CHOICE_CHARS = 80
diff --git a/httpie/output/ui/rich_palette.py b/httpie/output/ui/rich_palette.py
deleted file mode 100644
index 103d4637..00000000
--- a/httpie/output/ui/rich_palette.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from collections import ChainMap
-from typing import TYPE_CHECKING, Any, Optional
-
-if TYPE_CHECKING:
- from rich.theme import Theme
-
-from httpie.output.ui.palette import GenericColor, PieStyle, Styles, ColorString, _StyledGenericColor # noqa
-
-RICH_BOLD = ColorString('bold')
-
-# Rich-specific color code declarations
-# <https://github.com/Textualize/rich/blob/fcd684dd3a482977cab620e71ccaebb94bf13ac9/rich/default_styles.py>
-CUSTOM_STYLES = {
- 'progress.description': RICH_BOLD | GenericColor.WHITE,
- 'progress.data.speed': RICH_BOLD | GenericColor.GREEN,
- 'progress.percentage': RICH_BOLD | GenericColor.AQUA,
- 'progress.download': RICH_BOLD | GenericColor.AQUA,
- 'progress.remaining': RICH_BOLD | GenericColor.ORANGE,
- 'bar.complete': RICH_BOLD | GenericColor.PURPLE,
- 'bar.finished': RICH_BOLD | GenericColor.GREEN,
- 'bar.pulse': RICH_BOLD | GenericColor.PURPLE,
- 'option': RICH_BOLD | GenericColor.PINK,
-}
-
-
-class _GenericColorCaster(dict):
- """
- Translate GenericColor to a regular string on the attribute access
- phase.
- """
-
- def _translate(self, key: Any) -> Any:
- if isinstance(key, GenericColor):
- return key.name.lower()
- else:
- return key
-
- def __getitem__(self, key: Any) -> Any:
- return super().__getitem__(self._translate(key))
-
- def get(self, key: Any) -> Any:
- return super().get(self._translate(key))
-
-
-def _make_rich_color_theme(style_name: Optional[str] = None) -> 'Theme':
- from rich.style import Style
- from rich.theme import Theme
-
- try:
- PieStyle(style_name)
- except ValueError:
- style = Styles.ANSI
- else:
- style = Styles.PIE
-
- theme = Theme()
- for color, color_set in ChainMap(
- GenericColor.__members__, CUSTOM_STYLES
- ).items():
- if isinstance(color_set, _StyledGenericColor):
- properties = dict.fromkeys(color_set.styles, True)
- color_set = color_set.color
- else:
- properties = {}
-
- theme.styles[color.lower()] = Style(
- color=color_set.apply_style(style, style_name=style_name),
- **properties,
- )
-
- # E.g translate GenericColor.BLUE into blue on key access
- theme.styles = _GenericColorCaster(theme.styles)
- return theme
diff --git a/httpie/output/ui/rich_utils.py b/httpie/output/ui/rich_utils.py
index 4843d149..77c34097 100644
--- a/httpie/output/ui/rich_utils.py
+++ b/httpie/output/ui/rich_utils.py
@@ -6,7 +6,7 @@ from contextlib import contextmanager
from rich.console import Console, RenderableType
from rich.highlighter import Highlighter
-from httpie.output.ui.rich_palette import _make_rich_color_theme
+from httpie.output.ui.palette import make_rich_theme_from_style
def render_as_string(renderable: RenderableType) -> str:
@@ -14,7 +14,7 @@ def render_as_string(renderable: RenderableType) -> str:
return a *style-less* version of it as a string."""
with open(os.devnull, 'w') as null_stream:
- fake_console = Console(file=null_stream, record=True, theme=_make_rich_color_theme())
+ fake_console = Console(file=null_stream, record=True, theme=make_rich_theme_from_style())
fake_console.print(renderable)
return fake_console.export_text()