X Tutup
Skip to content

Commit 5929cc3

Browse files
committed
implemented help() using pydoc.Helper and external pager
1 parent 6abbd06 commit 5929cc3

File tree

3 files changed

+69
-100
lines changed

3 files changed

+69
-100
lines changed

bpython/_internal.py

Lines changed: 12 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,24 @@
11
import pydoc
2-
import textwrap
32
import sys
4-
import cStringIO
53

6-
# window has to be a global so that the main bpython.py can load it and
7-
# alter its state and share it with the interpreter being used for the
8-
# actual user input, I couldn't think of another way of doing this.
9-
window = None
4+
from bpython.pager import page
105

6+
# Ugly monkeypatching
7+
pydoc.pager = page
118

12-
def _help(obj):
13-
"""Wrapper for the regular help() function but with a ghetto
14-
PAGER since curses + less = :(
15-
As per the vanilla help(), this function special-cases for str,
16-
so you can do help('isinstance') or help(isinstance) and get the
17-
same result.
18-
"""
19-
io = cStringIO.StringIO()
20-
doc = pydoc.TextDoc()
21-
helper = pydoc.Helper(None, io)
229

23-
rows, columns = window.getmaxyx()
24-
rows -= 3
25-
columns -= 1
26-
output = None
10+
class _Helper(object):
11+
def __init__(self):
12+
self.helper = pydoc.Helper(sys.stdin, sys.stdout)
2713

28-
# Copied and pasted from Lib/pydoc.py and fiddled with
29-
# so it works fine with bpython. As far as I can tell
30-
# the bpython help is no compliant with the vanilla help.
31-
# Please let me know if you find this to be untrue.
32-
if type(obj) is type(''):
33-
if obj == 'help':
34-
helper.intro()
35-
elif obj == 'keywords':
36-
helper.listkeywords()
37-
elif obj == 'topics':
38-
helper.listtopics()
39-
elif obj == 'modules':
40-
helper.listmodules()
41-
elif obj[:8] == 'modules ':
42-
helper.listmodules(split(obj)[1])
43-
elif obj in helper.keywords:
44-
helper.showtopic(obj)
45-
elif obj in helper.topics:
46-
helper.showtopic(obj)
47-
elif obj:
48-
output = doc.document(eval(obj))
49-
#######################
14+
def __repr__(self):
15+
return ("Type help() for interactive help, "
16+
"or help(object) for help about object.")
5017

51-
else:
52-
output = doc.document(obj)
53-
if not output:
54-
output = "No help found for %s" % (obj, )
55-
return
18+
def __call__(self, *args, **kwargs):
19+
self.helper(*args, **kwargs)
5620

57-
if output is None:
58-
output = io.getvalue()
59-
io.close()
21+
_help = _Helper()
6022

61-
if not output:
62-
return
63-
64-
output = output.replace('\t', ' ')
65-
66-
if '\n' in output:
67-
output = output.replace('\n\n', '\n')
68-
output = output.split('\n')
69-
else:
70-
output = [output]
71-
72-
paragraphs = []
73-
for o in output:
74-
paragraphs.append(textwrap.wrap(o, columns))
75-
76-
i = 0
77-
for j, paragraph in enumerate(paragraphs):
78-
for line in paragraph:
79-
sys.stdout.write(line + '\n')
80-
i += 1
81-
# This is a little unclear, but it just waits for a
82-
# keypress when the a page worth of text has been
83-
# displayed and returns if 'q' is pressed:
84-
if not i % rows and not wait_for_key():
85-
return
86-
87-
88-
def wait_for_key():
89-
"""Block until a key is pressed for the ghetto paging."""
90-
91-
q = True
92-
window.addstr("Press any key, q to cancel.")
93-
while True:
94-
c = window.getch()
95-
if c and c == ord('q'):
96-
q = False
97-
if c:
98-
break
99-
clear_line()
100-
return q
101-
102-
103-
def clear_line():
104-
y = window.getyx()[0]
105-
window.move(y, 0)
106-
window.clrtoeol()
10723

10824
# vim: sw=4 ts=4 sts=4 ai et

bpython/cli.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -997,10 +997,8 @@ def repl(self):
997997
f.close()
998998
self.interp.runcode(code_obj)
999999

1000-
# The regular help() function uses PAGER to display the help, which
1001-
# screws with bpython.
1002-
from bpython import _internal
1003-
_internal.window = self.scr
1000+
# Use our own helper function because Python's will use real stdin and
1001+
# stdout instead of our wrapped
10041002
self.push('from bpython import _internal\n')
10051003
self.push('help = _internal._help')
10061004

bpython/pager.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# The MIT License
2+
#
3+
# Copyright (c) 2009 Andreas Stuehrk
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
# THE SOFTWARE.
22+
23+
24+
import curses
25+
import errno
26+
import os
27+
import subprocess
28+
import sys
29+
30+
31+
def get_pager_command():
32+
command = os.environ.get('PAGER')
33+
return command
34+
35+
36+
def page_internal(data):
37+
"""A more than dumb pager function."""
38+
sys.stdout.write(data)
39+
40+
41+
def page(data, use_internal=False):
42+
command = get_pager_command()
43+
if not command or use_internal:
44+
page_internal(data)
45+
else:
46+
curses.endwin()
47+
popen = subprocess.Popen([command], stdin=subprocess.PIPE)
48+
try:
49+
popen.stdin.write(data)
50+
popen.stdin.close()
51+
except OSError, e:
52+
if e.errno != errno.EPIPE:
53+
raise
54+
popen.wait()
55+
curses.doupdate()

0 commit comments

Comments
 (0)
X Tutup