[solo.commands.command] simplify and improve bash completions

Note: <tab> below can mean double <tab>.

This commit fixes cases such like the following ones:

* crash (issue !73) - e.g. KeyError: u'--mtime':
    - equo security oscheck --mtime <tab>
    - equo query graph --complete <tab>
      (this was due to a typo in variable name)

* now prints options, previously it didn't:
    - equo install -a <tab>

* crashed, or (with only variable name fixed) didn't print all options:
    - equo security oscheck --mtime <tab>
      (note that it worked with more special -q instead of --mtime etc.)

* didn't print all options:
    - equo query list installed <tab>
      (now shows also --by-user)

The following behaviour is still buggy:

* last typed word (note: no space before <tab>) disappears upon completion:
    - equo security oscheck<tab>
      (not a regression)
    - equo install --deep<tab>
      (here it's an option; regression! - previously it didn't complete but
      didn't cause the word to be erased either)

These can be corrected reliably when something like ${COMP_WORDS[COMP_CWORD]}
(from complete -F) is passed to the Python side.
Without this it's not possible to distinguish between `recognized_option<tab>`
(completion of recognized_option) and `recognized_option <tab>`.
This commit is contained in:
Sławomir Nizio
2019-07-16 08:35:32 +02:00
parent fa6068b2e4
commit b2c8e2c819

View File

@@ -183,35 +183,23 @@ class SoloCommand(object):
This method implements bash completion through
a hierarchical (commands) dictionary object.
"""
# navigate through commands, finding the list of commands
_commands = commands
if not self._args:
# show all the commands
outcome += sorted(commands.keys())
for index, item in enumerate(self._args):
if item in _commands:
_commands = commands[item]
if index == (len(self._args) - 1):
# if this is the last one, generate
# proper outcome elements.
outcome += sorted(_commands.keys())
# reset last_arg so that outcome list
# won't be filtered
last_arg = ""
elif index == (len(self._args) - 1):
# if this is the last one, and item
# is not in _commands, outcome becomes
# _commands.keys()
outcome += sorted(_commands.keys())
# no need to break here
else:
# item not in commands, but that's not the
# last one, we must generate proper outcome
# elements and stop right after
outcome += sorted(_commands.keys())
last_arg_recognised = False
for item in self._args:
if item not in _commands:
last_arg_recognised = False
break
last_arg_recognised = True
if item.startswith("-"):
continue
_commands = _commands[item]
outcome += sorted(_commands.keys())
if last_arg_recognised:
# Make it so all outcomes will be displayed, not filtered out.
last_arg = None
return self._bashcomp(sys.stdout, last_arg, outcome)