completion.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import shlex
  2. from argparse import Action
  3. from borgmatic.commands import arguments
  4. def upgrade_message(language: str, upgrade_command: str, completion_file: str):
  5. return f'''
  6. Your {language} completions script is from a different version of borgmatic than is
  7. currently installed. Please upgrade your script so your completions match the
  8. command-line flags in your installed borgmatic! Try this to upgrade:
  9. {upgrade_command}
  10. source {completion_file}
  11. '''
  12. def parser_flags(parser):
  13. '''
  14. Given an argparse.ArgumentParser instance, return its argument flags in a space-separated
  15. string.
  16. '''
  17. return ' '.join(option for action in parser._actions for option in action.option_strings)
  18. def bash_completion():
  19. '''
  20. Return a bash completion script for the borgmatic command. Produce this by introspecting
  21. borgmatic's command-line argument parsers.
  22. '''
  23. top_level_parser, subparsers = arguments.make_parsers()
  24. global_flags = parser_flags(top_level_parser)
  25. actions = ' '.join(subparsers.choices.keys())
  26. # Avert your eyes.
  27. return '\n'.join(
  28. (
  29. 'check_version() {',
  30. ' local this_script="$(cat "$BASH_SOURCE" 2> /dev/null)"',
  31. ' local installed_script="$(borgmatic --bash-completion 2> /dev/null)"',
  32. ' if [ "$this_script" != "$installed_script" ] && [ "$installed_script" != "" ];'
  33. f''' then cat << EOF\n{upgrade_message(
  34. 'bash',
  35. 'sudo sh -c "borgmatic --bash-completion > $BASH_SOURCE"',
  36. '$BASH_SOURCE',
  37. )}\nEOF''',
  38. ' fi',
  39. '}',
  40. 'complete_borgmatic() {',
  41. )
  42. + tuple(
  43. ''' if [[ " ${COMP_WORDS[*]} " =~ " %s " ]]; then
  44. COMPREPLY=($(compgen -W "%s %s %s" -- "${COMP_WORDS[COMP_CWORD]}"))
  45. return 0
  46. fi'''
  47. % (action, parser_flags(subparser), actions, global_flags)
  48. for action, subparser in subparsers.choices.items()
  49. )
  50. + (
  51. ' COMPREPLY=($(compgen -W "%s %s" -- "${COMP_WORDS[COMP_CWORD]}"))' # noqa: FS003
  52. % (actions, global_flags),
  53. ' (check_version &)',
  54. '}',
  55. '\ncomplete -o bashdefault -o default -F complete_borgmatic borgmatic',
  56. )
  57. )
  58. def build_fish_flags(action: Action):
  59. '''
  60. Given an argparse.Action instance, return a string containing the fish flags for that action.
  61. '''
  62. if action.metavar and action.metavar == 'PATH' or action.metavar == 'FILENAME':
  63. return '-r -F'
  64. else:
  65. return '-f'
  66. def fish_completion():
  67. '''
  68. Return a fish completion script for the borgmatic command. Produce this by introspecting
  69. borgmatic's command-line argument parsers.
  70. '''
  71. top_level_parser, subparsers = arguments.make_parsers()
  72. all_subparsers = ' '.join(action for action in subparsers.choices.keys())
  73. # Avert your eyes.
  74. return '\n'.join(
  75. (
  76. 'function __borgmatic_check_version',
  77. ' set this_filename (status current-filename)',
  78. ' set this_script (cat $this_filename 2> /dev/null)',
  79. ' set installed_script (borgmatic --fish-completion 2> /dev/null)',
  80. ' if [ "$this_script" != "$installed_script" ] && [ "$installed_script" != "" ]',
  81. f''' echo "{upgrade_message(
  82. 'fish',
  83. 'borgmatic --fish-completion | sudo tee $this_filename',
  84. '$this_filename',
  85. )}"''',
  86. ' end',
  87. 'end',
  88. '__borgmatic_check_version &',
  89. )
  90. + ('\n# subparser completions',)
  91. + tuple(
  92. f'''complete -c borgmatic -a '{action_name}' -d {shlex.quote(subparser.description)} -f -n "not __fish_seen_subcommand_from {all_subparsers}"'''
  93. for action_name, subparser in subparsers.choices.items()
  94. )
  95. + ('\n# global flags',)
  96. + tuple(
  97. f'''complete -c borgmatic -a '{' '.join(action.option_strings)}' -d {shlex.quote(action.help)} {build_fish_flags(action)}'''
  98. for action in top_level_parser._actions
  99. )
  100. + ('\n# subparser flags',)
  101. + tuple(
  102. f'''complete -c borgmatic -a '{' '.join(action.option_strings)}' -d {shlex.quote(action.help)} -n "__fish_seen_subcommand_from {action_name}" {build_fish_flags(action)}'''
  103. for action_name, subparser in subparsers.choices.items()
  104. for action in subparser._actions
  105. )
  106. )