# -*- encoding: utf-8 -*-
# Copyright (c) 2020 Stephen Bunn <stephen@bunn.io>
# ISC License <https://choosealicense.com/licenses/isc>
"""Contains the base chalk class that is used to group some style and colors."""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Optional, Set, Union, overload
from .color import Color_T
from .constants import is_disabled
from .interface import get_interface
from .style import Style
[docs]@dataclass
class Chalk:
"""Describes the style and color to use for styling some printable text.
Chalk can be composed using ``&`` and can be applied to strings with ``|``.
You can create your own instance of chalk by setting your desired
:class:`~style.Style` and :class:`~color.Color` when creating a new instance.
Examples:
Creating custom instances of chalk looks like the following:
>>> my_chalk = Chalk(
... style={Style.BOLD, Style.UNDERLINE},
... foreground=Color.RED,
... )
Composing two chalk instances can be done through either using ``&`` or ``+``:
>>> bold_chalk = Chalk(style={Style.BOLD})
>>> error_chalk = bold_chalk & Chalk(foreground=Color.RED)
Using chalk instances to style strings can be done using either ``|`` or ``+``:
>>> error_chalk | "Hello, World!"
Hello, World!
.. important::
When composing two chalk instances together, the chalk *being* applied to the
base chalk instance will override the foreground and background colors.
This means that if you apply a new chalk with a different foreground color it
will override the starting foreground color:
>>> red = Chalk(foreground=Color.RED)
>>> blue = Chalk(foreground=Color.BLUE)
>>> assert blue == (red & blue)
"""
style: Set[Style] = field(default_factory=set)
foreground: Optional[Color_T] = field(default=None)
background: Optional[Color_T] = field(default=None)
[docs] def __and__(self, other: Chalk) -> Chalk:
"""Create a new chalk instance from the composition of two chalk.
Args:
other (:class:`~Chalk`):
Another chalk to combine with the current chalk.
Returns:
:class:`~Chalk`:
The newly created chalk instance.
"""
return Chalk(
style=self.style.union(other.style),
foreground=other.foreground or self.foreground,
background=other.background or self.background,
)
[docs] def __or__(self, value: Any) -> str:
"""Style some given string with the current chalk instance.
.. tip::
If a non-string value is provided, we will attempt to get the most
appropriate string from the value by simply calling ``str(value)``.
So if you are passing in an object, make sure to use an appropriate
``__str__`` or ``__repr__``.
Args:
value (~typing.Any):
The value to apply the current chalk styles to.
Returns:
str:
The newly styled string.
"""
if is_disabled():
return str(value)
interface = get_interface()
return interface.apply(
value=str(value),
style=self.style,
background=self.background,
foreground=self.foreground,
)
@overload
def __add__(self, other: Chalk) -> Chalk: # pragma: no cover
"""Handle applying chalk to other chalk instances.
Args:
other (:class:`~Chalk`):
The chalk instance to apply to the current instance.
Returns:
:class:`~Chalk`:
They newly created chalk instance.
"""
...
@overload
def __add__(self, other: str) -> str: # pragma: no cover
"""Handle applying chalk to strings.
Args:
other (str):
The string to style with the current chalk instance.
Returns:
str:
They newly styled string.
"""
...
[docs] def __add__(self, other: Union[Chalk, str]) -> Union[Chalk, str]:
"""Handle applying chalk instances to things.
Args:
other (Union[Chalk, str]):
Either another chalk instance or a string.
Returns:
Union[Chalk, str]:
The combined chalk instances or a styled string.
"""
if isinstance(other, Chalk):
return self & other
return self | other
[docs] def __call__(self, value: str) -> str:
"""Handle applying chalk instances to strings.
Args:
value (str):
The string to apply the current styles to.
Returns:
str:
The newly styled string.
"""
return self | value
@property
def reverse(self) -> Chalk:
"""Color reverse of the current chalk instance.
Returns:
:class:`~Chalk`:
The revsered chalk instance
"""
return self & Chalk(style={Style.REVERSED})