# Written by Sebastian Pipping # Licensed under CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/) # 2015-05-22 16:51 UTC+2 from __future__ import print_function import readline import sys from ctypes import CDLL, c_int from ctypes.util import find_library if sys.version_info[0] > 2: raw_input = input _rl_state_flags = { # 'RL_STATE_INITIALIZING': 0x0000001, # initializing 'RL_STATE_INITIALIZED': 0x0000002, # initialization done 'RL_STATE_TERMPREPPED': 0x0000004, # terminal is prepped 'RL_STATE_READCMD': 0x0000008, # reading a command key 'RL_STATE_METANEXT': 0x0000010, # reading input after ESC 'RL_STATE_DISPATCHING': 0x0000020, # dispatching to a command 'RL_STATE_MOREINPUT': 0x0000040, # reading more input in a command function 'RL_STATE_ISEARCH': 0x0000080, # doing incremental search 'RL_STATE_NSEARCH': 0x0000100, # doing non-inc search 'RL_STATE_SEARCH': 0x0000200, # doing a history search 'RL_STATE_NUMERICARG': 0x0000400, # reading numeric argument 'RL_STATE_MACROINPUT': 0x0000800, # getting input from a macro 'RL_STATE_MACRODEF': 0x0001000, # defining keyboard macro 'RL_STATE_OVERWRITE': 0x0002000, # overwrite mode 'RL_STATE_COMPLETING': 0x0004000, # doing completion 'RL_STATE_SIGHANDLER': 0x0008000, # in readline sighandler 'RL_STATE_UNDOING': 0x0010000, # doing an undo 'RL_STATE_INPUTPENDING': 0x0020000, # rl_execute_next called 'RL_STATE_TTYCSAVED': 0x0040000, # tty special chars saved 'RL_STATE_CALLBACK': 0x0080000, # using the callback interface 'RL_STATE_VIMOTION': 0x0100000, # reading vi motion arg 'RL_STATE_MULTIKEY': 0x0200000, # reading multiple-key command 'RL_STATE_VICMDONCE': 0x0400000, # entered vi command mode at least once 'RL_STATE_REDISPLAYING': 0x0800000, # updating terminal display 'RL_STATE_DONE': 0x1000000, # done; accepted line } _RL_STATE_ISEARCH = _rl_state_flags['RL_STATE_ISEARCH'] _RL_STATE_DONE = _rl_state_flags['RL_STATE_DONE'] _readline_so = CDLL(find_library('readline')) _rl_readline_state = c_int.in_dll(_readline_so, 'rl_readline_state') def _tell_readline_state(): enabled_flag_names = [] for flag_name, flag_value in sorted(_rl_state_flags.items()): if _rl_readline_state.value & flag_value: enabled_flag_names.append('%s(0x%x)' % (flag_name, flag_value)) if not enabled_flag_names: enabled_flag_names.append('RL_STATE_NONE') print('Readline state: %s' % ' | '.join(enabled_flag_names), file=sys.stderr) def _fix_readline_state_after_ctrl_c(): changes_needed = False # Unset RL_STATE_ISEARCH flag if _rl_readline_state.value & _RL_STATE_ISEARCH: _rl_readline_state.value &= ~_RL_STATE_ISEARCH changes_needed = True # Set RL_STATE_DONE flag if not _rl_readline_state.value & _RL_STATE_DONE: _rl_readline_state.value |= _RL_STATE_DONE changes_needed = True return changes_needed if __name__ == '__main__': readline.add_history('some command to search for') print('Press Ctrl+D to leave.') print('For the workaround to show: press (for search), type "a", press , press .') _tell_readline_state() while True: try: line = raw_input('> ') _tell_readline_state() except EOFError: print() _tell_readline_state() break except KeyboardInterrupt: print() _tell_readline_state() if _fix_readline_state_after_ctrl_c(): print('Readline state adjusted.', file=sys.stderr) _tell_readline_state() continue print('You wrote "%s".' % line)