eclipse
eclipse

Reputation: 397

tab completion not working

I'm trying to create a prompt with tab completion. I have two files. main.py and prompt.py. main.py imports prompt.py and runs prompt.py's main() function. The main() function sets up a tab completer using readline and repeatedly waits for user input. It prints whatever is inputted and should have tab completion which completes according to whatever text is in the COMMANDS list.

main.py:

import prompt
prompt.main()

prompt.py:

import readline
import colorama
colorama.init()
COMMANDS = ['qwerty','uiop','asdf','ghjkl']

def complete(text, state):
    for cmd in COMMANDS:
        if cmd.startswith(text):
            if not state:
                return cmd
            else:
                state -= 1

def main():
    readline.parse_and_bind("tab: complete")
    readline.set_completer(complete)
    while True:
        test_input=raw_input(':')
        print test_input

main()

What should happen is when I press the tab button the program tries to autocomplete to whatever is in the COMMANDS list. So if I type in "qwe" and press tab the program tab completes to "qwerty". However when I press tab in the program, nothing happens.

Upon commenting the line colorama.init(), the code can now autocomplete. So the line colorama.init() is affecting tab completing. Why is this so? How can I run that line without it affecting the tab as I need the colorama module to output colored text on the windows command prompt.

Upvotes: 1

Views: 1404

Answers (1)

c z
c z

Reputation: 8958

The problem is that readline uses the standard output stream, which is equivalent to sys.__stdout__, to control the terminal.

However, when you call colorama.init(), Python's default stream, sys.stdout, is redirected to colorama's own wrapper.

readline then no longer sees the unadulterated standard output and fails to function. Notably, colorama strips the special escape codes that readline uses.

This problem will also occur if you manually redirect sys.stdout - for instance to apply your own formatting or send output to a GUI.

The solution in all cases is to restore sys.stdout to the default, sys.__stdout__, for the duration of any input, for instance via:

original_stdout = sys.stdout
sys.stdout = sys.__stdout__
foo = input()
sys.stdout = original_stdout

Note that coloramas OS-indenpendent colouring features now won't work during this input, so if you want colours in your input prompt, you'll have to branch and make the relevant escape calls for your supported platforms (Windows/Unix) independently.

Upvotes: 1

Related Questions