Beispiel #1
0
 def __init__(self, default_fg, default_bg, **kwargs):
     super().__init__(**kwargs)
     # These are ordinary instance parameters, but are used as the default
     # source for components for "DEFAULT_FG" and "DEFAULT_BG" colors
     # for all non-terminal backends.
     self._default_fg = Color(default_fg)
     self._default_bg = Color(default_bg)
Beispiel #2
0
    def __init__(self, attributes=None, pop_attributes=None, moveto=None, rmoveto=None, color=None, foreground=None, background=None, effects=None, direction=None, transformer=None, new_line=None):
        self.attributes = attributes or {}
        if isinstance(pop_attributes, (set, Sequence)):
            pop_attributes = {name: None for name in pop_attributes}
        self.pop_attributes = pop_attributes
        self.moveto = moveto
        self.rmoveto = rmoveto
        for parameter in "color foreground background effects direction transformer new_line".split():
            if locals()[parameter] is None:
                continue
            value = locals()[parameter]
            if parameter == "color": parameter = "foreground"
            if parameter == "transformer": parameter = "pretransformer"
            if parameter in ("foreground", "background") and not isinstance(value, Color):
                value = Color(value)
            if parameter == "effects" and not (isinstance(value, Effects) or value is TRANSPARENT):
                sep = "," if "," in value else "|" if "|" in value else " "
                effects = [e.strip() for e in value.split(sep) if e]
                value = Effects.none
                for effect in effects:
                    value |= Effects.__members__[effect.lower()]
            if parameter == "direction" and isinstance(value, str):
                value = V2(value)

            self.attributes[parameter] = value
        self.affects_text_flow = bool(self.moveto or self.rmoveto or self.attributes.get("direction") or new_line)
Beispiel #3
0
    def __init__(self):
        self.active_unicode_effects = Effects.none
        self.__class__.last_pos = V2(0, 0)
        self.next_pos = V2(0, 0)

        self.current_foreground = None
        self.current_background = None
        self.current_effects = None
        self.next_foreground = Color((0, 0, 0))
        self.next_background = Color((255, 255, 255))
        self.next_effects = Effects.none

        self.tag_is_open = False
Beispiel #4
0
 def set_bg_color(self, color, file=None):
     """Writes ANSI sequence to set the background color
     color: RGB  3-sequence (0.0-1.0 or 0-255 range) or color constant
     """
     if color == DEFAULT_BG:
         self.SGR(49, file=file)
     else:
         self.SGR(48, 2, *Color(color), file=file)
Beispiel #5
0
def test_color_name_is_reset_on_any_change():
    c = Color("red")
    assert c.name == "red"
    c.green = 255
    assert not c.name
    c = Color("red")
    c[1] = 1.0
    assert not c.name
    c = Color("red")
    c.components = (0, 1, 0)
    assert not c.name
Beispiel #6
0
def test_can_set_color_component_by_name():
    c = Color("red")
    c.green = 255
    assert c.components == (255, 255, 0)
    c = Color("red")
    c.green = 1.0
    assert c.components == (255, 255, 0)
Beispiel #7
0
def test_setting_hsv_component_works():
    c1 = Color("red")
    c1.hue = 0.5

    assert c1.components == (0, 255, 255)
    c1 = Color("red")
    c1.saturation = 0.5

    assert c1.components == (255, 127, 127)
Beispiel #8
0
 def __setitem__(self, pos, value):
     """
     Values set for each pixel are 3-sequences with an RGB color value
     """
     pos = V2(pos)
     self.dirty_mark_pixel(pos)
     color = value
     if isinstance(value, Pixel):
         v, color = value.get_values(self.context,
                                     self.PixelCls.capabilities)
     elif isinstance(value, (int, tuple, Color)):
         color = Color(value)
     elif isinstance(value, str):
         color = self.context.color if value != EMPTY else self.context.background
     self._raw_setitem(pos, color)
Beispiel #9
0
    def __getitem__(self, pos):
        """Values for each pixel are: character, fg_color, bg_color, effects.
        """
        v = super().__getitem__(pos)
        if v:
            return v
        char = self.get_raw(pos)
        value = bool(char != EMPTY)

        # TODO: Legacy: when this class doubled as "BooleanShape".
        # (remove comment block when BooleanShape is implemented)
        # if self.color_map:
        # foreground_arg = (self.color_map.get(char, DEFAULT_FG),)
        # else:
        # foreground_arg = ()

        foreground_arg = self.color_map.get(char, CONTEXT_COLORS)
        if not isinstance(foreground_arg, Color):
            foreground_arg = Color(foreground_arg)
        return self.PixelCls(value, foreground_arg)
