Source code for pypsi.completers
#
# Copyright (c) 2015, Adam Meily <meily.adam@gmail.com>
# Pypsi - https://github.com/ameily/pypsi
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
'''
Builtin tab completion functions.
'''
from pypsi.os import path_completer # noqa
[docs]def command_completer(parser, shell, args, prefix, case_sensitive=False):
'''
Completion function that can tab complete options, options' values,
and positional parameters. Shell, args, and prefix should be the same
params as passed to the :meth:`pypsi.core.Command.complete` function
:param parser: A PypsiArgParser object or an action object returned
from :meth:`PypsiArgParser.add_subparsers`
:param pypsi.shell.Shell shell: The current Shell object
:param list args: The full list of current CLI args
:param str prefix: The partial arg being completed
:param bool case_sensitive: Whether the prefix will be completed
in a case sensitive manner
:return list: A list of possible options based on the prefix
'''
cmd_parser = None
offset = 0
completions = []
ops = []
if hasattr(parser, 'choices'):
# Is a subparser, get all possible subcommands
sub_commands = [key for key in parser.choices]
if len(args) == 1:
# User is typing sub command
completions.extend([x for x in sub_commands
if x.startswith(prefix) or not prefix])
return sorted(completions)
# Get the command parser for the current subcommand
cmd_parser = parser.choices.get(args[0], None)
offset = 1 # Set an offset so the subcmd is not counted in index
else:
# Is a PyPsiArgumentParser
cmd_parser = parser
# Get the last complete argument - should always be the second to last
# ['-s', 'tes<cursor>'] --or-- ['-s', 'test', '<cursor>']
last_arg = args[-2] if len(args) >= 2 else ''
if not cmd_parser:
return []
# Try to get an option's callback - returns None if no option or cb exists
cb = cmd_parser.get_option_completer(last_arg)
if callable(cb) and cmd_parser.has_value(last_arg):
# If the option has a callback defined and has a value
ops = cb(shell, args, prefix)
elif prefix.startswith('-'):
# Complete the optional arguments
ops = cmd_parser.get_options()
else:
# Else complete the positional args
# Get the current POSITIONAL index
# This does NOT include any optional (-v --verbose OPTION) arguments
index = cmd_parser.get_positional_arg_index(args)
# Get the callback for the current positional parameter
# Index includes subcmd if there is one, so subtract offset
# Ex: 'cmd subcmd <cursor>' would have two args: ['subcmd', ''] but
# 'cmd <cursor> would have one arg: ['']
# Pass the params index here - if you want the first pos param, pass 0
cb = cmd_parser.get_positional_completer(index - offset)
if callable(cb):
ops = cb(shell, args, prefix)
if case_sensitive:
completions.extend([o for o in ops
if not prefix or o.startswith(prefix)])
else:
completions.extend([o for o in ops if not prefix
or o.lower().startswith(prefix.lower())])
return sorted(completions)
[docs]def choice_completer(choices, case_sensitive=False):
'''
Tab complete from a list of choices.
:param list choices: the list of choices
:param bool case_sensitive: whether the choices are case sensitive
'''
def complete(shell, args, prefix):
r = []
for choice in choices:
if choice.startswith(prefix if case_sensitive else prefix.lower()):
r.append(choice)
return r
return complete