1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
# SPDX-License-Identifier: GPL-3.0-or-later
# Copyright (C) 2025-2026 Benjamin Abendroth <braph93@gmx.de>
'''This module contains code for completing option strings in Bash.'''
from collections import namedtuple
from . import cli
from . import algo
from . import shell
from . import bash_when
from .str_utils import indent
_Option = namedtuple('_Option', ('option', 'conditions', 'when'))
def _make_option_strings(options):
opt_strings = []
for opt in options:
opt_strings.extend(opt.get_short_option_strings())
add_equal_sign = (
opt.has_optional_arg() or (
opt.has_required_arg() and
opt.long_opt_arg_sep in ('both', 'equals')
)
)
if add_equal_sign:
opt_strings.extend(f'{s}=' for s in opt.get_long_option_strings())
opt_strings.extend(f'{s}=' for s in opt.get_old_option_strings())
else:
opt_strings.extend(opt.get_long_option_strings())
opt_strings.extend(opt.get_old_option_strings())
return shell.join_quoted(opt_strings)
def _get_option_full_condition(option):
if option.conditions and option.when:
return '(( %s )) && %s' % (' && '.join(option.conditions), option.when)
if option.conditions:
return '(( %s ))' % (' && '.join(option.conditions))
if option.when:
return '%s' % option.when
return ''
def _generate_option_strings_completion(options):
r = []
grouped_by_condition = algo.group_by(options, _get_option_full_condition)
for condition, opts in grouped_by_condition.items():
s = 'opts+=(%s)' % _make_option_strings([o.option for o in opts])
if condition:
s = '%s && %s' % (condition, s)
r.append(s)
return '\n'.join(r)
def _generate_final_check_with_options(final_conditions, options):
option_strings_completion = _generate_option_strings_completion(options)
if not final_conditions:
return option_strings_completion
r = 'if (( %s )); then\n' % ' && '.join(final_conditions)
r += '%s\n' % indent(option_strings_completion, 2)
r += 'fi'
return r
def generate(generator):
'''Generate option strings completion code.'''
if len(generator.options) == 0:
return None
commandline = generator.commandline
variable_manager = generator.variable_manager
options = []
final_conditions = []
for final_option in commandline.get_final_options():
final_conditions += ["! ${#%s[@]}" % variable_manager.capture_variable(final_option)]
for option in commandline.options:
if option.hidden:
continue
conditions = []
for exclusive_option in option.get_conflicting_options():
conditions += ["! ${#%s[@]}" % variable_manager.capture_variable(exclusive_option)]
if not option.repeatable:
conditions += ["! ${#%s[@]}" % variable_manager.capture_variable(option)]
for final_condition in final_conditions:
try:
conditions.remove(final_condition)
except ValueError:
pass
conditions = algo.uniq(sorted(conditions))
when = None
if option.when is not None:
when = bash_when.generate_when_conditions(commandline, variable_manager, option.when)
options.append(_Option(option, conditions, when))
r = 'if (( ! END_OF_OPTIONS )) && [[ "$cur" = -* ]]; then\n'
r += ' local -a opts\n'
r += '%s\n' % indent(_generate_final_check_with_options(final_conditions, options), 2)
r += ' COMPREPLY+=($(compgen -W "${opts[*]}" -- "$cur"))\n'
r += ' [[ ${COMPREPLY-} == *= ]] && compopt -o nospace\n'
r += ' return 1\n'
r += 'fi'
return r
|