Skip to content

Text

Bases: Text

A rich text class that supports gradient colors and styles.

Source code in src/rich_gradient/text.py
class Text(RichText):
    """A rich text class that supports gradient colors and styles."""

    def __init__(
        self,
        text: TextType = "",
        colors: Optional[Sequence[ColorInputType]] = None,
        *,
        rainbow: bool = False,
        hues: int = 5,
        style: StyleType = "",
        justify: JustifyMethod = "default",
        overflow: OverflowMethod = "fold",
        no_wrap: bool = False,
        end: str = "\n",
        tab_size: int = 4,
        markup: bool = True,
    ):
        """Initialize the Text with gradient colors and styles.
        Args:
            text (TextType): The text content.
            colors (Optional[List[ColorType]]): A list of colors as Color instances or strings.
            rainbow (bool): If True, generate a rainbow spectrum.
            hues (int): The number of hues to generate if colors are not provided.
            style (StyleType): The style of the text.
            justify (JustifyMethod): Justification method for the text.
            overflow (OverflowMethod): Overflow method for the text.
            no_wrap (bool): If True, disable wrapping of the text.
            markup (bool): If True, parse Rich markup tags in the input text.
        """
        # Extract out complex expressions for clarity
        parsed_text = RichText.from_markup(
            text=str(text), style=style, justify=justify, overflow=overflow
        )
        plain = parsed_text.plain
        parsed_justify = parsed_text.justify
        parsed_overflow = parsed_text.overflow
        parsed_spans = parsed_text._spans

        super().__init__(
            plain,
            justify=parsed_justify,
            overflow=parsed_overflow,
            no_wrap=no_wrap,
            end=end,
            tab_size=tab_size,
            spans=parsed_spans,
        )
        self.colors = self.parse_colors(colors, hues, rainbow)
        # Apply the gradient coloring
        self.apply_gradient()

    @property
    def colors(self) -> Sequence[Color]:
        """Return the list of colors in the gradient."""
        return self._colors

    @colors.setter
    def colors(self, value: Optional[Sequence[Color]]) -> None:
        """Set the list of colors in the gradient."""
        self._colors = value or []

    @staticmethod
    def parse_colors(
        colors: Optional[Sequence[ColorInputType]] = None,
        hues: int = 5,
        rainbow: bool = False,
    ) -> List[Color]:
        """Parse and return a list of colors for the gradient.
        Supports 3-digit hex colors (e.g., '#f00', '#F90'), 6-digit hex, CSS names, and Color objects.
        Args:
            colors (Optional[Sequence[ColorType | Color]]): A list of colors as Color instances or strings.
            hues (int): The number of hues to generate if colors are not provided.
            rainbow (bool): If True, generate a rainbow spectrum.
        Returns:
            List[Color]: A list of Color objects.
        """
        if rainbow:
            return Spectrum(hues=18).colors
        if colors is None or len(colors) == 0:
            return Spectrum(hues).colors
        # Support 3-digit hex colors and all string representations via Color.parse
        return [c if isinstance(c, Color) else Color.parse(c) for c in colors]

    def interpolate_colors(self) -> List[Color]:
        """Interpolate colors in the gradient."""
        if not self.colors:
            raise ValueError("No colors to interpolate")
        # Prepare the text and handle edge cases
        text = self.plain
        length = len(text)
        if length == 0:
            return []
        num_colors = len(self.colors)
        if num_colors == 1:
            return [self.colors[0]] * length

        # Compute number of segments between colors
        segments = num_colors - 1
        result: List[Color] = []

        # For each character, determine its position and blend accordingly
        for i in range(length):
            # Normalized position along the entire text
            pos = i / (length - 1) if length > 1 else 0.0
            # Determine which two colors to blend between
            float_index = pos * segments
            index = int(float_index)
            # Clamp to valid segment range
            if index >= segments:
                index = segments - 1
                t = 1.0
            else:
                t = float_index - index

            start = self.colors[index]
            end = self.colors[index + 1]
            triplet1 = start.get_truecolor()
            triplet2 = end.get_truecolor()

            # Interpolate each RGB component
            r = int(triplet1.red + (triplet2.red - triplet1.red) * t)
            g = int(triplet1.green + (triplet2.green - triplet1.green) * t)
            b = int(triplet1.blue + (triplet2.blue - triplet1.blue) * t)

            result.append(Color.from_rgb(r, g, b))

        return result

    def apply_gradient(self) -> None:
        """Apply interpolated colors as spans to each character in the text."""
        # Generate a color for each character
        colors = self.interpolate_colors()
        # Apply a style span for each character with its corresponding color
        for index, color in enumerate(colors):
            # Build a style with the interpolated color
            span_style = Style(color=color)
            # Stylize the single character range
            self.stylize(span_style, index, index + 1)

colors property writable

Return the list of colors in the gradient.

__init__(text='', colors=None, *, rainbow=False, hues=5, style='', justify='default', overflow='fold', no_wrap=False, end='\n', tab_size=4, markup=True)

Initialize the Text with gradient colors and styles. Args: text (TextType): The text content. colors (Optional[List[ColorType]]): A list of colors as Color instances or strings. rainbow (bool): If True, generate a rainbow spectrum. hues (int): The number of hues to generate if colors are not provided. style (StyleType): The style of the text. justify (JustifyMethod): Justification method for the text. overflow (OverflowMethod): Overflow method for the text. no_wrap (bool): If True, disable wrapping of the text. markup (bool): If True, parse Rich markup tags in the input text.

