Introductory code examples.
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()
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()
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()
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()