[Jython-checkins] jython: Fixes paging for the help function on Windows
jim.baker
jython-checkins at python.org
Mon Jan 19 17:15:33 CET 2015
https://hg.python.org/jython/rev/6e8e76987965
changeset: 7538:6e8e76987965
user: Jim Baker <jim.baker at rackspace.com>
date: Mon Jan 19 09:15:00 2015 -0700
summary:
Fixes paging for the help function on Windows
On Windows, the text pager for the help function was not being
properly selected, due to os.name/os._name differences. However, even
if this OS testing is fixed, the use of subprocess to use the more
command to page was hanging.
Now uses a JLine2 specific pager if JLine2 is available that emulates
a subset of less functionality, namely paging backwards, otherwise a
plainpager (simply write lines to stdout).
Fixes http://bugs.jython.org/issue2209
files:
Lib/pydoc.py | 110 ++++++++++++++++++++++++++++++++++++--
1 files changed, 102 insertions(+), 8 deletions(-)
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -64,6 +64,8 @@
def popleft(self):
return self.pop(0)
+_is_windows = sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt')
+
# --------------------------------------------------------- common routines
def pathdirs():
@@ -598,7 +600,7 @@
try:
path = inspect.getabsfile(object)
url = path
- if sys.platform == 'win32':
+ if _is_windows:
import nturl2path
url = nturl2path.pathname2url(path)
filelink = '<a href="file:%s">%s</a>' % (url, path)
@@ -1328,6 +1330,14 @@
line += '\n' + self.indent(str(doc))
return line
+class AnsiDoc(TextDoc):
+ """Formatter class for ANSI texst documentation."""
+
+ def bold(self, text):
+ """Format a string in bold by overstriking."""
+ return "\x1b[1m" + text + "\x1b[0m"
+
+
# --------------------------------------------------------- user interfaces
def pager(text):
@@ -1336,14 +1346,95 @@
pager = getpager()
pager(text)
+
+class JLine2Pager(object):
+
+
+ @staticmethod
+ def available():
+ try:
+ sys._jy_console.reader
+ return True
+ except AttributeError:
+ return False
+
+ def __init__(self, lines):
+ self.data = lines.split("\n")
+ self.reader = sys._jy_console.reader
+ self.index = 0
+ ansi_codes = {
+ "bold": "\x1b[1m",
+ "negative": "\x1b[7m",
+ "normal": "\x1b[0m"
+ }
+ self.more_prompt_back = "--more-- space/{bold}b{normal}ack/{bold}q{normal}uit:".format(**ansi_codes)
+ self.more_prompt = "--more-- space/{bold}q{normal}uit:".format(**ansi_codes)
+ self.end_prompt_back = "{negative}(END){normal} {bold}b{normal}ack/{bold}q{normal}uit:".format(**ansi_codes)
+ self.end_prompt = "{negative}(END){normal} {bold}q{normal}uit:".format(**ansi_codes)
+
+ @property
+ def visible(self):
+ # The terminal may be resized at any time by the user,
+ # so check terminal.height on each iteration
+ return self.reader.terminal.height - 1
+
+ def handle_prompt(self):
+ can_go_back = self.index - self.visible > 0
+ if self.index == len(self.data):
+ if can_go_back:
+ self.reader.resetPromptLine(self.end_prompt_back, "", 0)
+ else:
+ self.reader.resetPromptLine(self.end_prompt, "", 0)
+ else:
+ if can_go_back:
+ self.reader.resetPromptLine(self.more_prompt_back, "", 0)
+ else:
+ self.reader.resetPromptLine(self.more_prompt, "", 0)
+ c = chr(self.reader.readCharacter())
+ self.reader.resetPromptLine("", "", 0)
+ if c == "q":
+ return "quit"
+ elif c == "b":
+ if not can_go_back:
+ return "reprompt"
+ self.index -= self.visible * 2
+ if self.index < 0:
+ self.index = 0
+ elif self.index != len(self.data):
+ return "forward"
+ else:
+ return "reprompt"
+
+ def page(self):
+ # TODO count wrapped lines with respect to terminal width by
+ # taking in account ANSI formatting codes
+ row_count = 0
+ while self.index < len(self.data):
+ line = self.data[self.index]
+ self.reader.print(line + "\n")
+ self.index += 1
+ row_count += 1
+ if row_count == self.visible or self.index == len(self.data):
+ while True:
+ action = self.handle_prompt()
+ if action == "quit":
+ return
+ elif action != "reprompt":
+ break
+ row_count = 0
+ self.reader.resetPromptLine("", "", 0)
+
+
def getpager():
"""Decide what method to use for paging through text."""
+ if _is_windows and JLine2Pager.available():
+ return lambda text: JLine2Pager(text).page()
if type(sys.stdout) is not types.FileType:
return plainpager
if not sys.stdin.isatty() or not sys.stdout.isatty():
return plainpager
if 'PAGER' in os.environ:
- if sys.platform == 'win32': # pipes completely broken in Windows
+ if _is_windows: # pipes completely broken in Windows
return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
elif os.environ.get('TERM') in ('dumb', 'emacs'):
return lambda text: pipepager(plain(text), os.environ['PAGER'])
@@ -1351,7 +1442,7 @@
return lambda text: pipepager(text, os.environ['PAGER'])
if os.environ.get('TERM') in ('dumb', 'emacs'):
return plainpager
- if sys.platform == 'win32' or sys.platform.startswith('os2'):
+ if _is_windows or sys.platform.startswith('os2'):
return lambda text: tempfilepager(plain(text), 'more <')
if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
return lambda text: pipepager(text, 'less')
@@ -1484,7 +1575,10 @@
# --------------------------------------- interactive interpreter interface
-text = TextDoc()
+if _is_windows and JLine2Pager.available():
+ text = AnsiDoc()
+else:
+ text = TextDoc()
html = HTMLDoc()
class _OldStyleClass: pass
@@ -2110,7 +2204,7 @@
self.search_ent.bind('<Return>', self.search)
self.stop_btn = Tkinter.Button(self.search_frm,
text='stop', pady=0, command=self.stop, state='disabled')
- if sys.platform == 'win32':
+ if _is_windows:
# Trying to hide and show this button crashes under Windows.
self.stop_btn.pack(side='right')
@@ -2126,7 +2220,7 @@
self.search_frm.pack(side='top', fill='x')
self.search_ent.focus_set()
- font = ('helvetica', sys.platform == 'win32' and 8 or 10)
+ font = ('helvetica', _is_windows and 8 or 10)
self.result_lst = Tkinter.Listbox(window, font=font, height=6)
self.result_lst.bind('<Button-1>', self.select)
self.result_lst.bind('<Double-Button-1>', self.goto)
@@ -2172,7 +2266,7 @@
import webbrowser
webbrowser.open(url)
except ImportError: # pre-webbrowser.py compatibility
- if sys.platform == 'win32':
+ if _is_windows:
os.system('start "%s"' % url)
else:
rc = os.system('netscape -remote "openURL(%s)" &' % url)
@@ -2217,7 +2311,7 @@
self.search_lbl.config(text='Search for')
self.search_lbl.pack(side='left')
self.search_ent.pack(side='right', fill='x', expand=1)
- if sys.platform != 'win32': self.stop_btn.forget()
+ if not _is_windows: self.stop_btn.forget()
self.stop_btn.config(state='disabled')
def select(self, event=None):
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list