python - 在 ipython 5.0+ 中按 Ctrl-C 时在屏幕上留下不完整的行

标签 python ipython keyboard-shortcuts keyboardinterrupt prompt-toolkit

在 IPython 的旧版本(我相信是 5.0 之前)中,如果我正在处理一行/ block ,并且突然发现我需要调查其他东西来完成它,我的方法是按 Ctrl-C,这就离开了屏幕上不完整的行/ block ,但未执行,并给了我一个新的提示。也就是说,我会看到类似这样的内容:

In [1]: def foo():
   ...:     stuff^C  # <-- Just realized I needed to check something on stuff usage

In [2]:    # <-- cursor goes to new line, but old stuff still on terminal

在较新的 IPython 中(似乎已经从 readline 切换到 prompt_toolkit 作为“CLI 支持框架”),Ctrl-C 的行为有所不同;现在,它不再给我换行符,而是重置当前换行符,丢弃我输入的所有内容并将光标返回到行首。

# Before:
In [1]: def foo():
   ...:     stuff

# After Ctrl-C:
In [1]:   # Hey, where'd everything go?

这非常烦人,因为我无法再看到或复制/粘贴我正在处理的代码,以便在我完成任何需要新提示的副任务后继续我的工作。

我的问题是:有什么方法可以恢复旧的 IPython 行为,其中 Ctrl-C 执行以下操作:

  1. 不执行目前输入的行/ block
  2. 留在屏幕上
  3. 能够选择(在配置时很好)是否添加到历史记录中(这将是个人偏好;你想要历史中的半成型的东西,还是只在终端上复制/粘贴?)<
  4. 在目前输入的文本下方为我提供新的提示

我到处搜索,找到最多的是a bug report comment提到这个新行为作为“......对早期 IPython 版本的改变,但它是有意的。”

我无法在 IPython 或 prompt_toolkit 文档中找到任何关于修改行为的文档;我已经找到了很多这些处理程序的安装位置,但是试图通过猴子修补来改变当前行为的尝试失败了(坦率地说,猴子修补未记录的代码意味着我冒着破坏每次升级的风险,所以我想找到对此有一些半支持的修复;如果失败,hacky monkey-patching 是可以接受的)。

最佳答案

经过更多研究,我发现了一种似乎受支持的方法,它依赖于 IPython keyboard shortcuts 文档(5.x6.x 的文档略有不同)。

解决方案是在~/.ipython/profile_default/startup中创建一个文件(任意名称,以.pyipy结尾很好,例如 fixctrlc.py),并添加以下内容:

def fix_ctrlc():
    '''Set up bindings so IPython 5.0+ responds to Ctrl-C as in pre-5.0

    Specific behavior is to have Ctrl-C leave existing typed command on
    screen and preserved in history. Easily modified to not put in history.

    Since this is run as a startup script, all work, including imports,
    is done in this function to avoid polluting global namespace.

    Updates made as needed at https://stackoverflow.com/a/45600868/364696
    '''
    from IPython import get_ipython
    from prompt_toolkit.enums import DEFAULT_BUFFER
    from prompt_toolkit.keys import Keys
    from prompt_toolkit.filters import HasFocus, ViInsertMode, EmacsInsertMode

    ip = get_ipython()

    # Determine if we're on a version of IPython that needs a fix,
    # acquire the key bindings registry from the appropriate location,
    # and establish closure state appropriate to that version of IPython
    try:
        try:
            # IPython 5-6; render_as_done doesn't exist, but manual print works
            registry = ip.pt_cli.application.key_bindings_registry
            redraw_args = {}
            doprint = True
        except AttributeError:
            # IPython 7+ (tested through 8.0.1)
            # render_as_done necessary, and removes need for print
            registry = ip.pt_app.key_bindings
            redraw_args = {'render_as_done': True}
            doprint = False
    except AttributeError:
        # On an old version of IPython that doesn't need the fix, or
        # a new version that changed the registry location. Nothing to do.
        return

    def on_ctrlc(event):
        text = event.cli.current_buffer.text.rstrip()
        if text:
            # Update cursor position to last non-space char in buffer (so Ctrl-C
            # with cursor in middle of block doesn't lose text typed after cursor)
            event.cli.current_buffer.cursor_position = len(text)
            event.cli.current_buffer.text = text

            # Redraw so cursor in correct position before print
            event.cli._redraw(**redraw_args)

            # (Optional) Put non-empty partial commands in history, not just left on screen
            # Delete to leave them on screen, but not in history
            event.cli.current_buffer.append_to_history()

            # Print a newline to move us past currently typed text so it's not
            # replaced on redraw
            if doprint:
                print()

            # Reset/redraw prompt
            event.cli.reset()

        # Clear active buffer, leaving you with fresh, empty prompt
        event.cli.current_buffer.reset()

    registry.add_binding(
            Keys.ControlC,
            filter=(HasFocus(DEFAULT_BUFFER) & (ViInsertMode() | EmacsInsertMode()))
            )(on_ctrlc)


fix_ctrlc()
del fix_ctrlc  # Avoid polluting global namespace

如果您找到更好的解决方案,请随时贡献力量。

关于python - 在 ipython 5.0+ 中按 Ctrl-C 时在屏幕上留下不完整的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45599850/

相关文章:

python - 替换数据框中的值

python - 在没有 sudo 权限的 Linux 系统上安装 Python TA-lib 包时出错

python - 如何在 *nix 下的 ipython 中使用 vi 键?

html - 从 'file' 菜单将 IPython 2.0 notebook 转换为 html

javascript - iPython/Jupyter 笔记本 : How to Embed Interactive Graph Using Desmos API?

macos - OS X 终端快捷方式 : Jump to beginning/end of line

Xcode 键盘快捷键直接跳转到主编辑器窗口?

Python3 : How to store information from short script in a CSV file?

python - 在 Python 中快速关闭系统

powershell - 退出 Powershell 的键盘快捷键