summaryrefslogtreecommitdiff
path: root/cmd2/cmd2.py
diff options
context:
space:
mode:
authorEric Lin <anselor@gmail.com>2018-05-02 14:53:20 -0400
committerEric Lin <anselor@gmail.com>2018-05-02 14:53:20 -0400
commita95c8a065abeac286c196783393ecc49e4356f54 (patch)
treeb4575eda772450b54620d16c09d4d29c52abdec7 /cmd2/cmd2.py
parentd2d3c2f37d5324b5bc967fe268a92f9d563a3a30 (diff)
parent148f05d0af66f38c8ba6ca3a5619f50a8bb1b8a9 (diff)
downloadcmd2-git-a95c8a065abeac286c196783393ecc49e4356f54.tar.gz
Merge branch 'bash_completion' into bash_to_pyscript
Diffstat (limited to 'cmd2/cmd2.py')
-rwxr-xr-xcmd2/cmd2.py95
1 files changed, 41 insertions, 54 deletions
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 98adc01f..80fa5601 100755
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -71,10 +71,6 @@ elif rl_type == RlType.GNU:
import ctypes
from .rl_utils import readline_lib
- # Save address that rl_basic_quote_characters is pointing to since we need to override and restore it
- rl_basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
- orig_rl_basic_quote_characters_addr = ctypes.cast(rl_basic_quote_characters, ctypes.c_void_p).value
-
# Newer versions of pyperclip are released as a single file, but older versions had a more complicated structure
try:
from pyperclip.exceptions import PyperclipException
@@ -184,21 +180,6 @@ def _which(editor: str) -> Optional[str]:
return editor_path
-def strip_quotes(arg: str) -> str:
- """ Strip outer quotes from a string.
-
- Applies to both single and double quotes.
-
- :param arg: string to strip outer quotes from
- :return: same string with potentially outer quotes stripped
- """
- quote_chars = '"' + "'"
-
- if len(arg) > 1 and arg[0] == arg[-1] and arg[0] in quote_chars:
- arg = arg[1:-1]
- return arg
-
-
def parse_quoted_string(cmdline: str) -> List[str]:
"""Parse a quoted string into a list of arguments."""
if isinstance(cmdline, list):
@@ -211,7 +192,7 @@ def parse_quoted_string(cmdline: str) -> List[str]:
if not POSIX_SHLEX and STRIP_QUOTES_FOR_NON_POSIX:
temp_arglist = []
for arg in lexed_arglist:
- temp_arglist.append(strip_quotes(arg))
+ temp_arglist.append(utils.strip_quotes(arg))
lexed_arglist = temp_arglist
return lexed_arglist
@@ -385,7 +366,7 @@ def replace_with_file_contents(fname: str) -> str:
"""
try:
# Any outer quotes are not part of the filename
- unquoted_file = strip_quotes(fname[0])
+ unquoted_file = utils.strip_quotes(fname[0])
with open(os.path.expanduser(unquoted_file)) as source_file:
result = source_file.read()
except IOError:
@@ -603,11 +584,22 @@ class AddSubmenu(object):
try:
# copy over any shared attributes
self._copy_in_shared_attrs(_self)
+
+ # Reset the submenu's tab completion parameters
+ submenu.allow_appended_space = True
+ submenu.allow_closing_quote = True
+ submenu.display_matches = []
+
return _complete_from_cmd(submenu, text, line, begidx, endidx)
finally:
# copy back original attributes
self._copy_out_shared_attrs(_self, original_attributes)
+ # Pass the submenu's tab completion parameters back up to the menu that called complete()
+ _self.allow_appended_space = submenu.allow_appended_space
+ _self.allow_closing_quote = submenu.allow_closing_quote
+ _self.display_matches = copy.copy(submenu.display_matches)
+
original_do_help = cmd_obj.do_help
original_complete_help = cmd_obj.complete_help
@@ -996,6 +988,11 @@ class Cmd(cmd.Cmd):
self.allow_closing_quote = True
self.display_matches = []
+ if rl_type == RlType.GNU:
+ readline.set_completion_display_matches_hook(self._display_matches_gnu_readline)
+ elif rl_type == RlType.PYREADLINE:
+ readline.rl.mode._display_completions = self._display_matches_pyreadline
+
def tokens_for_completion(self, line, begidx, endidx):
"""
Used by tab completion functions to get all tokens through the one being completed
@@ -1105,7 +1102,7 @@ class Cmd(cmd.Cmd):
raw_tokens = initial_tokens
# Save the unquoted tokens
- tokens = [strip_quotes(cur_token) for cur_token in raw_tokens]
+ tokens = [utils.strip_quotes(cur_token) for cur_token in raw_tokens]
# If the token being completed had an unclosed quote, we need
# to remove the closing quote that was added in order for it
@@ -2368,38 +2365,33 @@ class Cmd(cmd.Cmd):
"""
# An almost perfect copy from Cmd; however, the pseudo_raw_input portion
# has been split out so that it can be called separately
- if self.use_rawinput and self.completekey:
+ if self.use_rawinput and self.completekey and rl_type != RlType.NONE:
# Set up readline for our tab completion needs
if rl_type == RlType.GNU:
- readline.set_completion_display_matches_hook(self._display_matches_gnu_readline)
-
# Set GNU readline's rl_basic_quote_characters to NULL so it won't automatically add a closing quote
# We don't need to worry about setting rl_completion_suppress_quote since we never declared
# rl_completer_quote_characters.
- rl_basic_quote_characters.value = None
+ basic_quote_characters = ctypes.c_char_p.in_dll(readline_lib, "rl_basic_quote_characters")
+ old_basic_quote_characters = ctypes.cast(basic_quote_characters, ctypes.c_void_p).value
+ basic_quote_characters.value = None
- elif rl_type == RlType.PYREADLINE:
- readline.rl.mode._display_completions = self._display_matches_pyreadline
+ old_completer = readline.get_completer()
+ old_delims = readline.get_completer_delims()
+ readline.set_completer(self.complete)
- try:
- self.old_completer = readline.get_completer()
- self.old_delims = readline.get_completer_delims()
- readline.set_completer(self.complete)
+ # Break words on whitespace and quotes when tab completing
+ completer_delims = " \t\n" + ''.join(constants.QUOTES)
- # Break words on whitespace and quotes when tab completing
- completer_delims = " \t\n" + ''.join(constants.QUOTES)
+ if self.allow_redirection:
+ # If redirection is allowed, then break words on those characters too
+ completer_delims += ''.join(constants.REDIRECTION_CHARS)
- if self.allow_redirection:
- # If redirection is allowed, then break words on those characters too
- completer_delims += ''.join(constants.REDIRECTION_CHARS)
+ readline.set_completer_delims(completer_delims)
- readline.set_completer_delims(completer_delims)
+ # Enable tab completion
+ readline.parse_and_bind(self.completekey + ": complete")
- # Enable tab completion
- readline.parse_and_bind(self.completekey + ": complete")
- except NameError:
- pass
stop = None
try:
while not stop:
@@ -2423,19 +2415,15 @@ class Cmd(cmd.Cmd):
# Run the command along with all associated pre and post hooks
stop = self.onecmd_plus_hooks(line)
finally:
- if self.use_rawinput and self.completekey:
+ if self.use_rawinput and self.completekey and rl_type != RlType.NONE:
# Restore what we changed in readline
- try:
- readline.set_completer(self.old_completer)
- readline.set_completer_delims(self.old_delims)
- except NameError:
- pass
+ readline.set_completer(old_completer)
+ readline.set_completer_delims(old_delims)
if rl_type == RlType.GNU:
readline.set_completion_display_matches_hook(None)
- rl_basic_quote_characters.value = orig_rl_basic_quote_characters_addr
-
+ basic_quote_characters.value = old_basic_quote_characters
elif rl_type == RlType.PYREADLINE:
readline.rl.mode._display_completions = orig_pyreadline_display
@@ -2781,7 +2769,7 @@ Usage: Usage: unalias [-a] name [name ...]
set_parser = ACArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
set_parser.add_argument('-a', '--all', action='store_true', help='display read-only settings as well')
set_parser.add_argument('-l', '--long', action='store_true', help='describe function of parameter')
- set_parser.add_argument('settable', nargs=(0,2), help='[param_name] [value]')
+ set_parser.add_argument('settable', nargs=(0, 2), help='[param_name] [value]')
@with_argparser(set_parser)
def do_set(self, args):
@@ -2838,7 +2826,7 @@ Usage: Usage: unalias [-a] name [name ...]
# an unclosed quote, so we only need to check the first character.
first_char = tokens[index][0]
if first_char in constants.QUOTES:
- tokens[index] = strip_quotes(tokens[index])
+ tokens[index] = utils.strip_quotes(tokens[index])
tokens[index] = os.path.expanduser(tokens[index])
@@ -2862,7 +2850,6 @@ Usage: Usage: unalias [-a] name [name ...]
index_dict = {1: self.shell_cmd_complete}
return self.index_based_complete(text, line, begidx, endidx, index_dict, self.path_complete)
-
# noinspection PyBroadException
def do_py(self, arg):
"""
@@ -3356,7 +3343,7 @@ class ParserManager:
ignore=do_not_parse)('pipeTo')) + \
pyparsing.Optional(output_destination_parser +
pyparsing.SkipTo(string_end, ignore=do_not_parse).
- setParseAction(lambda x: strip_quotes(x[0].strip()))('outputTo'))
+ setParseAction(lambda x: utils.strip_quotes(x[0].strip()))('outputTo'))
multilineCommand.setParseAction(lambda x: x[0])
oneline_command.setParseAction(lambda x: x[0])