Skip to content
This repository was archived by the owner on Feb 20, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions rtv/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from .terminal import Terminal
from .content import RequestHeaderRateLimiter
from .objects import curses_session, patch_webbrowser
from .page import PageStack
from .subreddit_page import SubredditPage
from .submission_page import SubmissionPage
from .exceptions import ConfigError, SubredditError, SubmissionError
Expand Down Expand Up @@ -233,8 +234,9 @@ def main():
except Exception as e:
_logger.exception(e)
raise SubmissionError('Unable to load {0}'.format(url))
while page:
page = page.loop()
PageStack.add(page)
ps = PageStack()
ps.run()

page = None
name = config['subreddit']
Expand All @@ -251,8 +253,9 @@ def main():
raise SubredditError('Unable to load {0}'.format(name))

# Launch the subreddit page
while page:
page = page.loop()
PageStack.add(page)
ps = PageStack()
ps.run()

except ConfigError as e:
_logger.exception(e)
Expand Down
27 changes: 2 additions & 25 deletions rtv/inbox_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,6 @@ def __init__(self, reddit, term, config, oauth, content_type='all'):
self.nav = Navigator(self.content.get)
self.content_type = content_type

def handle_selected_page(self):
"""
Open the subscription and submission pages subwindows, but close the
current page if any other type of page is selected.
"""
if not self.selected_page:
pass
if self.selected_page.name in ('subscription', 'submission'):
# Launch page in a subwindow
self.selected_page = self.selected_page.loop()
elif self.selected_page.name in ('subreddit', 'inbox'):
# Replace the current page
self.active = False
else:
raise RuntimeError(self.selected_page.name)

@logged_in
def refresh_content(self, order=None, name=None):
"""
Expand Down Expand Up @@ -108,13 +92,6 @@ def inbox_reply(self):
"""
self.reply()

@InboxController.register(Command('INBOX_EXIT'))
def close_inbox(self):
"""
Close inbox and return to the previous page.
"""
self.active = False

@InboxController.register(Command('INBOX_VIEW_CONTEXT'))
@logged_in
def view_context(self):
Expand All @@ -123,7 +100,7 @@ def view_context(self):
"""
url = self.get_selected_item().get('context')
if url:
self.selected_page = self.open_submission_page(url)
self.open_submission_page(url)

@InboxController.register(Command('INBOX_OPEN_SUBMISSION'))
@logged_in
Expand All @@ -133,7 +110,7 @@ def open_submission(self):
"""
url = self.get_selected_item().get('submission_permalink')
if url:
self.selected_page = self.open_submission_page(url)
self.open_submission_page(url)

def _draw_item(self, win, data, inverted):

Expand Down
131 changes: 65 additions & 66 deletions rtv/page.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,51 @@ class PageController(Controller):
character_map = {}


class PageStack(object):
stack = []

def __init__(self, max_size=20):
self.max_size = max_size

@staticmethod
def add(page):
PageStack.stack.append(page)

@staticmethod
def init(page=None):
if page:
PageStack.stack = [page]
else:
PageStack.stack = []

@staticmethod
def pop():
return PageStack.stack.pop()

@staticmethod
def size():
return len(PageStack.stack)

@staticmethod
def current_page():
return PageStack.stack[-1]

def run(self):
"""
Runs the PageStack. It takes the most recently added page and calls
the calls the pages' wait method to draw the page and wait for
user input.
"""
while PageStack.stack:
self._stay_within_max_size()
page = PageStack.current_page()
page.wait()

def _stay_within_max_size(self):
if len(PageStack.stack) > self.max_size:
PageStack.stack = PageStack.stack[1:]


class Page(object):

BANNER = None
Expand All @@ -52,8 +97,6 @@ def __init__(self, reddit, term, config, oauth):
self.nav = None
self.controller = None

self.active = True
self.selected_page = None
self._row = 0
self._subwindows = None

