From 650813121279402b915c50ef729513cc030ce0c0 Mon Sep 17 00:00:00 2001 From: John Helmert Date: Fri, 28 Jun 2019 17:24:26 -0500 Subject: [PATCH] Implement compact look and feel. This comes with the addition of adding a reference to the config in SubredditPage objects, which breaks a lot of tests. Thoroughly discussed in #3. --- tuir/content.py | 35 ++++++++---- tuir/subreddit_page.py | 123 ++++++++++++++++++++++++++++++++++++---- tuir/templates/tuir.cfg | 7 +++ 3 files changed, 141 insertions(+), 24 deletions(-) diff --git a/tuir/content.py b/tuir/content.py index 65b9dde..75add2b 100644 --- a/tuir/content.py +++ b/tuir/content.py @@ -12,6 +12,7 @@ from bs4 import BeautifulSoup from kitchen.text.display import wrap from . import exceptions +from .config import Config from .packages import praw from .packages.praw.errors import InvalidSubreddit from .packages.praw.helpers import normalize_url @@ -563,18 +564,23 @@ class SubredditContent(Content): list for repeat access. """ - def __init__(self, name, submissions, loader, order=None, - max_title_rows=4, query=None, filter_nsfw=False): + def __init__(self, config, name, submissions, loader, order=None, + query=None, filter_nsfw=False): + self.config = config self.name = name self.order = order self.query = query - self.max_title_rows = max_title_rows self.filter_nsfw = filter_nsfw self._loader = loader self._submissions = submissions self._submission_data = [] + if self.config['look_and_feel'] == 'compact': + self.max_title_rows = 1 + else: + self.max_title_rows = 4 + # Verify that content exists for the given submission generator. # This is necessary because PRAW loads submissions lazily, and # there is is no other way to check things like multireddits that @@ -588,7 +594,7 @@ class SubredditContent(Content): raise exceptions.NoSubmissionsError(full_name) @classmethod - def from_name(cls, reddit, name, loader, order=None, query=None): + def from_name(cls, reddit, config, name, loader, order=None, query=None): """ Params: reddit (praw.Reddit): Instance of the reddit api. @@ -796,7 +802,7 @@ class SubredditContent(Content): filter_nsfw = (reddit.user and reddit.user.over_18 is False) # We made it! - return cls(display_name, submissions, loader, order=display_order, + return cls(config, display_name, submissions, loader, order=display_order, query=query, filter_nsfw=filter_nsfw) @property @@ -847,17 +853,22 @@ class SubredditContent(Content): data = self.strip_praw_comment(submission) data['index'] = len(self._submission_data) + 1 - # Add the post number to the beginning of the title - data['title'] = '{0}. {1}'.format(data['index'], data['title']) + + # Add the post number to the beginning of the title if necessary + if self.config['look_and_feel'] != 'compact': + data['title'] = '{0}. {1}'.format(data['index'], data['title']) + self._submission_data.append(data) # Modifies the original dict, faster than copying data = self._submission_data[index] - data['split_title'] = self.wrap_text(data['title'], width=n_cols) - if len(data['split_title']) > self.max_title_rows: - data['split_title'] = data['split_title'][:self.max_title_rows-1] - data['split_title'].append('(Not enough space to display)') - data['n_rows'] = len(data['split_title']) + 3 + + if self.config['look_and_feel'] == 'compact': + data['n_rows'] = 2 + else: + data['split_title'] = self.wrap_text(data['title'], width=n_cols) + data['n_rows'] = len(data['split_title']) + 3 + data['h_offset'] = 0 return data diff --git a/tuir/subreddit_page.py b/tuir/subreddit_page.py index 86b352e..449a211 100644 --- a/tuir/subreddit_page.py +++ b/tuir/subreddit_page.py @@ -28,7 +28,7 @@ class SubredditPage(Page): super(SubredditPage, self).__init__(reddit, term, config, oauth) self.controller = SubredditController(self, keymap=config.keymap) - self.content = SubredditContent.from_name(reddit, name, term.loader) + self.content = SubredditContent.from_name(reddit, self.config, name, term.loader) self.nav = Navigator(self.content.get) self.toggled_subreddit = None @@ -68,7 +68,8 @@ class SubredditPage(Page): with self.term.loader('Refreshing page'): self.content = SubredditContent.from_name( - self.reddit, name, self.term.loader, order=order, query=query) + self.reddit, self.config, name, + self.term.loader, order=order, query=query) if not self.term.loader.exception: self.nav = Navigator(self.content.get) @@ -133,7 +134,7 @@ class SubredditPage(Page): with self.term.loader('Searching'): self.content = SubredditContent.from_name( - self.reddit, name, self.term.loader, query=query) + self.reddit, self.config, name, self.term.loader, query=query) if not self.term.loader.exception: self.nav = Navigator(self.content.get) @@ -233,36 +234,36 @@ class SubredditPage(Page): with self.term.loader('Hiding'): data['object'].hide() data['hidden'] = True - - def _draw_item(self, win, data, inverted): - n_rows, n_cols = win.getmaxyx() - n_cols -= 1 # Leave space for the cursor in the first column - - # Handle the case where the window is not large enough to fit the data. - valid_rows = range(0, n_rows) - offset = 0 if not inverted else -(data['n_rows'] - n_rows) + def _draw_item_default(self, win, data, n_rows, n_cols, valid_rows, offset): + """ + Draw items with default look and feel + """ n_title = len(data['split_title']) + if data['url_full'] in self.config.history: attr = self.term.attr('SubmissionTitleSeen') else: attr = self.term.attr('SubmissionTitle') + for row, text in enumerate(data['split_title'], start=offset): if row in valid_rows: self.term.add_line(win, text, row, 1, attr) row = n_title + offset + if data['url_full'] in self.config.history: attr = self.term.attr('LinkSeen') else: attr = self.term.attr('Link') + if row in valid_rows: self.term.add_line(win, '{url}'.format(**data), row, 1, attr) row = n_title + offset + 1 - if row in valid_rows: + if row in valid_rows: attr = self.term.attr('Score') self.term.add_line(win, '{score}'.format(**data), row, 1, attr) self.term.add_space(win) @@ -311,6 +312,7 @@ class SubredditPage(Page): self.term.add_line(win, 'NSFW', attr=attr) row = n_title + offset + 2 + if row in valid_rows: attr = self.term.attr('SubmissionAuthor') self.term.add_line(win, '{author}'.format(**data), row, 1, attr) @@ -324,6 +326,103 @@ class SubredditPage(Page): self.term.add_space(win) self.term.add_line(win, '{flair}'.format(**data), attr=attr) + def _draw_item_compact(self, win, data, n_rows, n_cols, valid_rows, offset): + """ + Draw items with compact look and feel + """ + + if data['url_full'] in self.config.history: + sub_attr = self.term.attr('SubmissionTitleSeen') + else: + sub_attr = self.term.attr('SubmissionTitle') + + if offset in valid_rows: + self.term.add_line(win, '{title}'.format(**data), offset, 1, attr=sub_attr) + + offset += 1 # Next row + + if offset in valid_rows: + sep_attr = self.term.attr('Separator') + + self.term.add_line(win, '<', offset, 1, attr=sep_attr) + + self.term.add_line(win, '{index}'.format(**data), offset, attr=sub_attr) + + self.term.add_line(win, '|', offset, attr=sep_attr) + + # Seems that praw doesn't give us raw numbers for score and comment + # count, so we have to cut off the extraneous characters + attr = self.term.attr('Score') + self.term.add_line(win, '{0}'.format(data['score'][:-4]), offset, attr=attr) + + arrow, attr = self.term.get_arrow(data['likes']) + self.term.add_line(win, arrow, attr=attr) + + if data['comments'] is not None: + self.term.add_line(win, '|', offset, attr=sep_attr) + attr = self.term.attr('CommentCount') + self.term.add_line(win, '{0}C'.format(data['comments'][:-9]), attr=attr) + + self.term.add_line(win, '>', offset, attr=sep_attr) + self.term.add_space(win) + + attr = self.term.attr('Created') + self.term.add_line(win, '{created}{edited}'.format(**data), attr=attr) + self.term.add_space(win) + + attr = self.term.attr('SubmissionAuthor') + self.term.add_line(win, '{author}'.format(**data), offset, attr=attr) + self.term.add_space(win) + + attr = self.term.attr('SubmissionSubreddit') + self.term.add_line(win, '/r/{subreddit}'.format(**data), attr=attr) + + if data['saved']: + attr = self.term.attr('Saved') + self.term.add_space(win) + self.term.add_line(win, '[saved]', attr=attr) + + if data['hidden']: + attr = self.term.attr('Hidden') + self.term.add_space(win) + self.term.add_line(win, '[hidden]', attr=attr) + + if data['stickied']: + attr = self.term.attr('Stickied') + self.term.add_space(win) + self.term.add_line(win, '[stickied]', attr=attr) + + if data['gold']: + attr = self.term.attr('Gold') + self.term.add_space(win) + count = 'x{}'.format(data['gold']) if data['gold'] > 1 else '' + text = self.term.gilded + count + self.term.add_line(win, text, attr=attr) + + if data['nsfw']: + attr = self.term.attr('NSFW') + self.term.add_space(win) + self.term.add_line(win, 'NSFW', attr=attr) + + if data['flair']: + attr = self.term.attr('SubmissionFlair') + self.term.add_space(win) + self.term.add_line(win, '{flair}'.format(**data), attr=attr) + + def _draw_item(self, win, data, inverted): + n_rows, n_cols = win.getmaxyx() + n_cols -= 1 # Leave space for the cursor in the first column + + # Handle the case where the window is not large enough to fit the data. + valid_rows = range(0, n_rows) + offset = 0 if not inverted else - (data['n_rows'] - n_rows) + + if self.config['look_and_feel'] == 'compact': + self._draw_item_compact(win, data, n_rows, n_cols, valid_rows, offset) + else: + self._draw_item_default(win, data, n_rows, n_cols, valid_rows, offset) + attr = self.term.attr('CursorBlock') + for y in range(n_rows): self.term.addch(win, y, 0, str(' '), attr) diff --git a/tuir/templates/tuir.cfg b/tuir/templates/tuir.cfg index 31c7932..a20b5ca 100644 --- a/tuir/templates/tuir.cfg +++ b/tuir/templates/tuir.cfg @@ -58,6 +58,13 @@ max_comment_cols = 120 ; Hide username if logged in, display "Logged in" instead hide_username = False +; Set the look and feel. Default allows posts to be spread across 4 lines, +; while compact reduces it to 2 lines. Compact reduces the vertical space +; the cost of horizontal space - the title won't be wrapped to the next +; line. +; look_and_feel = default +; look_and_feel = compact + ; Color theme, use "tuir --list-themes" to view a list of valid options. ; This can be an absolute filepath, or the name of a theme file that has ; been installed into either the custom of default theme paths.