_bashcomplete.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import os
  2. import re
  3. from .utils import echo
  4. from .parser import split_arg_string
  5. from .core import MultiCommand, Option
  6. COMPLETION_SCRIPT = '''
  7. %(complete_func)s() {
  8. COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\
  9. COMP_CWORD=$COMP_CWORD \\
  10. %(autocomplete_var)s=complete $1 ) )
  11. return 0
  12. }
  13. complete -F %(complete_func)s -o default %(script_names)s
  14. '''
  15. _invalid_ident_char_re = re.compile(r'[^a-zA-Z0-9_]')
  16. def get_completion_script(prog_name, complete_var):
  17. cf_name = _invalid_ident_char_re.sub('', prog_name.replace('-', '_'))
  18. return (COMPLETION_SCRIPT % {
  19. 'complete_func': '_%s_completion' % cf_name,
  20. 'script_names': prog_name,
  21. 'autocomplete_var': complete_var,
  22. }).strip() + ';'
  23. def resolve_ctx(cli, prog_name, args):
  24. ctx = cli.make_context(prog_name, args, resilient_parsing=True)
  25. while ctx.protected_args + ctx.args and isinstance(ctx.command, MultiCommand):
  26. a = ctx.protected_args + ctx.args
  27. cmd = ctx.command.get_command(ctx, a[0])
  28. if cmd is None:
  29. return None
  30. ctx = cmd.make_context(a[0], a[1:], parent=ctx, resilient_parsing=True)
  31. return ctx
  32. def get_choices(cli, prog_name, args, incomplete):
  33. ctx = resolve_ctx(cli, prog_name, args)
  34. if ctx is None:
  35. return
  36. choices = []
  37. if incomplete and not incomplete[:1].isalnum():
  38. for param in ctx.command.params:
  39. if not isinstance(param, Option):
  40. continue
  41. choices.extend(param.opts)
  42. choices.extend(param.secondary_opts)
  43. elif isinstance(ctx.command, MultiCommand):
  44. choices.extend(ctx.command.list_commands(ctx))
  45. for item in choices:
  46. if item.startswith(incomplete):
  47. yield item
  48. def do_complete(cli, prog_name):
  49. cwords = split_arg_string(os.environ['COMP_WORDS'])
  50. cword = int(os.environ['COMP_CWORD'])
  51. args = cwords[1:cword]
  52. try:
  53. incomplete = cwords[cword]
  54. except IndexError:
  55. incomplete = ''
  56. for item in get_choices(cli, prog_name, args, incomplete):
  57. echo(item)
  58. return True
  59. def bashcomplete(cli, prog_name, complete_var, complete_instr):
  60. if complete_instr == 'source':
  61. echo(get_completion_script(prog_name, complete_var))
  62. return True
  63. elif complete_instr == 'complete':
  64. return do_complete(cli, prog_name)
  65. return False