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()
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):
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?
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 = []
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):
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