Examples¶
Example code.
Completion Entry 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
.
You can run this example with python -m rl.examples.raw_input
.
# Complete system commands
import os
from rl import completer
class CommandCompleter:
# A completion entry function implementing readline's
# generator protocol
def __call__(self, text, state):
if state == 0:
self.matches = list(self.complete_command(text))
try:
return self.matches[state]
except IndexError:
return None
def complete_command(self, text):
# Return executables matching 'text'
for dir in os.environ.get('PATH').split(':'):
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 entry function
completer.completer = CommandCompleter()
# Enable TAB completion
completer.parse_and_bind('TAB: complete')
command = input('command> ')
print('You typed:', command)
if __name__ == '__main__':
main()
Generator Factory¶
The generator()
factory provides a simple way to support this
protocol. It is typically used as a decorator but can be passed any
callable to create a completion entry function.
You can run this example with python -m rl.examples.factory
.
# Complete system commands
import os
from rl import completer
from rl import generator
from rl import print_exc
@print_exc
@generator
def complete_command(text):
# Return executables matching 'text'
for dir in os.environ.get('PATH').split(':'):
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 entry function
completer.completer = complete_command
# Enable TAB completion
completer.parse_and_bind('TAB: complete')
command = input('command> ')
print('You typed:', command)
if __name__ == '__main__':
main()
Multiple Completions¶
The completion entry function is often a dispatcher,
forwarding calls to more specific completion functions depending on
position and format of the completion word.
You can run this example with python -m rl.examples.email
.
# Complete email addresses
from rl import completer
from rl import completion
from rl import generator
from rl import print_exc
from rl.utils import DEFAULT_DELIMS
def complete_hostname(text):
# Search /etc/hosts for matching hostnames
with open('/etc/hosts', 'rt') as f:
lines = f.readlines()
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
@generator
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():
# Configure word break characters
completer.word_break_characters = DEFAULT_DELIMS.replace('-', '')
# Configure special prefixes
completer.special_prefixes = '@'
# Set the completion entry function
completer.completer = complete_email
# Enable TAB completion
completer.parse_and_bind('TAB: complete')
email = input('email> ')
print('You typed:', email)
if __name__ == '__main__':
main()
Filename Completion¶
Filename completion is readline’s party trick. It is also the most complex
feature, requiring various parts of readline to be set up.
You can run this example with python -m rl.examples.filename
.
# Complete filenames
import sys
import unicodedata
from rl import completer
from rl import completion
from rl import generator
from rl import print_exc
@print_exc
def char_is_quoted(text, index):
# Return True if the character at index is quoted
return index > 0 and text[index-1] == '\\'
@print_exc
def quote_filename(text, single_match, quote_char):
# Backslash-quote characters in text
if quote_char == "'":
pass
elif quote_char == '"':
for c in '\\"$`\n':
text = text.replace(c, '\\'+c)
else:
for c in completer.filename_quote_characters:
text = text.replace(c, '\\'+c)
return text
@print_exc
def dequote_filename(text, quote_char):
# Backslash-dequote characters in text
if quote_char == "'":
pass
elif quote_char == '"':
for c in '\\"$`\n':
text = text.replace('\\'+c, c)
else:
for c in completer.filename_quote_characters:
text = text.replace('\\'+c, c)
return text
@print_exc
def rewrite_filename(text):
# Normalize decomposed UTF-8 received from HFS Plus
return unicodedata.normalize('NFC', text)
@print_exc
@generator
def complete_filename(text):
matches = []
# Complete usernames
if text.startswith('~') and '/' not in text:
matches = completion.complete_username(text)
# Complete filenames
if not matches:
matches = completion.complete_filename(text)
return matches
def main():
# Configure quote characters
completer.quote_characters = '\'"'
completer.word_break_characters = ' \t\n"\'><;|&=(:'
completer.filename_quote_characters = '\\ \t\n"\'@><;|&=()#$`?*[!:{'
# Configure quoting functions
completer.char_is_quoted_function = char_is_quoted
completer.filename_quoting_function = quote_filename
completer.filename_dequoting_function = dequote_filename
# Configure Unicode converter on Mac OS X
if sys.platform == "darwin":
completer.filename_rewrite_hook = rewrite_filename
# Set the completion entry function
completer.completer = complete_filename
# Enable TAB completion
completer.parse_and_bind('TAB: complete')
filename = input('file> ')
print('You typed:', filename)
if __name__ == '__main__':
main()
Display Matches Hook¶
The display_matches_hook
is called whenever matches need
to be displayed.
# Python implementation of the default display_matches_hook
import sys
from rl import completer
from rl import completion
from rl import readline
from rl import print_exc
@print_exc
def display_matches_hook(substitution, matches, longest_match_length):
num_matches = len(matches)
if num_matches >= completer.query_items > 0:
sys.stdout.write('\nDisplay all %d possibilities? (y or n)' % num_matches)
sys.stdout.flush()
while True:
c = readline.read_key()
if c in 'yY\x20': # SPACEBAR
break
if c in 'nN\x7f': # RUBOUT
sys.stdout.write('\n')
completion.redisplay(force=True)
return
completion.display_match_list(substitution, matches, longest_match_length)
completion.redisplay(force=True)