diff --git a/pyte/screens.py b/pyte/screens.py index 0ce2e86..238a92a 100644 --- a/pyte/screens.py +++ b/pyte/screens.py @@ -395,7 +395,8 @@ def draw(self, char): if mo.IRM in self.mode: self.insert_characters(1) - self[self.cursor.y][self.cursor.x] = self.cursor.attrs._replace(data=char) + self[self.cursor.y][self.cursor.x] = self.cursor.attrs \ + ._replace(data=char) # .. note:: We can't use :meth:`cursor_forward()`, because that # way, we'll never know when to linefeed. @@ -941,7 +942,7 @@ class HistoryScreen(DiffScreen): def __init__(self, columns, lines, history=100, ratio=.5): self.history = History(deque(maxlen=history // 2), - deque(maxlen=history - history // 2), + deque(maxlen=history), float(ratio), history, history) @@ -970,6 +971,13 @@ def __after__(self, command): self[idx] = line + take(self.columns - len(line), self.default_line) + # If we're at the bottom of the history buffer and `DECTCEM` + # mode is set -- show the cursor. + self.cursor.hidden = not ( + abs(self.history.position - self.history.size) < self.lines and + mo.DECTCEM in self.mode + ) + super(HistoryScreen, self).__after__(command) def reset(self): @@ -1007,7 +1015,7 @@ def prev_page(self): ``ratio = .5`` means that half the screen is restored from history on page switch. """ - if self.history.position > self.lines: + if self.history.position > self.lines and self.history.top: mid = min(len(self.history.top), int(math.ceil(self.lines * self.history.ratio))) @@ -1021,9 +1029,13 @@ def prev_page(self): self.dirty = set(range(self.lines)) + if len(self) is not self.lines or self.history.position > self.history.size: + import pdb; pdb.set_trace() + + def next_page(self): """Moves the screen page down through the history buffer.""" - if self.history.position < self.history.size: + if self.history.position < self.history.size and self.history.bottom: mid = min(len(self.history.bottom), int(math.ceil(self.lines * self.history.ratio))) @@ -1036,3 +1048,6 @@ def next_page(self): ] self.dirty = set(range(self.lines)) + + if len(self) is not self.lines or self.history.position > self.history.size: + import pdb; pdb.set_trace() diff --git a/tests/test_history.py b/tests/test_history.py index d6c50b5..708bd36 100644 --- a/tests/test_history.py +++ b/tests/test_history.py @@ -72,10 +72,10 @@ def test_reverse_index(): assert screen.history.bottom[1] == line # c) rotation. - for _ in range(len(screen) * screen.lines): + for _ in range(len(screen) ** screen.lines): screen.reverse_index() - assert len(screen.history.bottom) == 25 # pages // 2 * lines + assert len(screen.history.bottom) == 50 def test_prev_page(): @@ -153,8 +153,6 @@ def test_prev_page(): # c) same with odd number of lines. screen = HistoryScreen(5, 5, history=50) - # Once again filling the screen with line numbers, but this time, - # we need them to span on multiple lines. for idx in range(len(screen) * 10): map(screen.draw, unicode(idx)) screen.linefeed() @@ -188,7 +186,97 @@ def test_prev_page(): " ", ] + # d) same with cursor in the middle of the screen. + screen = HistoryScreen(5, 5, history=50) + + for idx in range(len(screen) * 10): + map(screen.draw, unicode(idx)) + screen.linefeed() + + assert screen.history.top + assert not screen.history.bottom + assert screen.history.position == 50 + assert screen.display == [ + "46 ", + "47 ", + "48 ", + "49 ", + " " + ] + + screen.cursor_to_line(screen.lines // 2) + + while screen.history.position > screen.lines: + screen.prev_page() + + assert screen.history.position == screen.lines + assert len(screen) == screen.lines + assert screen.display == [ + "21 ", + "22 ", + "23 ", + "24 ", + "25 " + ] + + while screen.history.position < screen.history.size: + screen.next_page() + assert screen.history.position == screen.history.size + assert len(screen) == screen.lines + assert screen.display == [ + "46 ", + "47 ", + "48 ", + "49 ", + " " + ] + + # e) same with cursor near the middle of the screen. + screen = HistoryScreen(5, 5, history=50) + + for idx in range(len(screen) * 10): + map(screen.draw, unicode(idx)) + screen.linefeed() + + assert screen.history.top + assert not screen.history.bottom + assert screen.history.position == 50 + assert screen.display == [ + "46 ", + "47 ", + "48 ", + "49 ", + " " + ] + + screen.cursor_to_line(screen.lines // 2 - 2) + + while screen.history.position > screen.lines: + screen.prev_page() + + assert screen.history.position == screen.lines + assert len(screen) == screen.lines + assert screen.display == [ + "21 ", + "22 ", + "23 ", + "24 ", + "25 " + ] + + while screen.history.position < screen.history.size: + screen.next_page() + + assert screen.history.position == screen.history.size + assert len(screen) == screen.lines + assert screen.display == [ + "46 ", + "47 ", + "48 ", + "49 ", + " " + ] def test_next_page(): screen = HistoryScreen(5, 5, history=50) @@ -386,3 +474,25 @@ def test_draw(): "24 ", "x " ] + + +def test_cursor_is_hidden(): + screen = HistoryScreen(5, 5, history=50) + stream = Stream() + stream.attach(screen) + stream.escape["N"] = "next_page" + stream.escape["P"] = "prev_page" + + for idx in range(len(screen) * 5): + map(stream.feed, unicode(idx) + "\n") + + assert not screen.cursor.hidden + + stream.feed(ctrl.ESC + "P") + assert screen.cursor.hidden + stream.feed(ctrl.ESC + "P") + assert screen.cursor.hidden + stream.feed(ctrl.ESC + "N") + assert screen.cursor.hidden + stream.feed(ctrl.ESC + "N") + assert not screen.cursor.hidden