Skip to content

Commit 1dbecfb

Browse files
committed
Restoring all changes to readline before command loop exits
1 parent 2b4f94f commit 1dbecfb

1 file changed

Lines changed: 30 additions & 17 deletions

File tree

cmd2.py

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,12 @@ def __subclasshook__(cls, C):
138138
if readline_lib_name is not None and readline_lib_name:
139139
readline_lib = ctypes.CDLL(readline_lib_name)
140140

141-
# On Windows, we save the original pyreadline display completion function since we have to override it
141+
# Save address that rl_basic_quote_characters is pointing to since we need to override and restore it
142+
rl_basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
143+
orig_rl_basic_quote_characters_addr = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value
144+
142145
else:
146+
# Save the original pyreadline display completion function since we need to override it and restore it
143147
# noinspection PyProtectedMember
144148
orig_pyreadline_display = readline.rl.mode._display_completions
145149

@@ -1209,19 +1213,12 @@ def get_subcommands(self, command):
12091213
def set_completion_defaults(self):
12101214
"""
12111215
Resets tab completion settings
1212-
Called each time complete() is called
1216+
Needs to be called each time readline runs tab completion
12131217
"""
12141218
self.allow_appended_space = True
12151219
self.allow_closing_quote = True
12161220
self.display_matches = []
12171221

1218-
if readline_lib is not None:
1219-
# Set GNU readline's rl_basic_quote_characters to NULL so it won't automatically add a closing quote
1220-
# We don't need to worry about setting rl_completion_suppress_quote since we never declared
1221-
# rl_completer_quote_characters.
1222-
rl_basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
1223-
rl_basic_quote_characters.value = None
1224-
12251222
@staticmethod
12261223
def display_match_list_gnu_readline(substitution, matches, longest_match_length):
12271224
"""
@@ -1956,14 +1953,6 @@ def complete(self, text, state):
19561953
unclosed_quote = ''
19571954
self.set_completion_defaults()
19581955

1959-
# GNU readline specific way to override the completions display function
1960-
if readline_lib is not None:
1961-
readline.set_completion_display_matches_hook(self._display_matches_gnu_readline)
1962-
1963-
# pyreadline specific way to override the completions display function
1964-
elif sys.platform.startswith('win'):
1965-
readline.rl.mode._display_completions = self._display_matches_pyreadline
1966-
19671956
# lstrip the original line
19681957
orig_line = readline.get_line_buffer()
19691958
line = orig_line.lstrip()
@@ -2662,16 +2651,31 @@ def _cmdloop(self):
26622651
# An almost perfect copy from Cmd; however, the pseudo_raw_input portion
26632652
# has been split out so that it can be called separately
26642653
if self.use_rawinput and self.completekey:
2654+
2655+
# Set up readline for our tab completion needs
2656+
if readline_lib is not None:
2657+
readline.set_completion_display_matches_hook(self._display_matches_gnu_readline)
2658+
2659+
# Set GNU readline's rl_basic_quote_characters to NULL so it won't automatically add a closing quote
2660+
# We don't need to worry about setting rl_completion_suppress_quote since we never declared
2661+
# rl_completer_quote_characters.
2662+
rl_basic_quote_characters.value = None
2663+
2664+
elif sys.platform.startswith('win'):
2665+
readline.rl.mode._display_completions = self._display_matches_pyreadline
2666+
26652667
try:
26662668
self.old_completer = readline.get_completer()
26672669
self.old_delims = readline.get_completer_delims()
26682670
readline.set_completer(self.complete)
26692671

26702672
# Break words on whitespace and quotes when tab completing
26712673
completer_delims = " \t\n\"'"
2674+
26722675
if self.allow_redirection:
26732676
# If redirection is allowed, then break words on those characters too
26742677
completer_delims += ''.join(REDIRECTION_CHARS)
2678+
26752679
readline.set_completer_delims(completer_delims)
26762680

26772681
# Enable tab completion
@@ -2702,12 +2706,21 @@ def _cmdloop(self):
27022706
stop = self.onecmd_plus_hooks(line)
27032707
finally:
27042708
if self.use_rawinput and self.completekey:
2709+
2710+
# Restore what we changed in readline
27052711
try:
27062712
readline.set_completer(self.old_completer)
27072713
readline.set_completer_delims(self.old_delims)
27082714
except NameError:
27092715
pass
27102716

2717+
if readline_lib is not None:
2718+
readline.set_completion_display_matches_hook(None)
2719+
rl_basic_quote_characters.value = orig_rl_basic_quote_characters_addr
2720+
2721+
elif sys.platform.startswith('win'):
2722+
readline.rl.mode._display_completions = orig_pyreadline_display
2723+
27112724
# Need to set empty list this way because Python 2 doesn't support the clear() method on lists
27122725
self.cmdqueue = []
27132726
self._script_dir = []

0 commit comments

Comments
 (0)