Ejemplo n.º 1
0
    def update(self):
        """Commit the changes in the screen buffer to the backend (terminal).

        Determines which pixels (characters) have been modified from their 
        previous value, and re-draws those pixels using the backend.

        It should be noted that the pixel attributes are compared to their
        previous values. This means that if you, for example, clear a black
        screen to white, and then clear it back to black, no pixels will be
        re-rendered. This means that it is reasonable to clear and re-render
        the entire screen whenever you make an update, if it seems too
        challenging to manually make only the necessary changes.
        """
        t0 = perf_counter()
        self._update_count = 0
        for y in range(self.h):
            for x in range(self.w):
                pixel = self.at_unsafe(x, y)
                if pixel != self._pixels_cache[x][y]:
                    self._pixels_cache[x][y].set(pixel)
                    self._update_count += 1

                    # don't render a pixel shadowed by a fullwidth character
                    if x > 0 and terminal_char_len(
                            self.at_unsafe(x - 1, y).char) > 1:
                        continue
                    self.render(pixel, x, y)

        self.backend.cursor_pos = self.cursor_pos
        self.backend.flush()
        self._update_duration = perf_counter() - t0
Ejemplo n.º 2
0
    def put_char(self, ch, x, y, *, fg=None, bg=None):
        """Put a single character and/or colors at a particular location.

        Puts a single character at the given x, y coordinates, only if those
        coordinates are within the bounds of the buffer. Coordinates are also
        considered out of bounds if the character has a width greater than 1 
        and it would not be entirely within the bounds of the buffer. If the 
        given coordinates are out of bounds, this method has no effect.

        If fg or bg colors are specified, they replace the fg or bg colors at
        the given coordinates. If None is given for either argument, the 
        existing colors are left unchanged.

        Returns the width of the character that was provided, even if it was 
        out of bounds.
        """
        ch_len = terminal_char_len(ch)
        if x >= 0 and y >= 0 and x + ch_len <= self.w and y < self.h:
            pixel = self.at_unsafe(x, y)
            pixel.char = ch
            if fg:
                pixel.fg = fg
            if bg:
                pixel.bg = bg

            # handle fullwidth (double-wide) characters.
            # clear character and set fg and bg so that values make sense if
            # the fullwidth character is later removed.
            if ch_len > 1:
                assert ch_len == 2
                shadowed = self.at_unsafe(x + 1, y)
                shadowed.char = " "
                if fg:
                    shadowed.fg = fg
                if bg:
                    shadowed.bg = bg
        return ch_len
Ejemplo n.º 3
0
def test_terminal_len():
    test_string = "你好 - Hello"
    assert terminal_len(test_string) == sum(
        terminal_char_len(i) for i in test_string)
Ejemplo n.º 4
0
def test_terminal_char_len_ambiguous():
    set_ambiguous_is_wide(False)
    assert terminal_char_len(ambiguous_char) == 1

    set_ambiguous_is_wide(True)
    assert terminal_char_len(ambiguous_char) == 2
Ejemplo n.º 5
0
def test_terminal_char_len_tab():
    # no way to tell tab width without context
    assert terminal_char_len("\t") == None
Ejemplo n.º 6
0
def test_terminal_char_len_control():
    assert terminal_char_len(control_char) == 0
Ejemplo n.º 7
0
def test_terminal_char_len_wide():
    assert terminal_char_len(wide_char) == 2
Ejemplo n.º 8
0
def test_terminal_char_len_narrow():
    assert terminal_char_len(narrow_char) == 1