Skip to content

Commit

Permalink
debugger: leave output screen with single key press
Browse files Browse the repository at this point in the history
Introduce support code for non-buffered console input (single key press
that doesn't accumulate input until ENTER is pressed). Support Windows
(msvcrt) and POSIX supporting Unix platforms (select and termios). Fall
back to the Python's input() routine for Webassembly and Emscripten.

Avoid the accumulation of repeated prompts on platforms that support
single key presses. Only the backwards compatible fallback on minor
platforms involves a prompt, so users can tell when they face that
situation.

The approach in this commit automatically detects platforms, no config
option is required. All depencencies are provided by Python core, there
are no external dependencies. The implementation is considered suitable
for future maintenance, extension, or adjustment for other platforms.
  • Loading branch information
gsigh committed Jan 18, 2025
1 parent f0b2aa5 commit 515ecc8
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 3 deletions.
11 changes: 8 additions & 3 deletions pudb/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

import urwid

from pudb.lowlevel import decode_lines, ui_log
from pudb.lowlevel import decode_lines, NonBufferedConsole, ui_log
from pudb.settings import get_save_config_path, load_config, save_config


Expand Down Expand Up @@ -769,10 +769,15 @@ def __init__(self, screen):

def __enter__(self):
self.screen.stop()
return self

def __exit__(self, exc_type, exc_value, exc_traceback):
self.screen.start()

def press_key_to_return(self):
with NonBufferedConsole() as nbc:
key = nbc.get_data()


class DebuggerUI(FrameVarInfoKeeper):
# {{{ constructor
Expand Down Expand Up @@ -2082,8 +2087,8 @@ def shrink_sidebar(w, size, key):
# {{{ top-level listeners

def show_output(w, size, key):
with StoppedScreen(self.screen):
input("Hit Enter to return:")
with StoppedScreen(self.screen) as s:
s.press_key_to_return()

def reload_breakpoints_and_redisplay():
reload_breakpoints()
Expand Down
69 changes: 69 additions & 0 deletions pudb/lowlevel.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,73 @@ def decode_lines(lines):

# }}}


# {{{ non-buffered console

# Local platform dependent helper to get single key presses from a
# terminal in unbuffered mode. Eliminates the necessity to press ENTER
# before other input also becomes available. Also avoids the accumulation
# of prompts on the screen as was the case with Python's input() call.
# Is used in situations where urwid is disabled and curses calls are
# not available.

_nbc_use_input = True
_nbc_use_getch = False
_nbc_use_select = False
if sys.platform in ("emscripten", "wasi"):
pass
elif sys.platform in ("win32",):
import msvcrt
_nbc_use_input = False
_nbc_use_getch = True
else:
import select
import termios
import tty
_nbc_use_input = False
_nbc_use_select = True


class NonBufferedConsole(object):

def __init__(self):
pass

def __enter__(self):
if _nbc_use_select:
self.prev_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
return self

def __exit__(self, type, value, traceback):
if _nbc_use_select:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.prev_settings)

def get_data(self):
if _nbc_use_getch:
c = msvcrt.getch()
if c in ('\x00', '\xe0'):
c = msvcrt.getch()
return c

if _nbc_use_select:
rset, _, _ = select.select([sys.stdin], [], [], None)
if sys.stdin in rset:
return sys.stdin.read(1)
return None

# Strictly speaking putting the fallback here which requires
# pressing ENTER is not correct, this is the "non buffered"
# console support code. But it simplifies call sites. And is
# easy to tell by users because a prompt is provided. This is
# the most portable approach, and backwards compatible with
# earlier PuDB releases. It's a most appropriate default for
# otherwise unsupported platforms. Or when users choose to
# not accept single key presses, or keys other than ENTER.
if _nbc_use_input:
input("Hit Enter to return:")
return None

# }}}

# vim: foldmethod=marker

0 comments on commit 515ecc8

Please sign in to comment.