Expand All @@ -69,68 +112,13 @@ def get_selected_item(self):
"""
return self.content.get(self.nav.absolute_index)

def loop(self):
def wait(self):
"""
Main control loop runs the following steps:
1. Re-draw the screen
2. Wait for user to press a key (includes terminal resizing)
3. Trigger the method registered to the input key
4. Check if there are any nested pages that need to be looped over

The loop will run until self.active is set to False from within one of
the methods.
Draw the page and wait for user input.
"""
self.active = True

# This needs to be called once before the main loop, in case a subpage
# was pre-selected before the loop started. This happens in __main__.py
# with ``page.open_submission(url=url)``
while self.selected_page and self.active:
self.handle_selected_page()

while self.active:
self.draw()
ch = self.term.stdscr.getch()
self.controller.trigger(ch)

while self.selected_page and self.active:
self.handle_selected_page()

return self.selected_page

def handle_selected_page(self):
"""
Some commands will result in an action that causes a new page to open.
Examples include selecting a submission, viewing subscribed subreddits,
or opening the user's inbox. With these commands, the newly selected
page will be pre-loaded and stored in ``self.selected_page`` variable.
It's up to each page type to determine what to do when another page is
selected.

- It can start a nested page.loop(). This would allow the user to
return to their previous screen after exiting the sub-page. For
example, this is what happens when opening an individual submission
from within a subreddit page. When the submission is closed, the
user resumes the subreddit that they were previously viewing.

- It can close the current self.loop() and bubble the selected page up
one level in the loop stack. For example, this is what happens when
the user opens their subscriptions and selects a subreddit. The
subscription page loop is closed and the selected subreddit is
bubbled up to the root level loop.

Care should be taken to ensure the user can never enter an infinite
nested loop, as this could lead to memory leaks and recursion errors.

# Example of an unsafe nested loop
subreddit_page.loop()
-> submission_page.loop()
-> subreddit_page.loop()
-> submission_page.loop()
...

"""
raise NotImplementedError
self.draw()
ch = self.term.stdscr.getch()
self.controller.trigger(ch)

@PageController.register(Command('REFRESH'))
def reload_page(self):
Expand Down Expand Up @@ -240,6 +228,13 @@ def move_page_bottom(self):
self.nav.cursor_index = 0
self.nav.inverted = True

@PageController.register(Command('RETURN'))
def page_return(self):
if PageStack.size() == 1:
self.term.flash()
else:
PageStack.pop()

@PageController.register(Command('UPVOTE'))
@logged_in
def upvote(self):
Expand Down Expand Up @@ -476,7 +471,7 @@ def send_private_message(self):
raise TemporaryFileError()
else:
self.term.show_notification('Message sent!')
self.selected_page = self.open_inbox_page('sent')
self.open_inbox_page('sent')

def prompt_and_select_link(self):
"""
Expand Down Expand Up @@ -551,15 +546,15 @@ def subscriptions(self):
"""
View a list of the user's subscribed subreddits
"""
self.selected_page = self.open_subscription_page('subreddit')
self.open_subscription_page('subreddit')

@PageController.register(Command('MULTIREDDITS'))
@logged_in
def multireddits(self):
"""
View a list of the user's subscribed multireddits
"""
self.selected_page = self.open_subscription_page('multireddit')
self.open_subscription_page('multireddit')

@PageController.register(Command('PROMPT'))
def prompt(self):
Expand Down Expand Up @@ -589,7 +584,7 @@ def inbox(self):
"""
View the user's inbox.
"""
self.selected_page = self.open_inbox_page('all')
self.open_inbox_page('all')

