From 0830543c54b0016fde60c50714750bc2484bc924 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 8 Dec 2023 08:26:03 +0000 Subject: [PATCH] Implement extending feeds backwards. --- cursesclient.py | 58 +++++++++++++++++++++++++++++++++++++++++-------- text.py | 10 ++++++++- 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/cursesclient.py b/cursesclient.py index d684310..381b473 100644 --- a/cursesclient.py +++ b/cursesclient.py @@ -405,10 +405,14 @@ class File(Activity): self.mode = 'normal' def handle_key(self, ch): + backward_keys = {'-', 'b', 'B', curses.KEY_PPAGE, curses.KEY_LEFT} + if not (self.mode == 'normal' and ch in backward_keys): + self.unprime() + if self.mode == 'normal': if ch in {' ', curses.KEY_NPAGE, curses.KEY_RIGHT}: self.down_screen() - elif ch in {'-', 'b', 'B', curses.KEY_PPAGE, curses.KEY_LEFT}: + elif ch in backward_keys: self.up_screen() elif ch == curses.KEY_DOWN: self.down_line() @@ -452,6 +456,8 @@ class File(Activity): ch in {'d', 'D'}): self.boost_complete(-1) + def unprime(self): + pass # not supported def send_mode(self): pass # not supported def favourite_mode(self): @@ -481,11 +487,12 @@ class ObjectFile(File): self.select_target = None self.old_display_state = None self.index_by_line = [] + self.primed_to_extend = False def iter_text_indexed(self): yield self.header, None if not self.history_closed: - yield text.ExtendableIndicator(), None + yield text.ExtendableIndicator(self.primed_to_extend), None for i in range(self.minpos, self.maxpos): for thing in self.statuses[i].text(): yield thing, i # FIXME: maybe just yield the last? @@ -510,10 +517,29 @@ class ObjectFile(File): return got_any def regenerate_lines(self, width): - display_state = (self.mode, self.select_target) - if (self.width == width and display_state == self.old_display_state and - not self.fetch_new()): + # We need to recompute our line position in the buffer if the + # width has changed (so everything was rewrapped) or new stuff + # has arrived. + got_new = self.fetch_new() + recompute_line = got_new or self.width != width + + # If not that, and also nothing _else_ has changed, we don't + # need to do anything at all. + display_state = (self.mode, self.select_target, self.primed_to_extend) + if not recompute_line and display_state == self.old_display_state: return + + # If we're recomputing our line position but the width + # _hasn't_ changed, we should be able to keep our exact + # location within the current item. + pos_within_item = 0 + if self.width == width: + line_index = self.linepos + while (line_index < len(self.lines) and + self.index_by_line[line_index] == self.itempos): + line_index += 1 + pos_within_item = line_index - self.linepos + self.old_display_state = display_state self.lines = [] self.index_by_line = [] @@ -523,14 +549,17 @@ class ObjectFile(File): if (self.mode == 'select' and itemindex == self.select_target and hasattr(thing, 'can_highlight_as_target')): params['target'] = True + oldlen = len(self.lines) for line in thing.render(width, **params): for s in line.split(width): self.lines.append(s) self.index_by_line.append(itemindex) if itemindex == self.itempos: - pos = len(self.lines) - if self.width != width: - self.width = width + itemheight = len(self.lines) - oldlen + pos = len(self.lines) - min(pos_within_item, itemheight) + + self.width = width + if recompute_line: self.move_to(pos) def render(self): @@ -639,18 +668,29 @@ class ObjectFile(File): self.linepos = pos self.linepos = max(self.linepos, self.cc.scr_h - 1) self.linepos = min(self.linepos, len(self.lines)) + self.itempos = self.index_by_line[self.linepos - 1] return self.linepos != old_linepos def move_by(self, delta): return self.move_to(self.linepos + delta) def down_screen(self): return self.move_by(max(1, self.cc.scr_h - 3)) - def up_screen(self): return self.move_by(-max(1, self.cc.scr_h - 3)) def down_line(self): return self.move_by(+1) def up_line(self): return self.move_by(-1) def goto_top(self): return self.move_to(0) def goto_bottom(self): return self.move_to(len(self.lines)) + def up_screen(self): + success = self.move_by(-max(1, self.cc.scr_h - 3)) + if not success: + if not self.primed_to_extend: + self.primed_to_extend = True + else: + self.feed.extend_past() + self.primed_to_extend = False + def unprime(self): + self.primed_to_extend = False + class StatusFile(ObjectFile): items_are_statuses = True items_have_authors = True diff --git a/text.py b/text.py index 5b67a6f..c0cd566 100644 --- a/text.py +++ b/text.py @@ -231,8 +231,16 @@ class FileHeader: logo[1]) class ExtendableIndicator: + def __init__(self, primed): + self.primed = primed + def render(self, width): - message = ColouredString("FIXME: extendability message here", 'H') + if self.primed: + message = ColouredString("Press [B] once more to extend", + "HHHHHHHKHHHHHHHHHHHHHHHHHHHHH") + else: + message = ColouredString("Press [B] twice to extend", + "HHHHHHHKHHHHHHHHHHHHHHHHH") space = width - message.width lspace = space // 2 + 1 rspace = space - lspace + 1 -- 2.30.2