Beispiel #10
0
def test_subtracting_colors_dont_underflow():
    c = Color((200, 0, 0))
    c -= Color((255, 255, 0))
    assert c.components == (0, 0, 0)
Beispiel #11
0
def test_can_sub_colors():
    c = Color("red")
    c -= Color((255, 0, 0))
    assert c.components == (0, 0, 0)
Beispiel #12
0
def test_color_by_name_works():
    c = Color("red")
    assert "red" in repr(c)
    assert tuple(c.components) == (255, 0, 0)
Beispiel #13
0
def test_can_set_color_component_by_index():
    c = Color("red")
    c[1] = 255
    assert c.components == (255, 255, 0)
Beispiel #14
0
 def set_bg_color(self, color, file=None):
     """
     """
     self.next_background = Color(color)
Beispiel #15
0
def test_html_rendering_of_color():
    c = Color((255, 128, 0))
    assert c.html == "#FF8000"
Beispiel #16
0
def test_normalized_color_works():
    c = Color("red")
    assert tuple(c.components) == (255, 0, 0)
    assert c.normalized == (1.0, 0, 0)
Beispiel #17
0
    def default_bg(self, value):
        from terminedia.values import DEFAULT_BG

        if value is DEFAULT_BG:
            raise ValueError("The source for default_bg can't be set as DEFAULT_BG")
        self._default_bg = Color(value)
Beispiel #18
0
    def print(self, *texts, pos=None, context=None, color=None, foreground=None, background=None, effects=None,
              file=None, flush=False, sep=" ", end="\n"
              ):
        """Method to print a straightforward rich-text string to the terminal

        Params:
          *texts: List[str]: strings to print
          pos: Optional[Tuple[int, int]]: Terminal position to print to
          context: Optional[terminedia.Context instance]
          color: Union[terminedia.Color, str, Tuple[int, int, int], Tuple[float, float, float]] : foreground color to use
          foreground: aliased to color
          background: Union[terminedia.Color, str, Tuple[int, int, int], Tuple[float, float, float]] : background color to use
          effects: terminedia.Effects : effect or effect combination to apply to characters before printing
          file, flush, sep, end: The same as standard Python's `print`

        """
        from terminedia.text.style import MLTokenizer
        from terminedia import shape
        import os

        if not context:
            context = active_context.get()

        original_attributes = (context.color, context.background, context.effects)

        color = foreground or color
        color = Color(color) if color is not None else context.color
        background = Color(background) if background is not None else context.background

        if effects is not None:
            # if an empty string is given, we have to use Effects.none
            effects = Effects(effects) if effects else Effects.none
        else:
            effects = context.effects

        self.set_colors(color, background, effects, file=file)

        if self.active_unicode_effects:
            texts = [self.apply_unicode_effects(text) if text[0] != ESC else text for text in texts]

        if pos:
            self.__class__.last_pos = None
            self.moveto(pos, file=file)

        first_text = True
        for text in texts:
            if not first_text:
                self._print(sep, file=file, end="")
            if not isinstance(text, str):
                text = str(text)
            tokenized = MLTokenizer(text)
            tokenized.parse()
            if not tokenized.mark_sequence:
                self._print(text, file=file, flush=flush, sep=sep, end=end)
            else:
                try:
                    size = os.get_terminal_size()
                except OSError:
                    size = 80, 25
                sh = shape(size)
                sh.text[1][0,0] = text
                output = sh.render()
                self._print(output, file=file, flush=flush, sep=sep, end="")
            first_text = False
        self._print(end, file=file, flush=flush, end="")

        self.set_colors(*original_attributes, file=file)
Beispiel #19
0
def test_color_by_float_works():
    c = Color((1.0, 0, 0))
    assert tuple(c.components) == (255, 0, 0)
Beispiel #20
0
def test_colors_isclose():
    a = Color("black")
    assert a.isclose((0, 2, 2))
    assert not a.isclose((0, 2, 4))
    assert a.isclose((0, 2, 4), abs_tol=10)
Beispiel #21
0
def test_can_add_colors_to_sequences():
    c = Color("red")
    c += [0, 1.0, 0]
    assert c.components == (255, 255, 0)
Beispiel #22
0
def test_can_add_colors():
    c = Color("red")
    c += Color((0, 255, 0))
    assert c.components == (255, 255, 0)
Beispiel #23
0
def test_can_get_color_component_by_name():
    c = Color("red")
    assert c.red == 255 and c.green == 0 and c.blue == 0
Beispiel #24
0
 def set_fg_color(self, color, file=None):
     """
     """
     self.next_foreground = Color(color)
