prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.1k stars 717 forks source link

Terminal left in broken state after exit when binding ctrl-c #1820

Open olejorgenb opened 7 months ago

olejorgenb commented 7 months ago
import sys
import prompt_toolkit

from prompt_toolkit.key_binding import KeyBindings

def main():
    bindings = KeyBindings()

    @bindings.add("c-c")
    def _(event):
        sys.exit()

    session = prompt_toolkit.PromptSession(key_bindings=bindings)

    while True:
        line = session.prompt("> ")

if __name__ == '__main__':
    main()

After pressing ctrl-c, the terminal is no longer processing ctr-c (a literal ^C is inserted).

Version: 3.0.36 Terminals tested: Tilix, gnome-terminal

joouha commented 5 months ago

The default prompt-session includes a key-binding for Ctrl-c which exits the current application with a KeyboardInterrupt exception, like this:

import prompt_toolkit
from prompt_toolkit.key_binding import KeyBindings

def main():
    bindings = KeyBindings()

    @bindings.add("c-c")
    def _keyboard_interrupt(event):
        """Abort when Control-C has been pressed."""
        event.app.exit(exception=KeyboardInterrupt, style="class:aborting")

    session = prompt_toolkit.PromptSession(key_bindings=bindings)

    while True:
        try:
            line = session.prompt("> ")
        except KeyboardInterrupt:
            break

if __name__ == "__main__":
    main()

Using Application.exit instead of sys.exit will allow the application renderer to restore the terminal state when it exits.

olejorgenb commented 5 months ago

Ah, I thought the reason I bound ctrl-c was that it wasn't bound by the default bindings to exit, but maybe I mixed up. (Maybe there downsides to this, but it is possible to handle sys.exit as well by catching the SystemExit exception)

Feel free to close this issue then.