diff options
author | Eric Lin <anselor@gmail.com> | 2018-04-14 14:15:16 -0700 |
---|---|---|
committer | Eric Lin <anselor@gmail.com> | 2018-04-14 14:15:16 -0700 |
commit | e20f7ec3850db2658053f73f5c9023868d7f12c7 (patch) | |
tree | 5a0acbd4a27f9c9b65874d2975d5b6c6ae155dc1 | |
parent | f6b6a3ce05c47dec6fa7f9c8ab4fc90b9efc6306 (diff) | |
download | cmd2-git-e20f7ec3850db2658053f73f5c9023868d7f12c7.tar.gz |
Started working on an example for autocompleter usage.
-rwxr-xr-x | AutoCompleter.py | 4 | ||||
-rwxr-xr-x | examples/tab_autocompletion.py | 175 |
2 files changed, 177 insertions, 2 deletions
diff --git a/AutoCompleter.py b/AutoCompleter.py index 10274d93..753c8e63 100755 --- a/AutoCompleter.py +++ b/AutoCompleter.py @@ -16,7 +16,7 @@ class _RangeAction(object): self.nargs_max = None
# pre-process special ranged nargs
- if isinstance(nargs, Tuple):
+ if isinstance(nargs, tuple):
if len(nargs) != 2 or not isinstance(nargs[0], int) or not isinstance(nargs[1], int):
raise ValueError('Ranged values for nargs must be a tuple of 2 integers')
if nargs[0] >= nargs[1]:
@@ -122,7 +122,7 @@ class AutoCompleter(object): def __init__(self,
parser: argparse.ArgumentParser,
- token_start_index: int,
+ token_start_index: int = 1,
arg_choices: Dict[str, Union[List, Tuple, Callable]] = None,
subcmd_args_lookup: dict = None,
tab_for_arg_help: bool = True):
diff --git a/examples/tab_autocompletion.py b/examples/tab_autocompletion.py new file mode 100755 index 00000000..a28f839d --- /dev/null +++ b/examples/tab_autocompletion.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# coding=utf-8 +"""A simple example demonstrating how to use flag and index based tab-completion functions +""" +import argparse +import AutoCompleter + +import cmd2 +from cmd2 import with_argparser + +# List of strings used with flag and index based completion functions +food_item_strs = ['Pizza', 'Hamburger', 'Ham', 'Potato'] +sport_item_strs = ['Bat', 'Basket', 'Basketball', 'Football'] + + +class TabCompleteExample(cmd2.Cmd): + """ Example cmd2 application where we a base command which has a couple subcommands.""" + + def __init__(self): + cmd2.Cmd.__init__(self) + + # This demonstrates a number of customizations of the AutoCompleter version of ArgumentParser + # - The help output will separately group required vs optional flags + # - The help output for arguments with multiple flags or with append=True is more concise + # - ACArgumentParser adds the ability to specify ranges of argument counts in 'nargs' + + suggest_parser = AutoCompleter.ACArgumentParser() + + suggest_parser.add_argument('-t', '--type', choices=['movie', 'show'], required=True) + suggest_parser.add_argument('-d', '--duration', nargs=(1, 2), action='append', + help='Duration constraint in minutes.\n' + '\tsingle value - maximum duration\n' + '\t[a, b] - duration range') + + @with_argparser(suggest_parser) + def do_suggest(self, args): + if not args.type: + self.do_help('suggest') + + def complete_suggest(self, text, line, begidx, endidx): + """ Adds tab completion to media""" + print('1') + completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser, 1) + print('2') + tokens, _ = self.tokens_for_completion(line, begidx, endidx) + print('22') + results = completer.complete_command(tokens, text, line, begidx, endidx) + print('3') + + return results + + # If you prefer the original argparse help output but would like narg ranges, it's possible + # to enable narg ranges without the help changes using this method + + suggest_parser_hybrid = argparse.ArgumentParser() + # This registers the custom narg range handling + AutoCompleter.register_custom_actions(suggest_parser_hybrid) + + suggest_parser_hybrid.add_argument('-t', '--type', choices=['movie', 'show'], required=True) + suggest_parser_hybrid.add_argument('-d', '--duration', nargs=(1, 2), action='append', + help='Duration constraint in minutes.\n' + '\tsingle value - maximum duration\n' + '\t[a, b] - duration range') + @with_argparser(suggest_parser_hybrid) + def do_orig_suggest(self, args): + if not args.type: + self.do_help('orig_suggest') + + def complete_hybrid_suggest(self, text, line, begidx, endidx): + """ Adds tab completion to media""" + completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser_hybrid) + + tokens, _ = self.tokens_for_completion(line, begidx, endidx) + results = completer.complete_command(tokens, text, line, begidx, endidx) + + return results + + suggest_parser_orig = argparse.ArgumentParser() + + suggest_parser_orig.add_argument('-t', '--type', choices=['movie', 'show'], required=True) + suggest_parser_orig.add_argument('-d', '--duration', nargs='+', action='append', + help='Duration constraint in minutes.\n' + '\tsingle value - maximum duration\n' + '\t[a, b] - duration range') + @with_argparser(suggest_parser_orig) + def do_orig_suggest(self, args): + if not args.type: + self.do_help('orig_suggest') + + def complete_orig_suggest(self, text, line, begidx, endidx): + """ Adds tab completion to media""" + completer = AutoCompleter.AutoCompleter(TabCompleteExample.suggest_parser_orig) + + tokens, _ = self.tokens_for_completion(line, begidx, endidx) + results = completer.complete_command(tokens, text, line, begidx, endidx) + + return results + + + ################################################################################### + # The media command demonstrates a completer with multiple layers of subcommands + # + + def query_actors(self): + """Simulating a function that queries and returns a completion values""" + return ['Mark Hamill', 'Harrison Ford', 'Carrie Fisher', 'Alec Guinness', 'Peter Mayhew', 'Anthony Daniels', + 'Adam Driver', 'Daisy Ridley', 'John Boyega', 'Oscar Isaac', 'Lupita Nyong\'o', 'Andy Serkis'] + + def _do_media_movies(self, args): + if not args.command: + self.do_help('media movies') + + def _do_media_shows(self, args): + if not args.command: + self.do_help('media shows') + + # example choices list + ratings_types = ['G', 'PG', 'PG-13', 'R', 'NC-17'] + + media_parser = AutoCompleter.ACArgumentParser() + + media_types_subparsers = media_parser.add_subparsers(title='Media Types', dest='type') + + movies_parser = media_types_subparsers.add_parser('movies') + movies_parser.set_defaults(func=_do_media_movies) + + movies_commands_subparsers = movies_parser.add_subparsers(title='Commands', dest='command') + + movies_list_parser = movies_commands_subparsers.add_parser('list') + + movies_list_parser.add_argument('-t', '--title', help='Title Filter') + movies_list_parser.add_argument('-r', '--rating', help='Rating Filter', nargs='+', + choices=ratings_types) + movies_list_parser.add_argument('-d', '--director', help='Director Filter') + movies_list_parser.add_argument('-a', '--actor', help='Actor Filter', action='append') + + movies_add_parser = movies_commands_subparsers.add_parser('add') + movies_add_parser.add_argument('-t', '--title', help='Movie Title', required=True) + movies_add_parser.add_argument('-r', '--rating', help='Movie Rating', choices=ratings_types, required=True) + movies_add_parser.add_argument('-d', '--director', help='Director', action='append', required=True) + movies_add_parser.add_argument('-a', '--actor', help='Actors', action='append', required=True) + + movies_delete_parser = movies_commands_subparsers.add_parser('delete') + + shows_parser = media_types_subparsers.add_parser('shows') + shows_parser.set_defaults(func=_do_media_shows) + + @with_argparser(media_parser) + def do_media(self, args): + """Media management""" + func = getattr(args, 'func', None) + if func is not None: + # Call whatever subcommand function was selected + func(self, args) + else: + # No subcommand was provided, so call help + self.do_help('media') + + def complete_media(self, text, line, begidx, endidx): + """ Adds tab completion to media""" + directors = ['J. J. Abrams', 'Irvin Kershner', 'George Lucas', 'Richard Marquand', + 'Rian Johnson', 'Gareth Edwards'] + choices = {'actor': self.query_actors, + 'director': directors} + completer = AutoCompleter.AutoCompleter(TabCompleteExample.media_parser, arg_choices=choices) + + tokens, _ = self.tokens_for_completion(line, begidx, endidx) + results = completer.complete_command(tokens, text, line, begidx, endidx) + + return results + + +if __name__ == '__main__': + app = TabCompleteExample() + app.cmdloop() |