diff --git a/cliff/complete.py b/cliff/complete.py index bb5ef28..c84f0ca 100644 --- a/cliff/complete.py +++ b/cliff/complete.py @@ -21,9 +21,21 @@ class CompleteDictionary: optstr = ' '.join(opt for action in actions for opt in action.option_strings) dicto = self._dictionary + last_cmd = command[-1] for subcmd in command[:-1]: - dicto = dicto.setdefault(subcmd, {}) - dicto[command[-1]] = optstr + subdata = dicto.get(subcmd) + # If there is a string in corresponding dictionary, it means the + # verb used for the command exists already. + # For example, {'cmd': 'action'}, and we add the command + # 'cmd_other'. We want the result to be + # {'cmd': 'action other', 'cmd_other': 'sub_action'} + if isinstance(subdata, six.string_types): + subdata += ' ' + last_cmd + dicto[subcmd] = subdata + last_cmd = subcmd + '_' + last_cmd + else: + dicto = dicto.setdefault(subcmd, {}) + dicto[last_cmd] = optstr def get_commands(self): return ' '.join(k for k in sorted(self._dictionary.keys())) diff --git a/cliff/tests/test_complete.py b/cliff/tests/test_complete.py index 441b2ff..6134f57 100644 --- a/cliff/tests/test_complete.py +++ b/cliff/tests/test_complete.py @@ -32,6 +32,26 @@ def test_complete_dictionary(): assert "2" == result[3][1] +def test_complete_dictionary_subcmd(): + sot = complete.CompleteDictionary() + sot.add_command("image delete".split(), + [mock.Mock(option_strings=["1"])]) + sot.add_command("image list".split(), + [mock.Mock(option_strings=["2"])]) + sot.add_command("image list better".split(), + [mock.Mock(option_strings=["3"])]) + assert "image" == sot.get_commands() + result = sot.get_data() + assert "image" == result[0][0] + assert "delete list list_better" == result[0][1] + assert "image_delete" == result[1][0] + assert "1" == result[1][1] + assert "image_list" == result[2][0] + assert "2 better" == result[2][1] + assert "image_list_better" == result[3][0] + assert "3" == result[3][1] + + class FakeStdout: def __init__(self): self.content = []