Merge pull request #217 from michael-lazar/cursor-tracking

Cursor tracking
This commit is contained in:
Michael Lazar
2016-04-21 01:15:44 -07:00
8 changed files with 270 additions and 17 deletions

View File

@@ -92,6 +92,7 @@ class Content(object):
data['type'] = 'MoreComments'
data['count'] = comment.count
data['body'] = 'More comments'
data['hidden'] = True
else:
author = getattr(comment, 'author', '[deleted]')
name = getattr(author, 'name', '[deleted]')
@@ -114,6 +115,7 @@ class Content(object):
data['gold'] = comment.gilded > 0
data['permalink'] = permalink
data['stickied'] = stickied
data['hidden'] = False
return data
@@ -154,6 +156,7 @@ class Content(object):
data['gold'] = sub.gilded > 0
data['nsfw'] = sub.over_18
data['stickied'] = sub.stickied
data['hidden'] = False
data['index'] = None # This is filled in later by the method caller
if sub.url.split('/r/')[-1] == sub.permalink.split('/r/')[-1]:
@@ -317,7 +320,8 @@ class SubmissionContent(Content):
'cache': cache,
'count': count,
'level': data['level'],
'body': 'Hidden'}
'body': 'Hidden',
'hidden': True}
self._comment_data[index:index + len(cache)] = [comment]

View File

