Skip to content

Commit 8d8db3f

Browse files
authored
Merge branch 'master' into bash_completion
2 parents 452c396 + 01e4e02 commit 8d8db3f

File tree

1 file changed

+36
-34
lines changed

1 file changed

+36
-34
lines changed

cmd2/cmd2.py

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,6 @@
7171
import ctypes
7272
from .rl_utils import readline_lib
7373

74-
# Save address that rl_basic_quote_characters is pointing to since we need to override and restore it
75-
rl_basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
76-
orig_rl_basic_quote_characters_addr = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value
77-
7874
# Newer versions of pyperclip are released as a single file, but older versions had a more complicated structure
7975
try:
8076
from pyperclip.exceptions import PyperclipException
@@ -580,11 +576,22 @@ def complete_submenu(_self, text, line, begidx, endidx):
580576
try:
581577
# copy over any shared attributes
582578
self._copy_in_shared_attrs(_self)
579+
580+
# Reset the submenu's tab completion parameters
581+
submenu.allow_appended_space = True
582+
submenu.allow_closing_quote = True
583+
submenu.display_matches = []
584+
583585
return _complete_from_cmd(submenu, text, line, begidx, endidx)
584586
finally:
585587
# copy back original attributes
586588
self._copy_out_shared_attrs(_self, original_attributes)
587589

590+
# Pass the submenu's tab completion parameters back up to the menu that called complete()
591+
_self.allow_appended_space = submenu.allow_appended_space
592+
_self.allow_closing_quote = submenu.allow_closing_quote
593+
_self.display_matches = copy.copy(submenu.display_matches)
594+
588595
original_do_help = cmd_obj.do_help
589596
original_complete_help = cmd_obj.complete_help
590597

@@ -972,6 +979,11 @@ def set_completion_defaults(self):
972979
self.allow_closing_quote = True
973980
self.display_matches = []
974981

982+
if rl_type == RlType.GNU:
983+
readline.set_completion_display_matches_hook(self._display_matches_gnu_readline)
984+
elif rl_type == RlType.PYREADLINE:
985+
readline.rl.mode._display_completions = self._display_matches_pyreadline
986+
975987
def tokens_for_completion(self, line, begidx, endidx):
976988
"""
977989
Used by tab completion functions to get all tokens through the one being completed
@@ -2342,38 +2354,33 @@ def _cmdloop(self):
23422354
"""
23432355
# An almost perfect copy from Cmd; however, the pseudo_raw_input portion
23442356
# has been split out so that it can be called separately
2345-
if self.use_rawinput and self.completekey:
2357+
if self.use_rawinput and self.completekey and rl_type != RlType.NONE:
23462358

23472359
# Set up readline for our tab completion needs
23482360
if rl_type == RlType.GNU:
2349-
readline.set_completion_display_matches_hook(self._display_matches_gnu_readline)
2350-
23512361
# Set GNU readline's rl_basic_quote_characters to NULL so it won't automatically add a closing quote
23522362
# We don't need to worry about setting rl_completion_suppress_quote since we never declared
23532363
# rl_completer_quote_characters.
2354-
rl_basic_quote_characters.value = None
2364+
basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
2365+
old_basic_quote_characters = ctypes.cast(basic_quote_characters, ctypes.c_void_p).value
2366+
basic_quote_characters.value = None
23552367

2356-
elif rl_type == RlType.PYREADLINE:
2357-
readline.rl.mode._display_completions = self._display_matches_pyreadline
2368+
old_completer = readline.get_completer()
2369+
old_delims = readline.get_completer_delims()
2370+
readline.set_completer(self.complete)
23582371

2359-
try:
2360-
self.old_completer = readline.get_completer()
2361-
self.old_delims = readline.get_completer_delims()
2362-
readline.set_completer(self.complete)
2372+
# Break words on whitespace and quotes when tab completing
2373+
completer_delims = " \t\n" + ''.join(constants.QUOTES)
23632374

2364-
# Break words on whitespace and quotes when tab completing
2365-
completer_delims = " \t\n" + ''.join(constants.QUOTES)
2375+
if self.allow_redirection:
2376+
# If redirection is allowed, then break words on those characters too
2377+
completer_delims += ''.join(constants.REDIRECTION_CHARS)
23662378

2367-
if self.allow_redirection:
2368-
# If redirection is allowed, then break words on those characters too
2369-
completer_delims += ''.join(constants.REDIRECTION_CHARS)
2379+
readline.set_completer_delims(completer_delims)
23702380

2371-
readline.set_completer_delims(completer_delims)
2381+
# Enable tab completion
2382+
readline.parse_and_bind(self.completekey + ": complete")
23722383

2373-
# Enable tab completion
2374-
readline.parse_and_bind(self.completekey + ": complete")
2375-
except NameError:
2376-
pass
23772384
stop = None
23782385
try:
23792386
while not stop:
@@ -2397,19 +2404,15 @@ def _cmdloop(self):
23972404
# Run the command along with all associated pre and post hooks
23982405
stop = self.onecmd_plus_hooks(line)
23992406
finally:
2400-
if self.use_rawinput and self.completekey:
2407+
if self.use_rawinput and self.completekey and rl_type != RlType.NONE:
24012408

24022409
# Restore what we changed in readline
2403-
try:
2404-
readline.set_completer(self.old_completer)
2405-
readline.set_completer_delims(self.old_delims)
2406-
except NameError:
2407-
pass
2410+
readline.set_completer(old_completer)
2411+
readline.set_completer_delims(old_delims)
24082412

24092413
if rl_type == RlType.GNU:
24102414
readline.set_completion_display_matches_hook(None)
2411-
rl_basic_quote_characters.value = orig_rl_basic_quote_characters_addr
2412-
2415+
basic_quote_characters.value = old_basic_quote_characters
24132416
elif rl_type == RlType.PYREADLINE:
24142417
readline.rl.mode._display_completions = orig_pyreadline_display
24152418

@@ -2755,7 +2758,7 @@ def show(self, args, parameter):
27552758
set_parser = ACArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
27562759
set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well')
27572760
set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter')
2758-
set_parser.add_argument('settable', nargs=(0,2), help='[param_name] [value]')
2761+
set_parser.add_argument('settable', nargs=(0, 2), help='[param_name] [value]')
27592762

27602763
@with_argparser(set_parser)
27612764
def do_set(self, args):
@@ -2836,7 +2839,6 @@ def complete_shell(self, text, line, begidx, endidx):
28362839
index_dict = {1: self.shell_cmd_complete}
28372840
return self.index_based_complete(text, line, begidx, endidx, index_dict, self.path_complete)
28382841

2839-
28402842
# noinspection PyBroadException
28412843
def do_py(self, arg):
28422844
"""

0 commit comments

Comments
 (0)