chiark / gitweb /
Implement extending feeds backwards.
authorSimon Tatham <anakin@pobox.com>
Fri, 8 Dec 2023 08:26:03 +0000 (08:26 +0000)
committerSimon Tatham <anakin@pobox.com>
Fri, 8 Dec 2023 08:39:30 +0000 (08:39 +0000)
cursesclient.py
text.py

index d684310525cc8c1a4d7da193f0bcb74363d96bbe..381b473ddcf8a2e94c4968255b8bb3826f9742c2 100644 (file)
@@ -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 5b67a6fe40f70bc66742f5459721dbff877b493e..c0cd5666d10023bddbe0d7063bbeb28be7a33bbf 100644 (file)
--- 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