Beispiel #25
0
 def char(self, char, foreground):
     if not isinstance(foreground, Color):
         foreground = Color(foreground)
     if (foreground.value >= self.threshold) ^ self.invert:
         return char
     return values.EMPTY
Beispiel #26
0
def test_color_by_hex6_works():
    c = Color("#ff0000")
    assert tuple(c.components) == (255, 0, 0)
    c = Color("#FF0000")
    assert tuple(c.components) == (255, 0, 0)
Beispiel #27
0
def test_adding_colors_dont_overflow():
    c = Color((200, 0, 0))
    c += Color((200, 255, 0))
    assert c.components == (255, 255, 0)
Beispiel #28
0
    def _tokens_to_marks(self, raw_tokens):
        from terminedia.transformers import library as transformers_library
        from terminedia import Effects, Color, Directions, DEFAULT_BG, DEFAULT_FG, TRANSPARENT

        self.mark_sequence = {}
        # Separate stack to anottate the length of the affected string inside each Transformer
        transformer_stack = []
        last_offset = -1
        offset_repeat_counter = -1
        for offset, token in raw_tokens:
            if offset == last_offset:
                offset_repeat_counter += 1
            else:
                offset_repeat_counter = 0
            last_offset = offset
            attributes = None
            pop_attributes = None
            rmoveto = None
            moveto = None

            token = token.lower().strip() if not "transformer" in token else token.strip()
            if token.startswith("/"):
                starting_tag= False
                token = token[1:]
            else:
                starting_tag = True

            if ":" in token:
                action, value = [v.strip() for v in token.split(":")]
                action = action.lower()

            else:
                action = token.strip()
                value = None
                if action in {"left", "right", "up", "down"}:
                    value = action
                    action = "direction"

            if action == "effect":
                action = "effects"
            if action not in ("transformer", "font", "char") and value:
                value = value.lower()

            # Allow for special color values:
            if action in ("color", "foreground") and value == "default":
                value = DEFAULT_FG
            if action == "background" and value == "default":
                value = DEFAULT_BG
            if value == "transparent" and action in {"effects", "color", "foreground", "background"}:
                value = TRANSPARENT
            if value and isinstance(value, str) and value.count(",") == 2 and action in {"color", "foreground", "background"}:
                value = ast.literal_eval(value)
            if action == "transformer":
                action = "pretransformer"
                if starting_tag:
                    transformer_stack.append((value, offset, offset_repeat_counter))
                else:
                    closing_transformer, oppening_offset, oppening_repeat = transformer_stack.pop()
                    if not " " in closing_transformer:
                        # if there is a space, assume the spam of the transformer is given
                        # on the opening tag and do nothing.
                        spam = offset - oppening_offset
                        closing_mark = self.mark_sequence[oppening_offset]
                        if isinstance(closing_mark, list):
                            closing_mark = closing_mark[oppening_repeat]
                        closing_mark.attributes["pretransformer"] += f" {spam}"

            attribute_names = {"effects", "color", "foreground", "background", "direction", "pretransformer", "char", "font", }
            if action in attribute_names:
                if starting_tag:
                    attributes = {
                        action: (
                            Color(value) if action in ("color", "foreground", "background") else
                            sum(Effects.__members__.get(v.strip(), 0) for v in value.split("|"))
                                if action == "effects" else
                            getattr(Directions, value.upper()) if action == "direction" else
                            # getattr(transformers_library, value) if action == "pretransformer" else
                            value
                        )
                    }
                else:
                    pop_attributes = {action: None}

            if action == "new_line":
                attributes = {"new_line": True}

            if "," in action and attributes is None and pop_attributes is None:
                nx, ny = [v.strip() for v in action.split(",")]
                nnx, nny = int(nx), int(ny)
                if nx[0] in ("+", "-") and ny[0] in ("+", "-"):
                    rmoveto = nnx, nny
                elif nx[0] in ("+", "-") and ny[0] not in ("+", "-"):
                    moveto = RETAIN_POS, nny
                    rmoveto = nnx, 0
                elif nx[0] not in ("+", "-") and ny[0] in ("+", "-"):
                    moveto = nnx, RETAIN_POS
                    rmoveto = 0, nny
                else:
                    moveto = nnx, nny
            # Unknown token action - simply drop for now"
            mark = Mark(attributes, pop_attributes, moveto, rmoveto)
            if offset in self.mark_sequence:
                mark = Mark.merge(self.mark_sequence[offset], mark)
            self.mark_sequence[offset] = mark
Beispiel #29
0
def test_color_by_hsv_works():
    c = Color(hsv=(0, 1, 1))
    assert tuple(c.components) == (255, 0, 0)