@@ -315,7 +315,8 @@ class Navigator(object):
valid_page_cb,
page_index=0,
cursor_index=0,
inverted=False):
inverted=False,
top_item_height=None):
"""
Params:
valid_page_callback (func): This function, usually `Content.get`,
@@ -331,11 +332,16 @@ class Navigator(object):
inverted - The page is drawn from the bottom of the screen,
starting with the page index, up to the top of the
screen.
top_item_height (int): If this is set to a non-null value
The number of columns that the top-most item
should utilize if non-inverted. This is used for a special mode
where all items are drawn non-inverted except for the top one.
"""
self.page_index = page_index
self.cursor_index = cursor_index
self.inverted = inverted
self.top_item_height = top_item_height
self._page_cb = valid_page_cb
@property
@@ -396,15 +402,21 @@ class Navigator(object):
# Flip the orientation and reset the cursor
self.flip(self.cursor_index)
self.cursor_index = 0
self.top_item_height = None
redraw = True
else:
if self.cursor_index > 0:
self.cursor_index -= 1
if self.top_item_height and self.cursor_index == 0:
# Selecting the partially displayed item
self.top_item_height = None
redraw = True
else:
self.page_index -= self.step
if self._is_valid(self.absolute_index):
# We have reached the beginning of the page - move the
# index
self.top_item_height = None
redraw = True
else:
self.page_index += self.step
@@ -478,6 +490,7 @@ class Navigator(object):
self.page_index += (self.step * n_windows)
self.cursor_index = n_windows
self.inverted = not self.inverted
self.top_item_height = None
def _is_valid(self, page_index):
"""

View File

@@ -327,29 +327,46 @@ class Page(object):
# If not inverted, align the first submission with the top and draw
# downwards. If inverted, align the first submission with the bottom
# and draw upwards.
cancel_inverted = True
current_row = (win_n_rows - 1) if inverted else 0
available_rows = (win_n_rows - 1) if inverted else win_n_rows
top_item_height = None if inverted else self.nav.top_item_height
for data in self.content.iterate(page_index, step, win_n_cols - 2):
subwin_n_rows = min(available_rows, data['n_rows'])
subwin_inverted = inverted
if top_item_height is not None:
# Special case: draw the page as non-inverted, except for the
# top element. This element will be drawn as inverted with a
# restricted height
subwin_n_rows = min(subwin_n_rows, top_item_height)
subwin_inverted = True
top_item_height = None
subwin_n_cols = win_n_cols - data['offset']
start = current_row - subwin_n_rows if inverted else current_row
subwindow = window.derwin(
subwin_n_rows, subwin_n_cols, start, data['offset'])
attr = self._draw_item(subwindow, data, inverted)
attr = self._draw_item(subwindow, data, subwin_inverted)
self._subwindows.append((subwindow, attr))
available_rows -= (subwin_n_rows + 1) # Add one for the blank line
current_row += step * (subwin_n_rows + 1)
if available_rows <= 0:
# Indicate the page is full and we can keep the inverted screen.
cancel_inverted = False
break
else:
# If the page is not full we need to make sure that it is NOT
if len(self._subwindows) == 1:
# Never draw inverted if only one subwindow. The top of the
# subwindow should always be aligned with the top of the screen.
cancel_inverted = True
if cancel_inverted and self.nav.inverted:
# In some cases we need to make sure that the screen is NOT
# inverted. Unfortunately, this currently means drawing the whole
# page over again. Could not think of a better way to pre-determine
# if the content will fill up the page, given that it is dependent
# on the size of the terminal.
if self.nav.inverted:
self.nav.flip((len(self._subwindows) - 1))
self._draw_content()
self.nav.flip((len(self._subwindows) - 1))
self._draw_content()
self._row = n_rows

View File

@@ -33,11 +33,19 @@ class SubmissionPage(Page):
current_index = self.nav.absolute_index
self.content.toggle(current_index)
# This logic handles a display edge case after a comment toggle. We want
# to make sure that when we re-draw the page, the cursor stays at its
# current absolute position on the screen. In order to do this, apply
# a fixed offset if, while inverted, we either try to hide the bottom
# comment or toggle any of the middle comments.
if self.nav.inverted:
# Reset the navigator so that the cursor is at the bottom of the
# page. This is a workaround to handle if folding the comment
# causes the cursor index to go out of bounds.
self.nav.page_index, self.nav.cursor_index = current_index, 0
data = self.content.get(current_index)
if data['hidden'] or self.nav.cursor_index != 0:
window = self._subwindows[-1][0]
n_rows, _ = window.getmaxyx()
self.nav.flip(len(self._subwindows) - 1)
self.nav.top_item_height = n_rows
@SubmissionController.register(Command('SUBMISSION_EXIT'))
def exit_submission(self):
@@ -155,6 +163,16 @@ class SubmissionPage(Page):
valid_rows = range(0, n_rows)
offset = 0 if not inverted else -(data['n_rows'] - n_rows)
# If there isn't enough space to fit the comment body on the screen,
# replace the last line with a notification.
split_body = data['split_body']
if data['n_rows'] > n_rows:
# Only when there is a single comment on the page and not inverted
if not inverted and len(self._subwindows) == 0:
cutoff = data['n_rows'] - n_rows + 1
split_body = split_body[:-cutoff]
split_body.append('(Not enough space to display)')
row = offset
if row in valid_rows:
@@ -178,7 +196,7 @@ class SubmissionPage(Page):
text, attr = self.term.stickied
self.term.add_line(win, text, attr=attr)
for row, text in enumerate(data['split_body'], start=offset+1):
for row, text in enumerate(split_body, start=offset+1):
if row in valid_rows:
self.term.add_line(win, text, row, 1)

View File

@@ -0,0 +1,173 @@
interactions:
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate, compress']
User-Agent: [!!python/unicode rtv test suite PRAW/3.3.0 Python/2.7.6 Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty]
method: !!python/unicode GET
uri: https://www.reddit.com/r/Python/comments/2xmo63.json
response:
body:
string: !!binary |
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
headers:
access-control-allow-origin: ['*']
access-control-expose-headers: ['X-Reddit-Tracking, X-Moose']
cache-control: ['max-age=0, must-revalidate']
cf-ray: [296f3f0aeb072858-SJC]
connection: [keep-alive]
content-encoding: [gzip]
content-length: ['7683']
content-type: [application/json; charset=UTF-8]
date: ['Thu, 21 Apr 2016 07:50:39 GMT']
server: [cloudflare-nginx]
set-cookie: ['__cfduid=d8e1d83c8cfa76ac404e21fc7d924dc961461225038; expires=Fri,
21-Apr-17 07:50:38 GMT; path=/; domain=.reddit.com; HttpOnly', 'loid=hCXBgtTCOflyUpYHv9;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 21-Apr-2018 07:50:38
GMT; secure', 'loidcreated=2016-04-21T07%3A50%3A38.582Z; Domain=reddit.com;
Max-Age=63071999; Path=/; expires=Sat, 21-Apr-2018 07:50:38 GMT; secure']
strict-transport-security: [max-age=15552000; includeSubDomains; preload]
vary: [accept-encoding]
x-content-type-options: [nosniff]
x-frame-options: [SAMEORIGIN]
x-moose: [majestic]
x-reddit-tracking: ['https://pixel.redditmedia.com/pixel/of_destiny.png?v=wUoXo%2B%2BbEgovlSTbKrPiRzy5CGl5PaWJAwmKAdLtVFDt9zGb%2FmDNZzDIUNfJZ7SEiQl6UK0WZns%3D']
x-ua-compatible: [IE=edge]
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
version: 1

View File

@@ -101,7 +101,8 @@ def test_content_submission(reddit, terminal):
assert content.get(40)['type'] == 'Comment'
for data in content.iterate(-1, 1):
assert all(k in data for k in ('object', 'n_rows', 'offset', 'type'))
assert all(k in data for k in ('object', 'n_rows', 'offset', 'type',
'hidden'))
# All text should be converted to unicode by this point
for val in data.values():
assert not isinstance(val, six.binary_type)
@@ -121,11 +122,14 @@ def test_content_submission(reddit, terminal):
data = content.get(2)
assert data['type'] == 'HiddenComment'
assert data['count'] == 3
assert data['hidden'] is True
assert data['level'] >= content.get(3)['level']
assert len(content._comment_data) == 43
# Toggling again expands the children
content.toggle(2)
data = content.get(2)
assert data['hidden'] is False
assert len(content._comment_data) == 45
@@ -195,8 +199,9 @@ def test_content_subreddit(reddit, terminal):
assert content.get(0)['type'] == 'Submission'
for data in content.iterate(0, 1):
assert all(k in data for k in ('object', 'n_rows', 'offset', 'type',
'index', 'title', 'split_title'))
assert all(k in data for k in (
'object', 'n_rows', 'offset', 'type', 'index', 'title',
'split_title', 'hidden'))
# All text should be converted to unicode by this point
for val in data.values():
assert not isinstance(val, six.binary_type)
@@ -227,6 +232,7 @@ def test_content_subreddit_load_more(reddit, terminal):
assert data['index'] == i + 1
assert data['title'].startswith(six.text_type(i + 1))
def test_content_subreddit_from_name(reddit, terminal):
name = '/r/python'

View File

@@ -346,11 +346,13 @@ def test_objects_navigator_properties():
assert nav.step == 1
assert nav.position == (0, 0, False)
assert nav.absolute_index == 0
assert nav.top_item_height is None
nav = Navigator(valid_page_cb, 5, 2, True)
nav = Navigator(valid_page_cb, 5, 2, True, 10)
assert nav.step == -1
assert nav.position == (5, 2, True)
assert nav.absolute_index == 3
assert nav.top_item_height == 10
def test_objects_navigator_move():
@@ -360,6 +362,7 @@ def test_objects_navigator_move():
raise IndexError()
nav = Navigator(valid_page_cb)
nav.top_item_height = 5
# Try to scroll up past the first item
valid, redraw = nav.move(-1, 2)
@@ -375,6 +378,7 @@ def test_objects_navigator_move():
# Scroll down, reach last item on the page and flip the screen
valid, redraw = nav.move(1, 3)
assert nav.top_item_height is None
assert nav.page_index == 2
assert nav.cursor_index == 0
assert nav.inverted

View File

@@ -111,6 +111,24 @@ def test_submission_pager(submission_page, terminal):
assert terminal.open_pager.called
def test_submission_comment_not_enough_space(submission_page, terminal):
# The first comment is 10 lines, shrink the screen so that it won't fit.
# Setting the terminal to 10 lines means that there will only be 8 lines
# available (after subtracting the header and footer) to draw the comment.
terminal.stdscr.nlines = 10
# Select the first comment
with mock.patch.object(submission_page, 'clear_input_queue'):
submission_page.move_cursor_down()
submission_page.draw()
text = '(Not enough space to display)'.encode('ascii')
window = terminal.stdscr.subwin
window.subwin.addstr.assert_any_call(7, 1, text)
def test_submission_vote(submission_page, refresh_token):
# Log in