diff --git a/az.completion.sh b/az.completion.sh new file mode 100644 index 000000000..654b52eb0 --- /dev/null +++ b/az.completion.sh @@ -0,0 +1,13 @@ +if type compdef &>/dev/null; then + #ZSH + _az_complete() { + compadd -- `"${COMP_WORDS[0]}" --complete "${words[@]:1}"` + } + compdef _az_complete az +elif type complete &>/dev/null; then + #BASH + _az_complete() { + COMPREPLY=( $(compgen -W '$("${COMP_WORDS[0]}" --complete "${COMP_WORDS[@]:1}")' -- "${COMP_WORDS[COMP_CWORD]}") ) + } + complete -F _az_complete az +fi diff --git a/src/azure/cli/_argparse.py b/src/azure/cli/_argparse.py index fc7ae204e..081e35ebb 100644 --- a/src/azure/cli/_argparse.py +++ b/src/azure/cli/_argparse.py @@ -264,15 +264,16 @@ class ArgumentParser(object): out.flush() logger.debug('Expected documentation at %s', doc_file) - def _display_completions(self, noun_map, arguments, out=sys.stdout): # pylint: disable=no-self-use - arguments.remove('--complete') + def _display_completions(self, noun_map, arguments, out=sys.stdout): + for a in self.complete_args: + arguments.remove(a) command_candidates = set([k for k in noun_map if not k.startswith('$')]) if command_candidates and not arguments[-1].startswith('-'): command_candidates = set([c for c in command_candidates if c.startswith(arguments[-1])]) kwargs = noun_map.get('$kwargs') or [] - args_candidates = set('--' + a for a in kwargs if a) + args_candidates = set(('--' if len(a) > 1 else '-') + a for a in kwargs) if arguments[-1].startswith('-'): # TODO: We don't have enough metadata about the command to do parameter value # completion (yet). This should only apply to value arguments, not flag arguments diff --git a/src/azure/cli/tests/test_argparse.py b/src/azure/cli/tests/test_argparse.py index 1ba354080..457770dbb 100644 --- a/src/azure/cli/tests/test_argparse.py +++ b/src/azure/cli/tests/test_argparse.py @@ -1,9 +1,17 @@ +try: + # on Python2, we like to use the module "StringIO" rather "io" so to + # avoid "print" errors like: TypeError: string argument expected, got 'str' + from StringIO import StringIO +except ImportError: + # Python 3 + from io import StringIO + import unittest from azure.cli._argparse import ArgumentParser, IncorrectUsageError from azure.cli._logging import logger import logging - +import azure.cli._util as util class Test_argparse(unittest.TestCase): @classmethod @@ -94,6 +102,33 @@ class Test_argparse(unittest.TestCase): self.assertIsNone(p.execute('n1 -b x'.split())) + def test_args_completion(self): + p = ArgumentParser('test') + p.add_command(lambda a, b: (a, b), 'n1', args=[('--arg -a', '', True), ('-b ', '', False)]) + io = StringIO() + + p.execute('n1 - --complete'.split(), + show_usage=False, + show_completions=True, + out=io) + candidates = util.normalize_newlines(io.getvalue()) + self.assertEqual(candidates, '--arg\n-a\n-b\n') + + io = StringIO() + p.execute('n1 --a --complete'.split(), + show_usage=False, + out=io) + candidates = util.normalize_newlines(io.getvalue()) + self.assertEqual(candidates, '--arg\n') + + io = StringIO() + p.execute('n --a --complete'.split(), + show_usage=False, + show_completions=True, + out=io) + candidates = util.normalize_newlines(io.getvalue()) + self.assertEqual(candidates, 'n1\n') + if __name__ == '__main__': unittest.main()