Source code in src/rich_gradient/text.py
def __init__(
    self,
    text: TextType = "",
    colors: Optional[Sequence[ColorInputType]] = None,
    *,
    rainbow: bool = False,
    hues: int = 5,
    style: StyleType = "",
    justify: JustifyMethod = "default",
    overflow: OverflowMethod = "fold",
    no_wrap: bool = False,
    end: str = "\n",
    tab_size: int = 4,
    markup: bool = True,
):
    """Initialize the Text with gradient colors and styles.
    Args:
        text (TextType): The text content.
        colors (Optional[List[ColorType]]): A list of colors as Color instances or strings.
        rainbow (bool): If True, generate a rainbow spectrum.
        hues (int): The number of hues to generate if colors are not provided.
        style (StyleType): The style of the text.
        justify (JustifyMethod): Justification method for the text.
        overflow (OverflowMethod): Overflow method for the text.
        no_wrap (bool): If True, disable wrapping of the text.
        markup (bool): If True, parse Rich markup tags in the input text.
    """
    # Extract out complex expressions for clarity
    parsed_text = RichText.from_markup(
        text=str(text), style=style, justify=justify, overflow=overflow
    )
    plain = parsed_text.plain
    parsed_justify = parsed_text.justify
    parsed_overflow = parsed_text.overflow
    parsed_spans = parsed_text._spans

    super().__init__(
        plain,
        justify=parsed_justify,
        overflow=parsed_overflow,
        no_wrap=no_wrap,
        end=end,
        tab_size=tab_size,
        spans=parsed_spans,
    )
    self.colors = self.parse_colors(colors, hues, rainbow)
    # Apply the gradient coloring
    self.apply_gradient()

apply_gradient()

Apply interpolated colors as spans to each character in the text.

Source code in src/rich_gradient/text.py
def apply_gradient(self) -> None:
    """Apply interpolated colors as spans to each character in the text."""
    # Generate a color for each character
    colors = self.interpolate_colors()
    # Apply a style span for each character with its corresponding color
    for index, color in enumerate(colors):
        # Build a style with the interpolated color
        span_style = Style(color=color)
        # Stylize the single character range
        self.stylize(span_style, index, index + 1)

interpolate_colors()

Interpolate colors in the gradient.

Source code in src/rich_gradient/text.py
def interpolate_colors(self) -> List[Color]:
    """Interpolate colors in the gradient."""
    if not self.colors:
        raise ValueError("No colors to interpolate")
    # Prepare the text and handle edge cases
    text = self.plain
    length = len(text)
    if length == 0:
        return []
    num_colors = len(self.colors)
    if num_colors == 1:
        return [self.colors[0]] * length

    # Compute number of segments between colors
    segments = num_colors - 1
    result: List[Color] = []

    # For each character, determine its position and blend accordingly
    for i in range(length):
        # Normalized position along the entire text
        pos = i / (length - 1) if length > 1 else 0.0
        # Determine which two colors to blend between
        float_index = pos * segments
        index = int(float_index)
        # Clamp to valid segment range
        if index >= segments:
            index = segments - 1
            t = 1.0
        else:
            t = float_index - index

        start = self.colors[index]
        end = self.colors[index + 1]
        triplet1 = start.get_truecolor()
        triplet2 = end.get_truecolor()

        # Interpolate each RGB component
        r = int(triplet1.red + (triplet2.red - triplet1.red) * t)
        g = int(triplet1.green + (triplet2.green - triplet1.green) * t)
        b = int(triplet1.blue + (triplet2.blue - triplet1.blue) * t)

        result.append(Color.from_rgb(r, g, b))

    return result

parse_colors(colors=None, hues=5, rainbow=False) staticmethod

Parse and return a list of colors for the gradient. Supports 3-digit hex colors (e.g., '#f00', '#F90'), 6-digit hex, CSS names, and Color objects. Args: colors (Optional[Sequence[ColorType | Color]]): A list of colors as Color instances or strings. hues (int): The number of hues to generate if colors are not provided. rainbow (bool): If True, generate a rainbow spectrum. Returns: List[Color]: A list of Color objects.

Source code in src/rich_gradient/text.py
@staticmethod
def parse_colors(
    colors: Optional[Sequence[ColorInputType]] = None,
    hues: int = 5,
    rainbow: bool = False,
) -> List[Color]:
    """Parse and return a list of colors for the gradient.
    Supports 3-digit hex colors (e.g., '#f00', '#F90'), 6-digit hex, CSS names, and Color objects.
    Args:
        colors (Optional[Sequence[ColorType | Color]]): A list of colors as Color instances or strings.
        hues (int): The number of hues to generate if colors are not provided.
        rainbow (bool): If True, generate a rainbow spectrum.
    Returns:
        List[Color]: A list of Color objects.
    """
    if rainbow:
        return Spectrum(hues=18).colors
    if colors is None or len(colors) == 0:
        return Spectrum(hues).colors
    # Support 3-digit hex colors and all string representations via Color.parse
    return [c if isinstance(c, Color) else Color.parse(c) for c in colors]