diff --git a/CHANGES.rst b/CHANGES.rst index 32d3baf07..3f6cccb50 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -81,6 +81,7 @@ Unreleased - Fix formatting for short help. (`#1008`_) - Document how ``auto_envar_prefix`` works with command groups. (`#1011`_) - Don't add newlines by default for progress bars. (`#1013`_) +- Use Python sorting order for ZSH completions. (`#1047`_, `#1059`_) - Document that parameter names are lowercased by default. (`#1055`_) - Subcommands that are named by the function now automatically have the underscore replaced with a dash. If you register a function named ``my_command`` it becomes ``my-command`` in the command line interface. @@ -190,7 +191,9 @@ Unreleased .. _#1020: https://github.com/pallets/click/pull/1020 .. _#1022: https://github.com/pallets/click/pull/1022 .. _#1027: https://github.com/pallets/click/pull/1027 +.. _#1047: https://github.com/pallets/click/pull/1047 .. _#1055: https://github.com/pallets/click/pull/1055 +.. _#1059: https://github.com/pallets/click/pull/1059 Version 6.7 diff --git a/click/_bashcomplete.py b/click/_bashcomplete.py index 10202d339..6576cfdc8 100644 --- a/click/_bashcomplete.py +++ b/click/_bashcomplete.py @@ -10,6 +10,7 @@ WORDBREAK = '=' +# Note, only BASH version 4.4 and later have the nosort option. COMPLETION_SCRIPT_BASH = ''' %(complete_func)s() { local IFS=$'\n' @@ -19,7 +20,17 @@ return 0 } -complete -F %(complete_func)s %(script_names)s +%(complete_func)setup() { + local COMPLETION_OPTIONS="" + local BASH_VERSION_ARR=(${BASH_VERSION//./ }) + if [ ${BASH_VERSION_ARR[0]} -ge 4 ] && [ ${BASH_VERSION_ARR[1]} -ge 4 ];then + COMPLETION_OPTIONS="-o nosort" + fi + + complete $COMPLETION_OPTIONS -F %(complete_func)s %(script_names)s +} + +%(complete_func)setup ''' COMPLETION_SCRIPT_ZSH = ''' @@ -41,11 +52,13 @@ done if [ -n "$completions_with_descriptions" ]; then - _describe '' completions_with_descriptions + _describe -V unsorted completions_with_descriptions -U -Q fi + if [ -n "$completions" ]; then - compadd -M 'r:|=* l:|=* r:|=*' -a completions + compadd -U -V unsorted -Q -a completions fi + compstate[insert]="automenu" } compdef %(complete_func)s %(script_names)s @@ -232,7 +245,8 @@ def get_choices(cli, prog_name, args, incomplete): return get_user_autocompletions(ctx, all_args, incomplete, param) add_subcommand_completions(ctx, incomplete, completions) - return completions + # Sort before returning so that proper ordering can be enforced in custom types. + return sorted(completions) def do_complete(cli, prog_name, include_descriptions): diff --git a/examples/bashcompletion/bashcompletion.py b/examples/bashcompletion/bashcompletion.py index 4d9fdde4b..107284003 100644 --- a/examples/bashcompletion/bashcompletion.py +++ b/examples/bashcompletion/bashcompletion.py @@ -8,6 +8,7 @@ def cli(): def get_env_vars(ctx, args, incomplete): + # Completions returned as strings do not have a description displayed. for key in os.environ.keys(): if incomplete in key: yield key @@ -26,11 +27,13 @@ def group(): def list_users(ctx, args, incomplete): - # Here you can generate completions dynamically - users = ['bob', 'alice'] - for user in users: - if user.startswith(incomplete): - yield user + # You can generate completions with descriptions by returning + # tuples in the form (completion, description). + users = [('bob', 'butcher'), + ('alice', 'baker'), + ('jerry', 'candlestick maker')] + # Ths will allow completion matches based on matches within the description string too! + return [user for user in users if incomplete in user[0] or incomplete in user[1]] @group.command(help='Choose a user') @@ -38,4 +41,5 @@ def list_users(ctx, args, incomplete): def subcmd(user): click.echo('Chosen user is %s' % user) + cli.add_command(group)