pythoncommand-line-interfacereadlinepython-cmd

Python cmd autocomplete: display options on separate lines


I am writing a CLI in Python using the cmd module, which provides the autocomplete functionality using the readline module. Autocomplete shows the different options on the same line, while I want them on different lines, and I have not find any parameter in cmd that allows me to do that.

This is an example program:

import cmd

class mycmd(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)

    def do_quit(self, s):
        return True

    def do_add(self, s):
        pass

    def do_addition(self, s):
        pass

    def complete_add(self, text, line, begidx, endidx):
        params = ['asd', 'asdasd', 'lol']
        return [s for s in params if s.startswith(text)]

if __name__ == '__main__':
    mycmd().cmdloop()

and this is the result:

(Cmd) <tab> <tab>
add       addition  help      quit   <-- I want these on different lines
(Cmd) add<tab> <tab>
add       addition                   <-- 
(Cmd) add <tab> <tab>
asd     asdasd  lol                  <-- 
(Cmd) add asd<tab> <tab>
asd     asdasd                       <-- 

If I add a line separator at the end of each autocomplete option, I get this:

(Cmd) add <tab> <tab>
asd^J     asdasd^J  lol^J    

Anyway, this would not solve the autocomplete of the commands, only of the parameters.

Any suggestions?

Thanks for the help!


Solution

  • You need to take over readline's displaying function to do this. To do that, import readline, add this to your __init__:

            readline.set_completion_display_matches_hook(self.match_display_hook)
    

    And add this to your class:

        def match_display_hook(self, substitution, matches, longest_match_length):
            print()
            for match in matches:
                print(match)
            print(self.prompt, readline.get_line_buffer(), sep='', end='', flush=True)