Skip to content

Commit c917b3e

Browse files
gh-65824: Add "Help on ..." to the "less" prompt in pydoc (GH-116183)
1 parent 438b7c3 commit c917b3e

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

Lib/pydoc.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,11 +1637,11 @@ def bold(self, text):
16371637

16381638
# --------------------------------------------------------- user interfaces
16391639

1640-
def pager(text):
1640+
def pager(text, title=''):
16411641
"""The first time this is called, determine what kind of pager to use."""
16421642
global pager
16431643
pager = getpager()
1644-
pager(text)
1644+
pager(text, title)
16451645

16461646
def getpager():
16471647
"""Decide what method to use for paging through text."""
@@ -1656,24 +1656,24 @@ def getpager():
16561656
use_pager = os.environ.get('MANPAGER') or os.environ.get('PAGER')
16571657
if use_pager:
16581658
if sys.platform == 'win32': # pipes completely broken in Windows
1659-
return lambda text: tempfilepager(plain(text), use_pager)
1659+
return lambda text, title='': tempfilepager(plain(text), use_pager)
16601660
elif os.environ.get('TERM') in ('dumb', 'emacs'):
1661-
return lambda text: pipepager(plain(text), use_pager)
1661+
return lambda text, title='': pipepager(plain(text), use_pager, title)
16621662
else:
1663-
return lambda text: pipepager(text, use_pager)
1663+
return lambda text, title='': pipepager(text, use_pager, title)
16641664
if os.environ.get('TERM') in ('dumb', 'emacs'):
16651665
return plainpager
16661666
if sys.platform == 'win32':
1667-
return lambda text: tempfilepager(plain(text), 'more <')
1667+
return lambda text, title='': tempfilepager(plain(text), 'more <')
16681668
if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
1669-
return lambda text: pipepager(text, 'less')
1669+
return lambda text, title='': pipepager(text, 'less', title)
16701670

16711671
import tempfile
16721672
(fd, filename) = tempfile.mkstemp()
16731673
os.close(fd)
16741674
try:
16751675
if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
1676-
return lambda text: pipepager(text, 'more')
1676+
return lambda text, title='': pipepager(text, 'more', title)
16771677
else:
16781678
return ttypager
16791679
finally:
@@ -1683,12 +1683,18 @@ def plain(text):
16831683
"""Remove boldface formatting from text."""
16841684
return re.sub('.\b', '', text)
16851685

1686-
def pipepager(text, cmd):
1686+
def escape_less(s):
1687+
return re.sub(r'([?:.%\\])', r'\\\1', s)
1688+
1689+
def pipepager(text, cmd, title=''):
16871690
"""Page through text by feeding it to another program."""
16881691
import subprocess
16891692
env = os.environ.copy()
1693+
if title:
1694+
title += ' '
1695+
esc_title = escape_less(title)
16901696
prompt_string = (
1691-
' '
1697+
f' {esc_title}' +
16921698
'?ltline %lt?L/%L.'
16931699
':byte %bB?s/%s.'
16941700
'.'
@@ -1716,7 +1722,7 @@ def pipepager(text, cmd):
17161722
# left running and the terminal is in raw mode and unusable.
17171723
pass
17181724

1719-
def tempfilepager(text, cmd):
1725+
def tempfilepager(text, cmd, title=''):
17201726
"""Page through text by invoking a program on a temporary file."""
17211727
import tempfile
17221728
with tempfile.TemporaryDirectory() as tempdir:
@@ -1733,7 +1739,7 @@ def _escape_stdout(text):
17331739
encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
17341740
return text.encode(encoding, 'backslashreplace').decode(encoding)
17351741

1736-
def ttypager(text):
1742+
def ttypager(text, title=''):
17371743
"""Page through text on a text terminal."""
17381744
lines = plain(_escape_stdout(text)).split('\n')
17391745
try:
@@ -1777,7 +1783,7 @@ def ttypager(text):
17771783
if tty:
17781784
tty.tcsetattr(fd, tty.TCSAFLUSH, old)
17791785

1780-
def plainpager(text):
1786+
def plainpager(text, title=''):
17811787
"""Simply print unformatted text. This is the ultimate fallback."""
17821788
sys.stdout.write(plain(_escape_stdout(text)))
17831789

@@ -1879,7 +1885,8 @@ def doc(thing, title='Python Library Documentation: %s', forceload=0,
18791885
"""Display text documentation, given an object or a path to an object."""
18801886
if output is None:
18811887
try:
1882-
pager(render_doc(thing, title, forceload))
1888+
what = thing if isinstance(thing, str) else type(thing).__name__
1889+
pager(render_doc(thing, title, forceload), f'Help on {what!s}')
18831890
except ImportError as exc:
18841891
if is_cli:
18851892
raise
@@ -2253,7 +2260,7 @@ def showtopic(self, topic, more_xrefs=''):
22532260
text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
22542261
wrapped_text = textwrap.wrap(text, 72)
22552262
doc += '\n%s\n' % '\n'.join(wrapped_text)
2256-
pager(doc)
2263+
pager(doc, f'Help on {topic!s}')
22572264

22582265
def _gettopic(self, topic, more_xrefs=''):
22592266
"""Return unbuffered tuple of (topic, xrefs).

0 commit comments

Comments
 (0)