Merge pull request #200 from michael-lazar/pager

Pager
This commit is contained in:
Michael Lazar
2016-03-03 22:45:20 -08:00
12 changed files with 307 additions and 26 deletions

View File

@@ -57,5 +57,6 @@ Submission Mode
In submission mode you can view the self text for a submission and browse comments.
:``h`` or ``◄``: Return to the subreddit
:``l`` or ``►``: Open the selected comment in a new window
:``o`` or ``ENTER``: Open the comment permalink with your web browser
:``SPACE``: Fold the selected comment, or load additional comments

View File

@@ -155,6 +155,28 @@ How do I run the repository code directly?
$ cd ~/rtv_project
$ python3 -m rtv
How do I run the tests?
This project uses `pytest <http://pytest.org/>`_ and `VCR.py <https://vcrpy.readthedocs.org/>`_.
.. code-block:: bash
$ pip3 install pytest
$ # The pip release for VCR.py is out-of-date
$ pip3 install git+https://github.com/kevin1024/vcrpy.git
$ cd ~/rtv_project
$ # Run the full suite
$ PYTHONPATH=. py.test
$ # or a single test
$ PYTHONPATH=. py.test tests/test_config.py::test_copy_default_config
VCR.py will record HTTP requests made during the test run and store
them in *tests/cassettes/*. By default these cassettes are read-only,
if you would like to record new cassettes you must provide your own refresh token.
.. code-block:: bash
$ PYTHONPATH=. py.test --record-mode=once --refresh-token=~/.config/rtv/refresh-token
=========
Changelog
=========

View File

@@ -17,7 +17,7 @@ Press `?` to open the help screen.
"""
HELP = """
Basic Commands
[Basic Commands]
`j/k` or `UP/DOWN` : Move the cursor up/down
`m/n` or `PgUp/PgDn`: Jump to the previous/next page
`o` or `ENTER` : Open the selected item as a webpage
@@ -27,7 +27,7 @@ Basic Commands
`?` : Show the help screen
`q/Q` : Quit/Force quit
Authenticated Commands
[Authenticated Commands]
`a/z` : Upvote/downvote
`c` : Compose a new post or comment
`e` : Edit an existing post or comment
@@ -35,13 +35,14 @@ Authenticated Commands
`i` : Display new messages prompt
`s` : Open/close subscribed subreddits list
Subreddit Mode
[Subreddit Mode]
`l` or `RIGHT` : Enter the selected submission
`/` : Open a prompt to switch subreddits
`f` : Open a prompt to search the current subreddit
Submission Mode
[Submission Mode]
`h` or `LEFT` : Return to subreddit mode
`l` or `RIGHT` : Open the selected comment in a new window
`SPACE` : Fold the selected comment, or load additional comments
"""

View File

@@ -79,7 +79,7 @@ class Page(object):
@PageController.register(Command('HELP'))
def show_help(self):
self.term.show_notification(docs.HELP.strip().splitlines())
self.term.show_notification(docs.HELP.strip('\n').splitlines())
@PageController.register(Command('SORT_HOT'))
def sort_content_hot(self):

View File

@@ -104,10 +104,11 @@ INBOX = i
REFRESH = r, <KEY_F5>
; Submission page
SUBMISSION_TOGGLE_COMMENT = l, 0x20, <KEY_RIGHT>
SUBMISSION_TOGGLE_COMMENT = 0x20
SUBMISSION_OPEN_IN_BROWSER = o, <LF>, <KEY_ENTER>
SUBMISSION_POST = c
SUBMISSION_EXIT = h, <KEY_LEFT>
SUBMISSION_OPEN_IN_PAGER = l, <KEY_RIGHT>
; Subreddit page
SUBREDDIT_SEARCH = f

View File

@@ -69,6 +69,19 @@ class SubmissionPage(Page):
else:
self.term.flash()
@SubmissionController.register(Command('SUBMISSION_OPEN_IN_PAGER'))
def open_pager(self):
"Open the selected item with the system's pager"
data = self.content.get(self.nav.absolute_index)
if data['type'] == 'Submission':
text = '\n\n'.join((data['permalink'], data['text']))
self.term.open_pager(text)
elif data['type'] == 'Comment':
text = '\n\n'.join((data['permalink'], data['body']))
self.term.open_pager(text)
else:
self.term.flash()
@SubmissionController.register(Command('SUBMISSION_POST'))
@logged_in
def add_comment(self):

View File

@@ -35,6 +35,7 @@ class Terminal(object):
# ASCII code
ESCAPE = 27
RETURN = 10
SPACE = 32
def __init__(self, stdscr, ascii=False):
@@ -356,6 +357,26 @@ class Terminal(object):
with self.suspend():
webbrowser.open_new_tab(url)
def open_pager(self, data):
"""
View a long block of text using the system's default pager.
The data string will be piped directly to the pager.
"""
pager = os.getenv('PAGER') or 'less'
try:
with self.suspend():
p = subprocess.Popen([pager], stdin=subprocess.PIPE)
p.stdin.write(self.clean(data))
p.stdin.close()
try:
p.wait()
except KeyboardInterrupt:
p.terminate()
except OSError:
self.show_notification('Could not open pager %s' % pager)
def open_editor(self, data=''):
"""
Open a temporary file using the system's default editor.
@@ -366,16 +387,19 @@ class Terminal(object):
"""
with NamedTemporaryFile(prefix='rtv-', suffix='.txt', mode='wb') as fp:
fp.write(codecs.encode(data, 'utf-8'))
fp.write(self.clean(data))
fp.flush()
editor = os.getenv('RTV_EDITOR') or os.getenv('EDITOR') or 'nano'
try:
with self.suspend():
subprocess.Popen([editor, fp.name]).wait()
p = subprocess.Popen([editor, fp.name])
try:
p.wait()
except KeyboardInterrupt:
p.terminate()
except OSError:
raise exceptions.ProgramError(
'Could not open file with %s' % editor)
self.show_notification('Could not open file with %s' % editor)
# Open a second file object to read. This appears to be necessary
# in order to read the changes made by some editors (gedit). w+

View File

@@ -25,13 +25,13 @@ for future sessions. You can disable this behavior by setting the option
.SH ENVIRONMENT
.TP
.BR RTV_EDITOR
Specifies which text editor RTV will attempt to use when editing comments and
posts. RTV will fallback to \fI$EDITOR\fR if the editor is unspecified.
Text editor to use when editing comments and submissions. Will fallback to
\fI$EDITOR\fR.
.TP
.BR BROWSER
Specifies which webbrowser RTV will attempt to use when opening links.
This can be set to a terminal browser (w3m, lynx, elinks, etc.) for a true
terminal experience. RTV will fallback to the system's default browser.
Web browser to use when opening links.
.BR PAGER
Pager to use when expanding individual comments and submissions.
.SH AUTHOR
Michael Lazar <lazar.michael22@gmail.com> (2016).
.SH BUGS

View File

@@ -0,0 +1,179 @@
interactions:
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Connection: [keep-alive]
User-Agent: [rtv test suite PRAW/3.3.0 Python/3.4.0 b'Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty']
method: GET
uri: https://www.reddit.com/r/Python/comments/2xmo63.json
response:
body:
string: !!binary |
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
headers:
CF-RAY: [27e2870df58d0701-SJC]
Connection: [keep-alive]
Content-Encoding: [gzip]
Content-Length: ['7681']
Content-Type: [application/json; charset=UTF-8]
Date: ['Fri, 04 Mar 2016 04:19:01 GMT']
Server: [cloudflare-nginx]
Set-Cookie: ['__cfduid=d74b0638b5cdf1ae3e52258dd917f74761457065141; expires=Sat,
04-Mar-17 04:19:01 GMT; path=/; domain=.reddit.com; HttpOnly', 'loid=FIHszkGB7O46d84R4x;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sun, 04-Mar-2018 04:19:01
GMT; secure', 'loidcreated=2016-03-04T04%3A19%3A01.483Z; Domain=reddit.com;
Max-Age=63071999; Path=/; expires=Sun, 04-Mar-2018 04:19:01 GMT; secure']
Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload]
Vary: [accept-encoding]
X-Moose: [majestic]
access-control-allow-origin: ['*']
access-control-expose-headers: ['X-Reddit-Tracking, X-Moose']
cache-control: ['max-age=0, must-revalidate']
set-cookie: ['__cfduid=d74b0638b5cdf1ae3e52258dd917f74761457065141; expires=Sat,
04-Mar-17 04:19:01 GMT; path=/; domain=.reddit.com; HttpOnly', 'loid=FIHszkGB7O46d84R4x;
Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sun, 04-Mar-2018 04:19:01
GMT; secure', 'loidcreated=2016-03-04T04%3A19%3A01.483Z; Domain=reddit.com;
Max-Age=63071999; Path=/; expires=Sun, 04-Mar-2018 04:19:01 GMT; secure']
x-content-type-options: [nosniff]
x-frame-options: [SAMEORIGIN]
x-reddit-tracking: ['https://pixel.redditmedia.com/pixel/of_destiny.png?v=WFLujq0%2BidDL%2F5%2FEeUPNp5nimP4wqGpVG5FP8Mx8Jg0%2Bh%2FCnbI6mePESqBT0oQ36bwCzJoaTgDU%3D']
x-ua-compatible: [IE=edge]
x-xss-protection: [1; mode=block]
status: {code: 200, message: OK}
version: 1

View File

@@ -72,7 +72,7 @@ def test_page_unauthenticated(reddit, terminal, config, oauth):
# Show help
page.controller.trigger('?')
message = 'Basic Commands'.encode('utf-8')
message = '[Basic Commands]'.encode('utf-8')
terminal.stdscr.subwin.addstr.assert_any_call(1, 1, message)
# Sort content

View File

@@ -94,6 +94,23 @@ def test_submission_open(submission_page, terminal):
assert terminal.open_browser.called
def test_submission_pager(submission_page, terminal):
# View a submission with the pager
with mock.patch.object(terminal, 'open_pager'):
submission_page.controller.trigger('l')
assert terminal.open_pager.called
# Move down to the first comment
with mock.patch.object(submission_page, 'clear_input_queue'):
submission_page.controller.trigger('j')
# View a comment with the pager
with mock.patch.object(terminal, 'open_pager'):
submission_page.controller.trigger('l')
assert terminal.open_pager.called
def test_submission_vote(submission_page, refresh_token):
# Log in

View File

@@ -309,3 +309,26 @@ def test_open_browser(terminal):
open_new_tab.assert_called_with(url)
assert curses.endwin.called
assert curses.doupdate.called
def test_open_pager(terminal, stdscr):
data = "Hello World!"
def side_effect(args, stdin=None):
assert stdin is not None
raise OSError
with mock.patch('subprocess.Popen', autospec=True) as Popen, \
mock.patch.dict('os.environ', {'PAGER': 'fake'}):
Popen.return_value.stdin = mock.Mock()
terminal.open_pager(data)
assert Popen.called
assert not stdscr.addstr.called
# Raise an OS error
Popen.side_effect = side_effect
terminal.open_pager(data)
message = 'Could not open pager fake'.encode('ascii')
assert stdscr.addstr.called_with(0, 0, message)