def open_inbox_page(self, content_type):
"""
Expand All @@ -601,6 +596,7 @@ def open_inbox_page(self, content_type):
page = InboxPage(self.reddit, self.term, self.config, self.oauth,
content_type=content_type)
if not self.term.loader.exception:
PageStack.add(page)
return page

def open_subscription_page(self, content_type):
Expand All @@ -613,6 +609,7 @@ def open_subscription_page(self, content_type):
page = SubscriptionPage(self.reddit, self.term, self.config,
self.oauth, content_type=content_type)
if not self.term.loader.exception:
PageStack.add(page)
return page

def open_submission_page(self, url=None, submission=None):
Expand All @@ -625,6 +622,7 @@ def open_submission_page(self, url=None, submission=None):
page = SubmissionPage(self.reddit, self.term, self.config,
self.oauth, url=url, submission=submission)
if not self.term.loader.exception:
PageStack.add(page)
return page

def open_subreddit_page(self, name):
Expand All @@ -637,6 +635,7 @@ def open_subreddit_page(self, name):
page = SubredditPage(self.reddit, self.term, self.config,
self.oauth, name)
if not self.term.loader.exception:
PageStack.add(page)
return page

def clear_input_queue(self):
Expand Down
23 changes: 0 additions & 23 deletions rtv/submission_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,6 @@ def __init__(self, reddit, term, config, oauth, url=None, submission=None):
# Start at the submission post, which is indexed as -1
self.nav = Navigator(self.content.get, page_index=-1)

def handle_selected_page(self):
"""
Open the subscription page in a subwindow, but close the current page
if any other type of page is selected.
"""
if not self.selected_page:
pass
elif self.selected_page.name == 'subscription':
# Launch page in a subwindow
self.selected_page = self.selected_page.loop()
elif self.selected_page.name in ('subreddit', 'submission', 'inbox'):
# Replace the current page
self.active = False
else:
raise RuntimeError(self.selected_page.name)

def refresh_content(self, order=None, name=None):
"""
Re-download comments and reset the page index
Expand Down Expand Up @@ -110,13 +94,6 @@ def toggle_comment(self):
self.nav.flip(len(self._subwindows) - 1)
self.nav.top_item_height = n_rows

@SubmissionController.register(Command('SUBMISSION_EXIT'))
def exit_submission(self):
"""
Close the submission and return to the subreddit page
"""
self.active = False

@SubmissionController.register(Command('SUBMISSION_OPEN_IN_BROWSER'))
def open_link(self):
"""
Expand Down
21 changes: 3 additions & 18 deletions rtv/subreddit_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,6 @@ def __init__(self, reddit, term, config, oauth, name):
self.nav = Navigator(self.content.get)
self.toggled_subreddit = None

def handle_selected_page(self):
"""
Open all selected pages in subwindows except other subreddit pages.
"""
if not self.selected_page:
pass
elif self.selected_page.name in ('subscription', 'submission', 'inbox'):
# Launch page in a subwindow
self.selected_page = self.selected_page.loop()
elif self.selected_page.name == 'subreddit':
# Replace the current page
self.active = False
else:
raise RuntimeError(self.selected_page.name)

def refresh_content(self, order=None, name=None):
"""
Re-download all submissions and reset the page index
Expand Down Expand Up @@ -165,7 +150,7 @@ def open_submission(self, url=None):
if data.get('url_type') == 'selfpost':
self.config.history.add(data['url_full'])

self.selected_page = self.open_submission_page(url)
self.open_submission_page(url)

@SubredditController.register(Command('SUBREDDIT_OPEN_IN_BROWSER'))
def open_link(self):
Expand Down Expand Up @@ -217,7 +202,7 @@ def post_submission(self):

if not self.term.loader.exception:
# Open the newly created submission
self.selected_page = self.open_submission_page(submission=submission)
self.open_submission_page(submission=submission)

@SubredditController.register(Command('SUBREDDIT_HIDE'))
@logged_in
Expand All @@ -233,7 +218,7 @@ def hide(self):
with self.term.loader('Hiding'):
data['object'].hide()
data['hidden'] = True

def _draw_item(self, win, data, inverted):

n_rows, n_cols = win.getmaxyx()
Expand Down
Loading