Example Code

Introductory code examples.

Completion Function

The completion entry function is called as function(text, state) for state in 0, 1, 2, ... until it returns None. It should return the next possible completion for text:

# Complete system commands

import os

from rl import completer
from rl import print_exc


class CommandCompleter(object):
    # A completion "function" implementing readline's
    # generator protocol

    @print_exc
    def __call__(self, text, state):
        if state == 0:
            self.matches = []
            # Find executables matching 'text'
            for dir in os.environ.get('PATH').split(':'):
                dir = os.path.expanduser(dir)
                if os.path.isdir(dir):
                    for name in os.listdir(dir):
                        if name.startswith(text):
                            if os.access(os.path.join(dir, name), os.R_OK|os.X_OK):
                                self.matches.append(name)
        try:
            return self.matches[state]
        except IndexError:
            return None


def main():
    # Set the completion function
    completer.completer = CommandCompleter()

    # Enable TAB completion
    completer.parse_and_bind('TAB: complete')

    command = raw_input('command> ')
    print 'You typed:', command


if __name__ == '__main__':
    main()

Generator Factory

The generator() factory provides a simpler way to support this protocol:

# Complete system commands

# Instead of implementing the generator protocol directly,
# we can provide a matcher function and use the 'generator'
# factory on it.

import os

from rl import completer
from rl import generator
from rl import print_exc


@print_exc
def complete_command(text):
    # Return executables matching 'text'
    for dir in os.environ.get('PATH').split(':'):
        dir = os.path.expanduser(dir)
        if os.path.isdir(dir):
            for name in os.listdir(dir):
                if name.startswith(text):
                    if os.access(os.path.join(dir, name), os.R_OK|os.X_OK):
                        yield name


def main():
    # Set the completion function
    completer.completer = generator(complete_command)

    # Enable TAB completion
    completer.parse_and_bind('TAB: complete')

    command = raw_input('command> ')
    print 'You typed:', command


if __name__ == '__main__':
    main()

Multiple Completions

Most of the time the completion entry function is itself a dispatcher, forwarding calls to more specific completion functions depending on position and format of the completion word:

# Complete email addresses

# The completion function oftentimes is a dispatcher,
# forwarding calls to more specific completion functions.

from rl import completer
from rl import completion
from rl import generator
from rl import print_exc


def complete_hostname(text):
    # Search /etc/hosts for matching hostnames
    f = open('/etc/hosts', 'rt')
    lines = f.readlines()
    f.close()
    for line in lines:
        line = line.split()
        if line and not line[0].startswith('#'):
            for hostname in line[1:]:
                if hostname.startswith(text[1:]):
                    yield '@' + hostname


@print_exc
def complete_email(text):
    # Dispatch to username or hostname completion
    if text.startswith('@'):
        return complete_hostname(text)
    else:
        completion.append_character = '@'
        return completion.complete_username(text)


def main():
    from rl.utils import DEFAULT_DELIMS

    # Configure word break characters
    completer.word_break_characters = DEFAULT_DELIMS.replace('-', '')

    # Configure special prefixes
    completer.special_prefixes = '@'

    # Set the completion function
    completer.completer = generator(complete_email)

    # Enable TAB completion
    completer.parse_and_bind('TAB: complete')

    try:
        email = raw_input('email> ')
    except (EOFError, KeyboardInterrupt):
        print # Newline
    else:
        print 'You typed:', email.strip()


if __name__ == '__main__':
   main()

Pre-Input Hook

The pre_input_hook may be used to pre-populate the line buffer:

# Demonstrate prompt and pre-input hook

from rl import completer
from rl import completion
from rl import print_exc


class Questionnaire(object):

    questions = ('My job is', 'My hobby is', 'I have always wanted to be a')
    defaults = ('great', 'golf', 'fireman')

    def __init__(self):
        completer.pre_input_hook = self.pre_input_hook

    def interact(self):
        print 'Please finish the following statements'
        print '--------------------------------------'
        # The prompt area is used for text the user
        # must not overwrite or change
        for self.index in range(len(self.questions)):
            raw_input(self.questions[self.index]+': ')
        print 'Thank you!'

    @print_exc
    def pre_input_hook(self):
        # The pre-input hook is used to insert text into
        # the line buffer which the user may then edit
        completion.line_buffer = self.defaults[self.index]
        completion.redisplay()


def main():
    Questionnaire().interact()


if __name__ == '__main__':
    main()