Indenting completer for the python shell

By Filip Salo; published on March 02, 2007.

Need to throw this out somewhere.

The rlcompleter module provides a simple way to get tab completion in the python shell. Unfortunately, that sort of disables the tab key for indentation (although you can do Ctrl-v TAB). I just wrote this indenting completer to get around that.

When you're at the beginning of a line, or have only whitespace to the left of the cursor, it completes to multiples of four spaces of indentation. Everything else gets passed through to the original completer.

And it goes a little something like this:

#!/usr/bin/env python
# Readline-thingamabob for the python shell
# 2007-03-02 Filip Salomonsson <filip.salomonsson@gmail.com>

import os, readline, rlcompleter, atexit

history_file = os.path.join(os.environ['HOME'], '.python_history')
try:
    readline.read_history_file(history_file)
except IOError:
    pass
readline.parse_and_bind("tab: complete")
readline.set_history_length(1000)
atexit.register(readline.write_history_file, history_file)

class IndentingCompleter:
    """Indenting tab completer. Completes to multiples of four spaces
    for indentation; passes through to original completer when
    appropriate."""
    def __init__(self, completer=None):
        # Grab the existing completer
        self.real_completer = completer or readline.get_completer()

    def complete(self, text, state):
        import readline
        # Get the part of the line preceding the cursor
        line = readline.get_line_buffer()[:readline.get_endidx()]
        if not text:
            # No word to complete
            if not line or line.isspace():
                # Indentation only (or start of line)
                if state > 0: return None # only one suggestion
                indent_level = (4 - len(line.replace("\t", 8*' ')) % 4)
                return indent_level * ' '
            else:
                # We're within a line; pass through to real completer
                return self.real_completer(text, state)

        # Normal word completion; pass through to real completer
        return self.real_completer(text, state)


readline.set_completer(IndentingCompleter().complete)

del os, readline, rlcompleter, atexit, __file__
del history_file, IndentingCompleter

Save it somewhere and put the file's path in your PYTHONSTARTUP environment variable, and you should be good to go. The cross-session 1000-command history comes with the package.

Enjoy.

Other variants