Оставьте неполную строку на экране при нажатии Ctrl-C в ipython 5.0+
В более старых (я полагаю, до 5.0) версиях IPython, если я работал над строкой / блоком и вдруг обнаружил, что мне нужно исследовать что-то еще, чтобы закончить его, мой подход заключался в нажатии Ctrl-C, что оставляло неполную строку / блок на экране, но не выполнен, и дал мне свежий запрос. То есть я бы увидел что-то вроде:
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 делает следующие вещи:
- Не выполняет введенную строку / блок
- Оставляет его на экране
- Возможность выбора (во время конфигурирования в порядке), добавлять ли в историю (это было бы личным предпочтением; хотите ли вы наполовину сформированные вещи в истории или просто на терминале для копирования / вставки?)
- Предоставляет мне свежую подсказку под текстом, набранным до сих пор
Я искал повсюду, и самое большое, что я нашел, это комментарий к сообщению об ошибке, который упоминает об этом новом поведении как "... изменение по сравнению с более ранними версиями IPython, но оно сделано намеренно".
Я не смог найти ничего задокументированного об изменении поведения в IPython или prompt_toolkit
документация; Я обнаружил, где установлены многие из этих обработчиков, но попытки обезьянок-патчей изменить текущее поведение потерпели неудачу (и, честно говоря, патчи-обезвреживания недокументированного кода означают, что я рискую нарушить каждое обновление, поэтому я хотел бы найти некоторые частично поддерживаемые исправления для этого; если это не так, то хакерские исправления для обезьян допустимы).
1 ответ
И после дальнейших исследований я обнаружил, что кажется поддерживаемым подходом, опираясь на документацию по сочетаниям клавиш IPython (документированную немного по-разному для 5.x и 6.x).
Решение состоит в том, чтобы создать файл в ~/.ipython/profile_default/startup
(любое имя, заканчивающееся на .py
или же ipy
хорошо, например fixctrlc.py
) и добавьте следующее:
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
def on_ctrlc(event):
# Move cursor to end of line and redraw (so whole block is preserved)
event.cli.current_buffer.cursor_position = len(event.cli.current_buffer.text)
event.cli._redraw(**redraw_args)
# (Optional) Put non-empty partial commands in history
if event.cli.current_buffer.text.strip():
event.cli.current_buffer.append_to_history()
if doprint:
print() # Skip to next line past cursor
event.cli.reset() # Reset/redraw prompt
event.cli.current_buffer.reset() # Clear buffer so new line is fresh (empty)
ip = get_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+; 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:
pass # Old IPython doesn't need special handler
else:
registry.add_binding(Keys.ControlC,
filter=(HasFocus(DEFAULT_BUFFER) & (ViInsertMode() | EmacsInsertMode()))
)(on_ctrlc)
Пожалуйста, не стесняйтесь вносить свой вклад, если вы найдете лучшее решение.