Source code for dataprocessor.gencompletion

# coding=utf-8
import argparse
from .exception import DataProcessorError


def _escape_strings(strings):
    r"""escape to squarebracket and doublequote.

    >>> print(_escape_strings("hoge"))
    hoge
    >>> print(_escape_strings("[hoge"))
    \[hoge
    >>> print(_escape_strings("hoge]"))
    hoge\]
    >>> print(_escape_strings("[hoge]"))
    \[hoge\]
    >>> print(_escape_strings('[ho"ge]'))
    \[ho\"ge\]
    >>> print(_escape_strings("ho'ge"))
    ho'\''ge

    """
    target_chars = "[]\"`"
    ret = []
    if strings is None:
        return ""
    for string in strings:
        if string in target_chars:
            string = '\\' + string
        if string is "'":
            string = "'\\''"
        ret.append(string)
    return "".join(ret)


def _normalize_strings(strings):
    return ' '.join(_escape_strings(strings).split())


[docs]class CompletionGenerator(object): """Generator of Zsh Completion Function. Since this class uses some inner function of argparse, this does not work well in some version of argparse. This is tested only on argparse of python 2.7.5. Attributes ---------- command_name : str command name of completion parser : argparse.ArgumentParser parser of command Methods ------- get() returns string of Zsh completion function """ def __init__(self, commandname, parser): self.commandname = commandname self.parser = parser def _main_function(self): ret = [] ret.append("") ret.append("function _%s (){" % self.commandname) ret.append(" typeset -A opt_args") ret.append(" local context state line\n") ret.append(" integer int=1\n") ret.append(" _arguments -w -s -S \\") actions = self.parser._actions for action in actions: opt_str = self._get_option_or_choice_string(action) if opt_str: ret.append(" " + opt_str) if self._get_subparser(): ret.append(" ':subcmd:->subcmd' \\") ret.append( " '*::subcmd-options-or-args:->subcmd-options-or-args'") casestring = """ case $state in subcmd) _%s_subcmd_list && ret=0 ;; subcmd-options-or-args) local curcontext=$curcontext curcontext=${curcontext%%:*:*}:%s-$words[1]: if (( $+functions[_%s-$words[1]] )); then _call_function ret _%s-$words[1] else _files && ret=0 fi ;; esac """ % (self.commandname, self.commandname, self.commandname, self.commandname) ret.append(casestring) else: ret.append(" '*::arguments:_files'") ret.append(" ret=0") ret.append(" return ret") ret.append("}\n") return "\n".join(ret) def _subcmd_function(self, subcmd_name): ret = [] ret.append("") ret.append("function _%s-%s (){" % (self.commandname, subcmd_name)) ret.append(" typeset -A opt_args") ret.append(" local context state line\n") ret.append(" _arguments -w -s -S \\") subparser = self._get_subparser() parser = subparser.choices[subcmd_name] actions = parser._actions for action in actions: opt_str = self._get_option_or_choice_string(action) if opt_str: ret.append(" " + opt_str) ret.append( " '*::arguments:_files'") ret.append("}\n") return "\n".join(ret) def _subcmd_list_function(self): prefmt = """ function _%s_subcmd_list() { local -a subcmd_list subcmd_list=( """ % self.commandname aftfmt = """ ) _describe -t subcmd 'subcommand list' subcmd_list && return } """ # extract subcmd name and the help subcmds_with_help = {} subparser = self._get_subparser() for action in subparser._choices_actions: subcmds_with_help[action.dest] = _normalize_strings(action.help) # for subcmd without help for subcmdname in self._get_subcmd_list(): if subcmdname not in subcmds_with_help: subcmds_with_help[subcmdname] = "" body = [] for name, help in subcmds_with_help.items(): body.append("%s:'%s'" % (name, help)) return prefmt + "\n ".join(body) + aftfmt def _get_subcmd_list(self): return self._get_subparser().choices.keys() def _get_option_string(self, action): argfmt = "" if not action.nargs and isinstance(action, argparse._StoreAction): argfmt = ": :_files" if isinstance(action.nargs, int) and action.nargs > 0: argfmt = ": :_files" * action.nargs if action.nargs == '?': argfmt = ":: :_files" if action.nargs == "+": # 10 is hard coding. argfmt = ": :_files" + ":: :_files" * 10 if action.nargs == '*': # 10 is hard coding. argfmt = ":: :_files" * 10 if action.choices: argfmt = self._get_choice_string(action) # for existing both long and short option if len(action.option_strings) == 2: short_opt = action.option_strings[0] long_opt = action.option_strings[1] help = _normalize_strings(action.help) if help: help = "[" + help + "]" return "'(%s %s)'{%s,%s}'%s%s' \\" % ( short_opt, long_opt, short_opt, long_opt, help, argfmt) # for one option if len(action.option_strings) == 1: help = _normalize_strings(action.help) if help: help = "[" + help + "]" return "'(%s)%s%s%s' \\" % (action.option_strings[0], action.option_strings[0], help, argfmt) def _get_choice_string(self, action): return "': :(%s)' \\" % (" ".join(action.choices)) def _get_option_or_choice_string(self, action): if len(action.option_strings) == 0 and \ action.choices and \ not isinstance(action, argparse._SubParsersAction): return self._get_choice_string(action) else: return self._get_option_string(action) # for choice argument def _get_subparser(self): ret = [] for action in self.parser._actions: if isinstance(action, argparse._SubParsersAction): ret.append(action) if len(ret) > 1: raise DataProcessorError( "Does not support two or more subparsers") if ret: return ret[0] else: return None
[docs] def get(self): """Get zsh completion function string.""" # func = getattr(self, "_get_%s_format" % self.output_format) # return func() header = "#compdef %s" % self.commandname footer = "_%s" % self.commandname body = self._main_function() subcmd_functions = [] if self._get_subparser(): subcmd_functions = [ self._subcmd_function(subcmdname) for subcmdname in self._get_subcmd_list()] body = "\n".join(subcmd_functions) + \ self._subcmd_list_function() + body body = header + body + footer return body