Simplify format string handling
Instead of using a format that is stored in a three-wide tuple in each SubredditPage, the displaying is done at display-time. Functionality related to creating the format has been removed. Additionally, this simplification makes it possible for correctly spacing the %F format specifier. Previously, it couldn't easily look ahead to check if a space was necessary; now, the spacing should be always be correct for any combination of flair-like information and consecutive spaces will not be printed to ensure the format isn't made to look strange if a piece of data is missing. Tests have also been updated to reflect changes in the SubredditPage class. The SubredditPage._create_format test has been removed, and much of its functionality is now tested in the test for SubredditPage._draw_item_format. Related to #3
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import curses
|
import curses
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
import sys
|
||||||
|
|
||||||
import six
|
import six
|
||||||
import pytest
|
import pytest
|
||||||
@@ -61,23 +62,6 @@ def test_subreddit_page_construct_default(reddit, terminal, config, oauth):
|
|||||||
page.draw()
|
page.draw()
|
||||||
|
|
||||||
|
|
||||||
def test_subreddit_page_construct_nondefault(reddit, terminal, config, oauth):
|
|
||||||
# We're just testing the constructor, and only a little bit of the
|
|
||||||
# constructor is dependent on a nondefault look and feel, so we can test
|
|
||||||
# just that little bit. The rest is tested in the above test.
|
|
||||||
config['look_and_feel'] = 'compact'
|
|
||||||
|
|
||||||
with mock.patch.object(SubredditPage, '_create_format'):
|
|
||||||
with terminal.loader():
|
|
||||||
page = SubredditPage(reddit, terminal, config, oauth, '/r/python')
|
|
||||||
SubredditPage._create_format.assert_called_with(config.COMPACT_FORMAT)
|
|
||||||
|
|
||||||
config['subreddit_format'] = 'NonNull'
|
|
||||||
with terminal.loader():
|
|
||||||
page = SubredditPage(reddit, terminal, config, oauth, '/r/python')
|
|
||||||
SubredditPage._create_format.assert_called_with('NonNull')
|
|
||||||
|
|
||||||
|
|
||||||
def test_subreddit_refresh(subreddit_page, terminal):
|
def test_subreddit_refresh(subreddit_page, terminal):
|
||||||
|
|
||||||
# Refresh the page with default values
|
# Refresh the page with default values
|
||||||
@@ -722,17 +706,14 @@ def test_subreddit_page__gold_str(config, terminal, subreddit_page):
|
|||||||
|
|
||||||
data['gold'] = 1
|
data['gold'] = 1
|
||||||
goldstr = subreddit_page._gold_str(data)
|
goldstr = subreddit_page._gold_str(data)
|
||||||
assert goldstr == terminal.gilded + ' '
|
assert goldstr == terminal.gilded
|
||||||
|
|
||||||
data['gold'] = 2
|
data['gold'] = 2
|
||||||
goldstr = subreddit_page._gold_str(data)
|
goldstr = subreddit_page._gold_str(data)
|
||||||
assert goldstr == terminal.gilded + 'x2 '
|
assert goldstr == terminal.gilded + 'x2'
|
||||||
|
|
||||||
|
|
||||||
def test_subreddit_page__create_format(terminal, subreddit_page):
|
def test_subreddit_page__draw_item_format(terminal, subreddit_page):
|
||||||
# We won't test unimplemented format specifiers. We can add tests when they
|
|
||||||
# are implemented. We also won't test the lambdas that call another
|
|
||||||
# function - we test those functions individually
|
|
||||||
data = {
|
data = {
|
||||||
'index': '1',
|
'index': '1',
|
||||||
'title': 'Without saying what the category is, what are your top five?',
|
'title': 'Without saying what the category is, what are your top five?',
|
||||||
@@ -746,6 +727,7 @@ def test_subreddit_page__create_format(terminal, subreddit_page):
|
|||||||
'url': 'self.AskReddit',
|
'url': 'self.AskReddit',
|
||||||
'url_type': 'selfpost',
|
'url_type': 'selfpost',
|
||||||
'url_full': 'https://www.reddit.com/r/AskReddit/comments/99eh6b/without_saying_what_the_category_is_what_are_your/',
|
'url_full': 'https://www.reddit.com/r/AskReddit/comments/99eh6b/without_saying_what_the_category_is_what_are_your/',
|
||||||
|
'gold': 1,
|
||||||
'saved': True,
|
'saved': True,
|
||||||
'hidden': True,
|
'hidden': True,
|
||||||
'stickied': True,
|
'stickied': True,
|
||||||
@@ -757,6 +739,7 @@ def test_subreddit_page__create_format(terminal, subreddit_page):
|
|||||||
'%i': '1',
|
'%i': '1',
|
||||||
'%t': 'Without saying what the category is, what are your top five?',
|
'%t': 'Without saying what the category is, what are your top five?',
|
||||||
'%s': '144655',
|
'%s': '144655',
|
||||||
|
'%v': '▲',
|
||||||
'%c': '26584',
|
'%c': '26584',
|
||||||
'%r': '10month',
|
'%r': '10month',
|
||||||
'%e': '(edit 5month)',
|
'%e': '(edit 5month)',
|
||||||
@@ -767,157 +750,94 @@ def test_subreddit_page__create_format(terminal, subreddit_page):
|
|||||||
'%A': '[saved]',
|
'%A': '[saved]',
|
||||||
'%h': '[hidden]',
|
'%h': '[hidden]',
|
||||||
'%T': '[stickied]',
|
'%T': '[stickied]',
|
||||||
|
'%g': '✪',
|
||||||
'%n': 'NSFW',
|
'%n': 'NSFW',
|
||||||
'%f': 'Serious Replies Only',
|
'%f': 'Serious Replies Only',
|
||||||
}
|
}
|
||||||
|
|
||||||
# This is what terminal.attr is expected to be called with for each item
|
|
||||||
expected_attr = {
|
expected_attr = {
|
||||||
'%s': 'Score',
|
'%i': terminal.attr('SubmissionTitle'),
|
||||||
'%c': 'CommentCount',
|
'%t': terminal.attr('SubmissionTitle'),
|
||||||
'%r': 'Created',
|
'%s': terminal.attr('Score'),
|
||||||
'%e': 'Created',
|
'%v': terminal.attr('Upvote'),
|
||||||
'%a': 'SubmissionAuthor',
|
'%c': terminal.attr('CommentCount'),
|
||||||
'%S': 'SubmissionSubreddit',
|
'%r': terminal.attr('Created'),
|
||||||
'%A': 'Saved',
|
'%e': terminal.attr('Created'),
|
||||||
'%h': 'Hidden',
|
'%a': terminal.attr('SubmissionAuthor'),
|
||||||
'%T': 'Stickied',
|
'%S': terminal.attr('SubmissionSubreddit'),
|
||||||
'%g': 'Gold',
|
'%u': terminal.attr('Link'),
|
||||||
'%n': 'NSFW',
|
'%U': terminal.attr('Link'),
|
||||||
'%f': 'SubmissionFlair'
|
'%A': terminal.attr('Saved'),
|
||||||
|
'%h': terminal.attr('Hidden'),
|
||||||
|
'%T': terminal.attr('Stickied'),
|
||||||
|
'%g': terminal.attr('Gold'),
|
||||||
|
'%n': terminal.attr('NSFW'),
|
||||||
|
'%f': terminal.attr('SubmissionFlair')
|
||||||
}
|
}
|
||||||
|
|
||||||
# This set of tests checks for proper splitting and newline handling
|
|
||||||
# For simplicity's sake, use explicit newlines
|
|
||||||
test_format = 'a\n<>'
|
|
||||||
|
|
||||||
format_list = None
|
|
||||||
format_list = subreddit_page._create_format(test_format)
|
|
||||||
|
|
||||||
# This gets a bit ugly due to {re|str}.split() adding few null strings.
|
|
||||||
assert len(format_list) == 7
|
|
||||||
|
|
||||||
# %i, \n, <, >
|
|
||||||
assert format_list[0][0] == 'a'
|
|
||||||
assert format_list[1][0] == '\n'
|
|
||||||
assert format_list[3][0] == '<'
|
|
||||||
assert format_list[5][0] == '>'
|
|
||||||
|
|
||||||
# Check for newline flag
|
|
||||||
assert format_list[2][2] == True
|
|
||||||
|
|
||||||
terminal.get_arrow = mock.Mock(return_value=['val1', 'val2'])
|
|
||||||
terminal.attr = mock.Mock()
|
|
||||||
subreddit_page._gold_str = mock.Mock()
|
|
||||||
|
|
||||||
# This set of tests makes sure each format specifier works as intended
|
|
||||||
for fmt in filter(None, '%i %t %s %v %c %r %e %a %S %u %U %A %h %T %g %n %f %F'.split()):
|
|
||||||
format_list = subreddit_page._create_format(fmt)
|
|
||||||
|
|
||||||
# First, some special cases
|
|
||||||
if fmt == '%v':
|
|
||||||
# User's comment status - upvoted, downvoted, neither
|
|
||||||
format_list[1][0](data)
|
|
||||||
|
|
||||||
# data['likes'] == True
|
|
||||||
terminal.get_arrow.assert_called_with(True)
|
|
||||||
elif fmt == '%i' or fmt == '%t' or fmt == '%u' or fmt == '%U':
|
|
||||||
# Don't check the attribute for these - they have their own
|
|
||||||
# attribute functions
|
|
||||||
assert format_list[1][0](data) == expected_str[fmt]
|
|
||||||
elif fmt == '%g':
|
|
||||||
# Gold. The string is given by the function _gold_str() which is
|
|
||||||
# tested elsewhere, so here we just check that it was called
|
|
||||||
assert subreddit_page._gold_str.assert_called
|
|
||||||
|
|
||||||
subreddit_page._gold_str.mock_reset()
|
|
||||||
elif fmt == '%F':
|
|
||||||
# The flair catch-all. Check for each individual flair
|
|
||||||
assert format_list[1][0](data) == expected_str['%f'] + ' '
|
|
||||||
format_list[1][1](data)
|
|
||||||
terminal.attr.assert_called_with(expected_attr['%f'])
|
|
||||||
terminal.attr.reset_mock()
|
|
||||||
|
|
||||||
assert format_list[2][0](data) == expected_str['%A'] + ' '
|
|
||||||
format_list[2][1](data)
|
|
||||||
terminal.attr.assert_called_with(expected_attr['%A'])
|
|
||||||
terminal.attr.reset_mock()
|
|
||||||
|
|
||||||
assert format_list[3][0](data) == expected_str['%h'] + ' '
|
|
||||||
format_list[3][1](data)
|
|
||||||
terminal.attr.assert_called_with(expected_attr['%h'])
|
|
||||||
terminal.attr.reset_mock()
|
|
||||||
|
|
||||||
assert format_list[4][0](data) == expected_str['%T'] + ' '
|
|
||||||
format_list[4][1](data)
|
|
||||||
terminal.attr.assert_called_with(expected_attr['%T'])
|
|
||||||
terminal.attr.reset_mock()
|
|
||||||
|
|
||||||
subreddit_page._gold_str.assert_called
|
|
||||||
|
|
||||||
assert format_list[6][0](data) == expected_str['%n'] + ' '
|
|
||||||
else:
|
|
||||||
# General case
|
|
||||||
assert format_list[1][0](data) == expected_str[fmt], \
|
|
||||||
"On specifier {0}".format(fmt)
|
|
||||||
format_list[1][1](data)
|
|
||||||
|
|
||||||
terminal.attr.assert_called_with(expected_attr[fmt])
|
|
||||||
terminal.attr.reset_mock()
|
|
||||||
|
|
||||||
|
|
||||||
def test_subreddit_page__draw_item_format(terminal, subreddit_page):
|
|
||||||
win = terminal.stdscr.subwin
|
win = terminal.stdscr.subwin
|
||||||
|
|
||||||
terminal.add_line = mock.Mock()
|
with mock.patch.object(terminal, 'add_line'):
|
||||||
terminal.add_space = mock.Mock()
|
# Loop through each individual format specifier and check for the desired behavior.
|
||||||
|
for fmt in filter(None, '%i %t %s %v %c %r %e %a %S %u %U %A %h %T %g %n %f %F'.split()):
|
||||||
|
subreddit_page.config['subreddit_format'] = fmt
|
||||||
|
subreddit_page._draw_item_format(win, data, 0, 0)
|
||||||
|
|
||||||
# Test proper handling of lambdas and not-lambdas
|
try:
|
||||||
subreddit_page.format = [(lambda data: "string", lambda data: None, False)]
|
if fmt == '%F':
|
||||||
subreddit_page._draw_item_format(win, None, None, 0)
|
|
||||||
|
|
||||||
terminal.add_line.assert_called_with(win, "string", 0, attr=None)
|
# Make sure each of the things that %F should print are printed
|
||||||
terminal.add_line.reset_mock()
|
# flair
|
||||||
|
terminal.add_line.assert_any_call(win, expected_str['%f'],
|
||||||
|
row=mock.ANY, col=mock.ANY,
|
||||||
|
attr=expected_attr['%f'])
|
||||||
|
|
||||||
subreddit_page.format = [("string", lambda data: None, False)]
|
# saved
|
||||||
subreddit_page._draw_item_format(win, None, None, 0)
|
terminal.add_line.assert_any_call(win, expected_str['%A'],
|
||||||
|
row=mock.ANY, col=mock.ANY,
|
||||||
|
attr=expected_attr['%A'])
|
||||||
|
|
||||||
terminal.add_line.assert_called_with(win, "string", 0, attr=None)
|
# hidden
|
||||||
terminal.add_line.reset_mock()
|
terminal.add_line.assert_any_call(win, expected_str['%h'],
|
||||||
|
row=mock.ANY, col=mock.ANY,
|
||||||
|
attr=expected_attr['%h'])
|
||||||
|
|
||||||
# Test newline handling, shouldn't be drawn
|
# stickied
|
||||||
subreddit_page.format = [("\n", lambda data: None, False)]
|
terminal.add_line.assert_any_call(win, expected_str['%T'],
|
||||||
subreddit_page._draw_item_format(win, None, None, 0)
|
row=mock.ANY, col=mock.ANY,
|
||||||
|
attr=expected_attr['%T'])
|
||||||
|
|
||||||
assert not terminal.add_line.called
|
# gold
|
||||||
terminal.add_line.reset_mock()
|
terminal.add_line.assert_any_call(win, expected_str['%g'],
|
||||||
|
row=mock.ANY, col=mock.ANY,
|
||||||
|
attr=expected_attr['%g'])
|
||||||
|
|
||||||
# add_line shouldn't be called if the string field is none
|
# nsfw
|
||||||
subreddit_page.format = [(None, lambda data: None, False)]
|
terminal.add_line.assert_any_call(win, expected_str['%n'],
|
||||||
subreddit_page._draw_item_format(win, None, None, 0)
|
row=mock.ANY, col=mock.ANY,
|
||||||
|
attr=expected_attr['%n'])
|
||||||
|
else:
|
||||||
|
terminal.add_line.assert_called_with(win, expected_str[fmt],
|
||||||
|
row=0, col=1,
|
||||||
|
attr=expected_attr[fmt])
|
||||||
|
except:
|
||||||
|
sys.stderr.write("Failed on {0}\n".format(fmt))
|
||||||
|
raise
|
||||||
|
|
||||||
assert not terminal.add_line.called
|
terminal.add_line.reset_mock()
|
||||||
|
|
||||||
# Check for newline handling and attribute reusing in the call of a null
|
# Ensure spaces aren't printed consecutively if data is absent
|
||||||
# attribute
|
data['gold'] = 0
|
||||||
subreddit_page.format = [("string", lambda data: terminal.attr("Link"), True),
|
subreddit_page.config['subreddit_format'] = ' %g '
|
||||||
("str", None, False)]
|
subreddit_page._draw_item_format(win, data, 0, 0)
|
||||||
subreddit_page._draw_item_format(win, None, None, 0)
|
|
||||||
|
|
||||||
# Should be called with a column of 1
|
assert terminal.add_line.call_count == 1
|
||||||
terminal.add_line.assert_any_call(win, "string", 0, 1,
|
|
||||||
attr=terminal.attr("Link"))
|
|
||||||
|
|
||||||
# "str" shouldn't be printed at the beginning of the line and it should be
|
terminal.add_line.reset_mock()
|
||||||
# printed with the same attribute as the previous item
|
|
||||||
terminal.add_line.assert_any_call(win, "str", 0,
|
|
||||||
attr=terminal.attr("Link"))
|
|
||||||
|
|
||||||
terminal.add_line.reset_mock()
|
# Test for correct handling of separators
|
||||||
|
subreddit_page.config['subreddit_format'] = ' | '
|
||||||
|
subreddit_page._draw_item_format(win, data, 0, 0)
|
||||||
|
|
||||||
# Check that spaces are printed with add_space and not add_line
|
# Should be called thrice - ' ', '|', ' '
|
||||||
subreddit_page.format = [(" ", lambda data: None, False)]
|
assert terminal.add_line.call_count == 3
|
||||||
subreddit_page._draw_item_format(win, None, None, 0)
|
|
||||||
|
|
||||||
assert terminal.add_space.called
|
|
||||||
assert not terminal.add_line.called
|
|
||||||
|
|||||||
@@ -116,6 +116,17 @@ def main():
|
|||||||
# Add an empty handler so the logger doesn't complain
|
# Add an empty handler so the logger doesn't complain
|
||||||
logging.root.addHandler(logging.NullHandler())
|
logging.root.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
if config['subreddit_format']:
|
||||||
|
# If the user has explicitly set a subreddit format, we don't want to
|
||||||
|
# try to do something else with the format so we fall out of the if now
|
||||||
|
pass
|
||||||
|
elif not config['look_and_feel'] or config['look_and_feel'] == 'default':
|
||||||
|
# FIXME - default needs its own subreddit_format but can't because
|
||||||
|
# no wrapped-title specifier exists
|
||||||
|
pass
|
||||||
|
elif config['look_and_feel'] == 'compact':
|
||||||
|
config['subreddit_format'] = config.COMPACT_FORMAT
|
||||||
|
|
||||||
# Make sure the locale is UTF-8 for unicode support
|
# Make sure the locale is UTF-8 for unicode support
|
||||||
default_locale = locale.setlocale(locale.LC_ALL, '')
|
default_locale = locale.setlocale(locale.LC_ALL, '')
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -42,11 +42,6 @@ class SubredditPage(Page):
|
|||||||
self.nav = Navigator(self.content.get)
|
self.nav = Navigator(self.content.get)
|
||||||
self.toggled_subreddit = None
|
self.toggled_subreddit = None
|
||||||
|
|
||||||
if self.config['subreddit_format']:
|
|
||||||
self.format = self._create_format(self.config['subreddit_format'])
|
|
||||||
elif self.config['look_and_feel'] == 'compact':
|
|
||||||
self.format = self._create_format(self.config.COMPACT_FORMAT)
|
|
||||||
|
|
||||||
def handle_selected_page(self):
|
def handle_selected_page(self):
|
||||||
"""
|
"""
|
||||||
Open all selected pages in subwindows except other subreddit pages.
|
Open all selected pages in subwindows except other subreddit pages.
|
||||||
@@ -274,187 +269,236 @@ class SubredditPage(Page):
|
|||||||
|
|
||||||
def _gold_str(self, data):
|
def _gold_str(self, data):
|
||||||
if data['gold'] > 1:
|
if data['gold'] > 1:
|
||||||
return self.term.gilded + 'x{} '.format(data['gold'])
|
return self.term.gilded + 'x{}'.format(data['gold'])
|
||||||
elif data['gold'] == 1:
|
elif data['gold'] == 1:
|
||||||
return self.term.gilded + ' '
|
return self.term.gilded
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def _create_format(self, format_string):
|
def _draw_item_format(self, win, data, valid_rows, offset):
|
||||||
"""
|
|
||||||
Returns a list of tuples of the format (datafield, attr, first) which
|
|
||||||
will be used by _draw_item to output information in the proper order.
|
|
||||||
It would be trivial to use the strings as simple format strings, but
|
|
||||||
more must be done in order to associate strings with their Attribute.
|
|
||||||
|
|
||||||
datafield = lambda that retrieves the proper field of the data
|
|
||||||
dict
|
|
||||||
|
|
||||||
attr = lambda that returns the proper attribute class associated with
|
|
||||||
datafield. Sometimes this isn't known until drawtime; see above
|
|
||||||
*_attr() functions for examples
|
|
||||||
|
|
||||||
first = boolean that signifies whether or not term.add_line should be
|
|
||||||
called with a col argument to start a line
|
|
||||||
"""
|
|
||||||
form = []
|
|
||||||
first = True
|
first = True
|
||||||
|
|
||||||
# Split the list between %., newlines, and separator characters to
|
# Split the list between %., newlines, and separator characters to
|
||||||
# treat them separately
|
# treat them separately
|
||||||
format_list = re.split(r'(%.|[\n' + re.escape(self.FORMAT_SEP) + '])', format_string, re.DOTALL)
|
format_list = re.split(r'(%.|[\n' + re.escape(self.FORMAT_SEP) + '])', self.config['subreddit_format'], re.DOTALL)
|
||||||
|
|
||||||
|
# Clean the list of null items. We don't need to join this list
|
||||||
|
# together again, so this is safe.
|
||||||
|
# https://stackoverflow.com/q/2197451
|
||||||
|
format_list = [item for item in format_list if item != '']
|
||||||
|
|
||||||
|
# Remember whether or not the last character printed was a space. If it
|
||||||
|
# was, printing more spaces should be avoided.
|
||||||
|
last_was_space = False
|
||||||
|
|
||||||
for item in format_list:
|
for item in format_list:
|
||||||
# Use lambdas because the actual data to be used is only known at
|
col = 1 if first else None
|
||||||
# drawtime. This way the format list knows how to use the data,
|
|
||||||
# and can simply be used when the data is available
|
# We don't want to print consecutive spaces, so check if a space
|
||||||
|
# was the last character printed, and skip this iteration if a
|
||||||
|
# space is to be printed
|
||||||
|
if last_was_space and item == ' ':
|
||||||
|
# coverage reports this as never executing, despite
|
||||||
|
# test_subreddit_page__draw_item_format testing for it, and pdb
|
||||||
|
# confirming the line is executed
|
||||||
|
continue
|
||||||
|
|
||||||
|
last_was_space = True
|
||||||
|
|
||||||
if item == "%i":
|
if item == "%i":
|
||||||
form.append((lambda data: str(data['index']),
|
self.term.add_line(win, str(data['index']),
|
||||||
lambda data: self._submission_attr(data), first))
|
row=offset, col=col,
|
||||||
|
attr=self._submission_attr(data))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%t":
|
elif item == "%t":
|
||||||
form.append((lambda data: data['title'],
|
self.term.add_line(win, data['title'],
|
||||||
lambda data: self._submission_attr(data), first))
|
row=offset, col=col,
|
||||||
|
attr=self._submission_attr(data))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%s":
|
elif item == "%s":
|
||||||
# Need to cut off the characters that aren't the score number
|
self.term.add_line(win, str(data['score']),
|
||||||
form.append((lambda data: str(data['score']),
|
row=offset, col=col,
|
||||||
lambda data: self.term.attr('Score'), first))
|
attr=self.term.attr('Score'))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%v":
|
elif item == "%v":
|
||||||
# This isn't great, self.term.get_arrow gets called twice
|
arrow = self.term.get_arrow(data['likes'])
|
||||||
form.append((lambda data: self.term.get_arrow(data['likes'])[0],
|
|
||||||
lambda data: self.term.get_arrow(data['likes'])[1], first))
|
self.term.add_line(win, arrow[0],
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=arrow[1])
|
||||||
|
last_was_space = False
|
||||||
elif item == "%c":
|
elif item == "%c":
|
||||||
form.append((
|
self.term.add_line(win, data['comments'],
|
||||||
lambda data: data['comments']
|
row=offset, col=col,
|
||||||
if data['comments'] else None, # Don't try to subscript null items
|
attr=self.term.attr('CommentCount'))
|
||||||
lambda data: self.term.attr('CommentCount'),
|
last_was_space = False
|
||||||
first))
|
|
||||||
elif item == "%r":
|
elif item == "%r":
|
||||||
form.append((lambda data: data['created'],
|
self.term.add_line(win, data['created'],
|
||||||
lambda data: self.term.attr('Created'), first))
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Created'))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%R":
|
elif item == "%R":
|
||||||
form.append((lambda data: data['created_exact'],
|
self.term.add_line(win, data['created_exact'],
|
||||||
lambda data: self.term.attr('Created'), first))
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Created'))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%e":
|
elif item == "%e":
|
||||||
form.append((lambda data: data['edited'],
|
self.term.add_line(win, data['edited'],
|
||||||
lambda data: self.term.attr('Created'), first))
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Created'))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%E":
|
elif item == "%E":
|
||||||
form.append((lambda data: data['edited_exact'],
|
self.term.add_line(win, data['edited_exact'],
|
||||||
lambda data: self.term.attr('Created'), first))
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Created'))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%a":
|
elif item == "%a":
|
||||||
form.append((lambda data: data['author'],
|
self.term.add_line(win, data['author'],
|
||||||
lambda data: self.term.attr('SubmissionAuthor'), first))
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('SubmissionAuthor'))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%S":
|
elif item == "%S":
|
||||||
form.append((lambda data: "/r/" + data['subreddit'],
|
self.term.add_line(win, "/r/" + data['subreddit'],
|
||||||
lambda data: self.term.attr('SubmissionSubreddit'),
|
row=offset, col=col,
|
||||||
first))
|
attr=self.term.attr('SubmissionSubreddit'))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%u":
|
elif item == "%u":
|
||||||
form.append((lambda data: self._url_str(data),
|
self.term.add_line(win, self._url_str(data),
|
||||||
lambda data: self._url_attr(data), first))
|
row=offset, col=col,
|
||||||
|
attr=self._url_attr(data))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%U":
|
elif item == "%U":
|
||||||
form.append((lambda data: data['url'],
|
self.term.add_line(win, data['url'],
|
||||||
lambda data: self._url_attr(data), first))
|
row=offset, col=col,
|
||||||
|
attr=self._url_attr(data))
|
||||||
|
last_was_space = False
|
||||||
elif item == "%A":
|
elif item == "%A":
|
||||||
form.append((lambda data: '[saved]' if data['saved'] else '',
|
if data['saved']:
|
||||||
lambda data: self.term.attr('Saved'), first))
|
self.term.add_line(win, '[saved]',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Saved'))
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
elif item == "%h":
|
elif item == "%h":
|
||||||
form.append((lambda data: '[hidden]' if data['hidden'] else '',
|
if data['hidden']:
|
||||||
lambda data: self.term.attr('Hidden'), first))
|
self.term.add_line(win, '[hidden]',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Hidden'))
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
elif item == "%T":
|
elif item == "%T":
|
||||||
form.append((lambda data: '[stickied]' if data['stickied'] else '',
|
if data['stickied']:
|
||||||
lambda data: self.term.attr('Stickied'), first))
|
self.term.add_line(win, '[stickied]',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Stickied'))
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
elif item == "%g":
|
elif item == "%g":
|
||||||
form.append((lambda data: self._gold_str(data),
|
if data['gold'] > 0:
|
||||||
lambda data: self.term.attr('Gold'), first))
|
self.term.add_line(win, self._gold_str(data),
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Gold'))
|
||||||
|
last_was_space = False
|
||||||
|
|
||||||
elif item == "%n":
|
elif item == "%n":
|
||||||
form.append((lambda data: 'NSFW' if data['nsfw'] else '',
|
if data['nsfw']:
|
||||||
lambda data: self.term.attr('NSFW'), first))
|
self.term.add_line(win, 'NSFW',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('NSFW'))
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
elif item == "%f":
|
elif item == "%f":
|
||||||
form.append((lambda data: data['flair'] if data['flair'] else '',
|
if data['flair']:
|
||||||
lambda data: self.term.attr('SubmissionFlair'), first))
|
self.term.add_line(win, data['flair'],
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('SubmissionFlair'))
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
elif item == "%F":
|
elif item == "%F":
|
||||||
form.append((lambda data: data['flair'] + ' ' if data['flair'] else '',
|
if data['flair']:
|
||||||
lambda data: self.term.attr('SubmissionFlair'), first))
|
self.term.add_line(win, data['flair'],
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('SubmissionFlair'))
|
||||||
|
|
||||||
form.append((lambda data: '[saved] ' if data['saved'] else '',
|
# These ugly if's write a space if necessary. It is
|
||||||
lambda data: self.term.attr('Saved'), first))
|
# necessary if there are more flairlike strings to write.
|
||||||
|
if (data['saved'] or data['hidden'] or
|
||||||
|
data['stickied'] or data['gold'] or
|
||||||
|
data['nsfw']):
|
||||||
|
self.term.add_space(win)
|
||||||
|
|
||||||
form.append((lambda data: '[hidden] ' if data['hidden'] else '',
|
last_was_space = False
|
||||||
lambda data: self.term.attr('Hidden'), first))
|
|
||||||
|
|
||||||
form.append((lambda data: '[stickied] ' if data['stickied'] else '',
|
if data['saved']:
|
||||||
lambda data: self.term.attr('Stickied'), first))
|
self.term.add_line(win, '[saved]',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Saved'))
|
||||||
|
|
||||||
form.append((lambda data: self._gold_str(data),
|
if (data['hidden'] or data['stickied'] or
|
||||||
lambda data: self.term.attr('Gold'), first))
|
data['gold'] or data['nsfw']):
|
||||||
|
self.term.add_space(win)
|
||||||
|
|
||||||
form.append((lambda data: 'NSFW ' if data['nsfw'] else '',
|
last_was_space = False
|
||||||
lambda data: self.term.attr('NSFW'), first))
|
|
||||||
|
if data['hidden']:
|
||||||
|
self.term.add_line(win, '[hidden]',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Hidden'))
|
||||||
|
|
||||||
|
if (data['stickied'] or data['gold'] or
|
||||||
|
data['nsfw']):
|
||||||
|
self.term.add_space(win)
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
|
|
||||||
|
if data['stickied']:
|
||||||
|
self.term.add_line(win, '[stickied]',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Stickied'))
|
||||||
|
|
||||||
|
if data['gold'] or data['nsfw']:
|
||||||
|
self.term.add_space(win)
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
|
|
||||||
|
if data['gold']:
|
||||||
|
self.term.add_line(win, self._gold_str(data),
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('Gold'))
|
||||||
|
|
||||||
|
if data['nsfw']:
|
||||||
|
self.term.add_space(win)
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
|
|
||||||
|
if data['nsfw']:
|
||||||
|
self.term.add_line(win, 'NSFW',
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=self.term.attr('NSFW'))
|
||||||
|
|
||||||
|
last_was_space = False
|
||||||
elif item == "\n":
|
elif item == "\n":
|
||||||
form.append((item, None, first))
|
|
||||||
first = True
|
first = True
|
||||||
|
offset += 1
|
||||||
|
|
||||||
continue
|
continue
|
||||||
else: # Write something else that isn't in the data dict
|
else: # Write something else that isn't in the data dict
|
||||||
# Make certain "separator" characters use the Separator
|
# Make certain "separator" characters use the Separator
|
||||||
# attribute
|
# attribute
|
||||||
if item in self.FORMAT_SEP:
|
if item in self.FORMAT_SEP:
|
||||||
form.append((item,
|
self.term.add_line(win, item,
|
||||||
lambda data: self.term.attr('Separator'),
|
row=offset, col=col,
|
||||||
first))
|
attr=self.term.attr('Separator'))
|
||||||
else:
|
else:
|
||||||
form.append((item, None, first))
|
self.term.add_line(win, item,
|
||||||
|
row=offset, col=col,
|
||||||
|
attr=None)
|
||||||
|
|
||||||
|
if item != ' ':
|
||||||
|
last_was_space = False
|
||||||
|
|
||||||
first = False
|
first = False
|
||||||
|
|
||||||
return form
|
|
||||||
|
|
||||||
def _draw_item_format(self, win, data, valid_rows, offset):
|
|
||||||
last_attr = None
|
|
||||||
for get_data, get_attr, first in self.format:
|
|
||||||
# add_line wants strings, make sure we give it strings
|
|
||||||
if callable(get_data):
|
|
||||||
print_data = get_data(data)
|
|
||||||
else:
|
|
||||||
# Start writing to the next line if we hit a newline
|
|
||||||
if get_data == "\n":
|
|
||||||
offset += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Otherwise, proceed on the same line
|
|
||||||
print_data = get_data
|
|
||||||
|
|
||||||
# Don't try to write None strings to the screen. This happens in
|
|
||||||
# places like user pages, where data['comments'] is None
|
|
||||||
if not print_data and first is False:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# We only want to print a maximum of one line of data,
|
|
||||||
# and we want to cast to a string, since sometimes 'data' is not a
|
|
||||||
# string, but a Redditor object
|
|
||||||
# TODO - support line wrapping
|
|
||||||
string = str(print_data).split('\n')[0]
|
|
||||||
|
|
||||||
if string == ' ':
|
|
||||||
# Make sure spaces aren't treated like normal strings and print
|
|
||||||
# them to the window this way. This ensures they won't be drawn
|
|
||||||
# with an attribute.
|
|
||||||
self.term.add_space(win)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# To make sure we don't try to write a None as an attribute,
|
|
||||||
# we can use the one that was last used
|
|
||||||
if get_attr is None:
|
|
||||||
attr = last_attr
|
|
||||||
else:
|
|
||||||
attr = get_attr(data)
|
|
||||||
|
|
||||||
if first:
|
|
||||||
self.term.add_line(win, string, offset, 1, attr=attr)
|
|
||||||
else:
|
|
||||||
self.term.add_line(win, string, offset, attr=attr)
|
|
||||||
|
|
||||||
last_attr = attr
|
|
||||||
|
|
||||||
def _draw_item_default(self, win, data, n_rows, n_cols, valid_rows, offset):
|
def _draw_item_default(self, win, data, n_rows, n_cols, valid_rows, offset):
|
||||||
"""
|
"""
|
||||||
Draw items with default look and feel
|
Draw items with default look and feel
|
||||||
@@ -554,8 +598,9 @@ class SubredditPage(Page):
|
|||||||
valid_rows = range(0, n_rows)
|
valid_rows = range(0, n_rows)
|
||||||
offset = 0 if not inverted else - (data['n_rows'] - n_rows)
|
offset = 0 if not inverted else - (data['n_rows'] - n_rows)
|
||||||
|
|
||||||
if self.config['look_and_feel'] == 'compact' or \
|
# FIXME - this assumes default doesn't have a subreddit_format. In the
|
||||||
self.config['subreddit_format']:
|
# future it should, and when it does it will break this if
|
||||||
|
if self.config['subreddit_format']:
|
||||||
self._draw_item_format(win, data, valid_rows, offset)
|
self._draw_item_format(win, data, valid_rows, offset)
|
||||||
else:
|
else:
|
||||||
self._draw_item_default(win, data, n_rows, n_cols, valid_rows, offset)
|
self._draw_item_default(win, data, n_rows, n_cols, valid_rows, offset)
|
||||||
|
|||||||
Reference in New Issue
Block a user