diff options
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/python/_shellcomp.py')
-rwxr-xr-x | lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/python/_shellcomp.py | 668 |
1 files changed, 0 insertions, 668 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/python/_shellcomp.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/python/_shellcomp.py deleted file mode 100755 index b7768027..00000000 --- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/python/_shellcomp.py +++ /dev/null @@ -1,668 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_shellcomp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -No public APIs are provided by this module. Internal use only. - -This module implements dynamic tab-completion for any command that uses -twisted.python.usage. Currently, only zsh is supported. Bash support may -be added in the future. - -Maintainer: Eric P. Mangold - twisted AT teratorn DOT org - -In order for zsh completion to take place the shell must be able to find an -appropriate "stub" file ("completion function") that invokes this code and -displays the results to the user. - -The stub used for Twisted commands is in the file C{twisted-completion.zsh}, -which is also included in the official Zsh distribution at -C{Completion/Unix/Command/_twisted}. Use this file as a basis for completion -functions for your own commands. You should only need to change the first line -to something like C{#compdef mycommand}. - -The main public documentation exists in the L{twisted.python.usage.Options} -docstring, the L{twisted.python.usage.Completions} docstring, and the -Options howto. -""" -import itertools, getopt, inspect - -from twisted.python import reflect, util, usage - - - -def shellComplete(config, cmdName, words, shellCompFile): - """ - Perform shell completion. - - A completion function (shell script) is generated for the requested - shell and written to C{shellCompFile}, typically C{stdout}. The result - is then eval'd by the shell to produce the desired completions. - - @type config: L{twisted.python.usage.Options} - @param config: The L{twisted.python.usage.Options} instance to generate - completions for. - - @type cmdName: C{str} - @param cmdName: The name of the command we're generating completions for. - In the case of zsh, this is used to print an appropriate - "#compdef $CMD" line at the top of the output. This is - not necessary for the functionality of the system, but it - helps in debugging, since the output we produce is properly - formed and may be saved in a file and used as a stand-alone - completion function. - - @type words: C{list} of C{str} - @param words: The raw command-line words passed to use by the shell - stub function. argv[0] has already been stripped off. - - @type shellCompFile: C{file} - @param shellCompFile: The file to write completion data to. - """ - # shellName is provided for forward-compatibility. It is not used, - # since we currently only support zsh. - shellName, position = words[-1].split(":") - position = int(position) - # zsh gives the completion position ($CURRENT) as a 1-based index, - # and argv[0] has already been stripped off, so we subtract 2 to - # get the real 0-based index. - position -= 2 - cWord = words[position] - - # since the user may hit TAB at any time, we may have been called with an - # incomplete command-line that would generate getopt errors if parsed - # verbatim. However, we must do *some* parsing in order to determine if - # there is a specific subcommand that we need to provide completion for. - # So, to make the command-line more sane we work backwards from the - # current completion position and strip off all words until we find one - # that "looks" like a subcommand. It may in fact be the argument to a - # normal command-line option, but that won't matter for our purposes. - while position >= 1: - if words[position - 1].startswith("-"): - position -= 1 - else: - break - words = words[:position] - - subCommands = getattr(config, 'subCommands', None) - if subCommands: - # OK, this command supports sub-commands, so lets see if we have been - # given one. - - # If the command-line arguments are not valid then we won't be able to - # sanely detect the sub-command, so just generate completions as if no - # sub-command was found. - args = None - try: - opts, args = getopt.getopt(words, - config.shortOpt, config.longOpt) - except getopt.error: - pass - - if args: - # yes, we have a subcommand. Try to find it. - for (cmd, short, parser, doc) in config.subCommands: - if args[0] == cmd or args[0] == short: - subOptions = parser() - subOptions.parent = config - - gen = ZshSubcommandBuilder(subOptions, config, cmdName, - shellCompFile) - gen.write() - return - - # sub-command not given, or did not match any knowns sub-command names - genSubs = True - if cWord.startswith("-"): - # optimization: if the current word being completed starts - # with a hyphen then it can't be a sub-command, so skip - # the expensive generation of the sub-command list - genSubs = False - gen = ZshBuilder(config, cmdName, shellCompFile) - gen.write(genSubs=genSubs) - else: - gen = ZshBuilder(config, cmdName, shellCompFile) - gen.write() - - - -class SubcommandAction(usage.Completer): - def _shellCode(self, optName, shellType): - if shellType == usage._ZSH: - return '*::subcmd:->subcmd' - raise NotImplementedError("Unknown shellType %r" % (shellType,)) - - - -class ZshBuilder(object): - """ - Constructs zsh code that will complete options for a given usage.Options - instance, possibly including a list of subcommand names. - - Completions for options to subcommands won't be generated because this - class will never be used if the user is completing options for a specific - subcommand. (See L{ZshSubcommandBuilder} below) - - @type options: L{twisted.python.usage.Options} - @ivar options: The L{twisted.python.usage.Options} instance defined for this - command. - - @type cmdName: C{str} - @ivar cmdName: The name of the command we're generating completions for. - - @type file: C{file} - @ivar file: The C{file} to write the completion function to. - """ - def __init__(self, options, cmdName, file): - self.options = options - self.cmdName = cmdName - self.file = file - - - def write(self, genSubs=True): - """ - Generate the completion function and write it to the output file - @return: C{None} - - @type genSubs: C{bool} - @param genSubs: Flag indicating whether or not completions for the list - of subcommand should be generated. Only has an effect - if the C{subCommands} attribute has been defined on the - L{twisted.python.usage.Options} instance. - """ - if genSubs and getattr(self.options, 'subCommands', None) is not None: - gen = ZshArgumentsGenerator(self.options, self.cmdName, self.file) - gen.extraActions.insert(0, SubcommandAction()) - gen.write() - self.file.write('local _zsh_subcmds_array\n_zsh_subcmds_array=(\n') - for (cmd, short, parser, desc) in self.options.subCommands: - self.file.write('"%s:%s"\n' % (cmd, desc)) - self.file.write(")\n\n") - self.file.write('_describe "sub-command" _zsh_subcmds_array\n') - else: - gen = ZshArgumentsGenerator(self.options, self.cmdName, self.file) - gen.write() - - - -class ZshSubcommandBuilder(ZshBuilder): - """ - Constructs zsh code that will complete options for a given usage.Options - instance, and also for a single sub-command. This will only be used in - the case where the user is completing options for a specific subcommand. - - @type subOptions: L{twisted.python.usage.Options} - @ivar subOptions: The L{twisted.python.usage.Options} instance defined for - the sub command. - """ - def __init__(self, subOptions, *args): - self.subOptions = subOptions - ZshBuilder.__init__(self, *args) - - - def write(self): - """ - Generate the completion function and write it to the output file - @return: C{None} - """ - gen = ZshArgumentsGenerator(self.options, self.cmdName, self.file) - gen.extraActions.insert(0, SubcommandAction()) - gen.write() - - gen = ZshArgumentsGenerator(self.subOptions, self.cmdName, self.file) - gen.write() - - - -class ZshArgumentsGenerator(object): - """ - Generate a call to the zsh _arguments completion function - based on data in a usage.Options instance - - @type options: L{twisted.python.usage.Options} - @ivar options: The L{twisted.python.usage.Options} instance to generate for - - @type cmdName: C{str} - @ivar cmdName: The name of the command we're generating completions for. - - @type file: C{file} - @ivar file: The C{file} to write the completion function to - - The following non-constructor variables are populated by this class - with data gathered from the C{Options} instance passed in, and its - base classes. - - @type descriptions: C{dict} - @ivar descriptions: A dict mapping long option names to alternate - descriptions. When this variable is defined, the descriptions - contained here will override those descriptions provided in the - optFlags and optParameters variables. - - @type multiUse: C{list} - @ivar multiUse: An iterable containing those long option names which may - appear on the command line more than once. By default, options will - only be completed one time. - - @type mutuallyExclusive: C{list} of C{tuple} - @ivar mutuallyExclusive: A sequence of sequences, with each sub-sequence - containing those long option names that are mutually exclusive. That is, - those options that cannot appear on the command line together. - - @type optActions: C{dict} - @ivar optActions: A dict mapping long option names to shell "actions". - These actions define what may be completed as the argument to the - given option, and should be given as instances of - L{twisted.python.usage.Completer}. - - Callables may instead be given for the values in this dict. The - callable should accept no arguments, and return a C{Completer} - instance used as the action. - - @type extraActions: C{list} of C{twisted.python.usage.Completer} - @ivar extraActions: Extra arguments are those arguments typically - appearing at the end of the command-line, which are not associated - with any particular named option. That is, the arguments that are - given to the parseArgs() method of your usage.Options subclass. - """ - def __init__(self, options, cmdName, file): - self.options = options - self.cmdName = cmdName - self.file = file - - self.descriptions = {} - self.multiUse = set() - self.mutuallyExclusive = [] - self.optActions = {} - self.extraActions = [] - - for cls in reversed(inspect.getmro(options.__class__)): - data = getattr(cls, 'compData', None) - if data: - self.descriptions.update(data.descriptions) - self.optActions.update(data.optActions) - self.multiUse.update(data.multiUse) - - self.mutuallyExclusive.extend(data.mutuallyExclusive) - - # I don't see any sane way to aggregate extraActions, so just - # take the one at the top of the MRO (nearest the `options' - # instance). - if data.extraActions: - self.extraActions = data.extraActions - - aCL = reflect.accumulateClassList - aCD = reflect.accumulateClassDict - - optFlags = [] - optParams = [] - - aCL(options.__class__, 'optFlags', optFlags) - aCL(options.__class__, 'optParameters', optParams) - - for i, optList in enumerate(optFlags): - if len(optList) != 3: - optFlags[i] = util.padTo(3, optList) - - for i, optList in enumerate(optParams): - if len(optList) != 5: - optParams[i] = util.padTo(5, optList) - - - self.optFlags = optFlags - self.optParams = optParams - - paramNameToDefinition = {} - for optList in optParams: - paramNameToDefinition[optList[0]] = optList[1:] - self.paramNameToDefinition = paramNameToDefinition - - flagNameToDefinition = {} - for optList in optFlags: - flagNameToDefinition[optList[0]] = optList[1:] - self.flagNameToDefinition = flagNameToDefinition - - allOptionsNameToDefinition = {} - allOptionsNameToDefinition.update(paramNameToDefinition) - allOptionsNameToDefinition.update(flagNameToDefinition) - self.allOptionsNameToDefinition = allOptionsNameToDefinition - - self.addAdditionalOptions() - - # makes sure none of the Completions metadata references - # option names that don't exist. (great for catching typos) - self.verifyZshNames() - - self.excludes = self.makeExcludesDict() - - - def write(self): - """ - Write the zsh completion code to the file given to __init__ - @return: C{None} - """ - self.writeHeader() - self.writeExtras() - self.writeOptions() - self.writeFooter() - - - def writeHeader(self): - """ - This is the start of the code that calls _arguments - @return: C{None} - """ - self.file.write('#compdef %s\n\n' - '_arguments -s -A "-*" \\\n' % (self.cmdName,)) - - - def writeOptions(self): - """ - Write out zsh code for each option in this command - @return: C{None} - """ - optNames = self.allOptionsNameToDefinition.keys() - optNames.sort() - for longname in optNames: - self.writeOpt(longname) - - - def writeExtras(self): - """ - Write out completion information for extra arguments appearing on the - command-line. These are extra positional arguments not associated - with a named option. That is, the stuff that gets passed to - Options.parseArgs(). - - @return: C{None} - - @raises: ValueError: if C{Completer} with C{repeat=True} is found and - is not the last item in the C{extraActions} list. - """ - for i, action in enumerate(self.extraActions): - descr = "" - if action._descr: - descr = action._descr - # a repeatable action must be the last action in the list - if action._repeat and i != len(self.extraActions) - 1: - raise ValueError("Completer with repeat=True must be " - "last item in Options.extraActions") - self.file.write(escape(action._shellCode('', usage._ZSH))) - self.file.write(' \\\n') - - - def writeFooter(self): - """ - Write the last bit of code that finishes the call to _arguments - @return: C{None} - """ - self.file.write('&& return 0\n') - - - def verifyZshNames(self): - """ - Ensure that none of the option names given in the metadata are typoed - @return: C{None} - @raise ValueError: Raised if unknown option names have been found. - """ - def err(name): - raise ValueError("Unknown option name \"%s\" found while\n" - "examining Completions instances on %s" % ( - name, self.options)) - - for name in itertools.chain(self.descriptions, self.optActions, - self.multiUse): - if name not in self.allOptionsNameToDefinition: - err(name) - - for seq in self.mutuallyExclusive: - for name in seq: - if name not in self.allOptionsNameToDefinition: - err(name) - - - def excludeStr(self, longname, buildShort=False): - """ - Generate an "exclusion string" for the given option - - @type longname: C{str} - @param longname: The long option name (e.g. "verbose" instead of "v") - - @type buildShort: C{bool} - @param buildShort: May be True to indicate we're building an excludes - string for the short option that correspondes to the given long opt. - - @return: The generated C{str} - """ - if longname in self.excludes: - exclusions = self.excludes[longname].copy() - else: - exclusions = set() - - # if longname isn't a multiUse option (can't appear on the cmd line more - # than once), then we have to exclude the short option if we're - # building for the long option, and vice versa. - if longname not in self.multiUse: - if buildShort is False: - short = self.getShortOption(longname) - if short is not None: - exclusions.add(short) - else: - exclusions.add(longname) - - if not exclusions: - return '' - - strings = [] - for optName in exclusions: - if len(optName) == 1: - # short option - strings.append("-" + optName) - else: - strings.append("--" + optName) - strings.sort() # need deterministic order for reliable unit-tests - return "(%s)" % " ".join(strings) - - - def makeExcludesDict(self): - """ - @return: A C{dict} that maps each option name appearing in - self.mutuallyExclusive to a list of those option names that is it - mutually exclusive with (can't appear on the cmd line with). - """ - - #create a mapping of long option name -> single character name - longToShort = {} - for optList in itertools.chain(self.optParams, self.optFlags): - if optList[1] != None: - longToShort[optList[0]] = optList[1] - - excludes = {} - for lst in self.mutuallyExclusive: - for i, longname in enumerate(lst): - tmp = set(lst[:i] + lst[i+1:]) - for name in tmp.copy(): - if name in longToShort: - tmp.add(longToShort[name]) - - if longname in excludes: - excludes[longname] = excludes[longname].union(tmp) - else: - excludes[longname] = tmp - return excludes - - - def writeOpt(self, longname): - """ - Write out the zsh code for the given argument. This is just part of the - one big call to _arguments - - @type longname: C{str} - @param longname: The long option name (e.g. "verbose" instead of "v") - - @return: C{None} - """ - if longname in self.flagNameToDefinition: - # It's a flag option. Not one that takes a parameter. - longField = "--%s" % longname - else: - longField = "--%s=" % longname - - short = self.getShortOption(longname) - if short != None: - shortField = "-" + short - else: - shortField = '' - - descr = self.getDescription(longname) - descriptionField = descr.replace("[", "\[") - descriptionField = descriptionField.replace("]", "\]") - descriptionField = '[%s]' % descriptionField - - actionField = self.getAction(longname) - if longname in self.multiUse: - multiField = '*' - else: - multiField = '' - - longExclusionsField = self.excludeStr(longname) - - if short: - #we have to write an extra line for the short option if we have one - shortExclusionsField = self.excludeStr(longname, buildShort=True) - self.file.write(escape('%s%s%s%s%s' % (shortExclusionsField, - multiField, shortField, descriptionField, actionField))) - self.file.write(' \\\n') - - self.file.write(escape('%s%s%s%s%s' % (longExclusionsField, - multiField, longField, descriptionField, actionField))) - self.file.write(' \\\n') - - - def getAction(self, longname): - """ - Return a zsh "action" string for the given argument - @return: C{str} - """ - if longname in self.optActions: - if callable(self.optActions[longname]): - action = self.optActions[longname]() - else: - action = self.optActions[longname] - return action._shellCode(longname, usage._ZSH) - - if longname in self.paramNameToDefinition: - return ':%s:_files' % (longname,) - return '' - - - def getDescription(self, longname): - """ - Return the description to be used for this argument - @return: C{str} - """ - #check if we have an alternate descr for this arg, and if so use it - if longname in self.descriptions: - return self.descriptions[longname] - - #otherwise we have to get it from the optFlags or optParams - try: - descr = self.flagNameToDefinition[longname][1] - except KeyError: - try: - descr = self.paramNameToDefinition[longname][2] - except KeyError: - descr = None - - if descr is not None: - return descr - - # let's try to get it from the opt_foo method doc string if there is one - longMangled = longname.replace('-', '_') # this is what t.p.usage does - obj = getattr(self.options, 'opt_%s' % longMangled, None) - if obj is not None: - descr = descrFromDoc(obj) - if descr is not None: - return descr - - return longname # we really ought to have a good description to use - - - def getShortOption(self, longname): - """ - Return the short option letter or None - @return: C{str} or C{None} - """ - optList = self.allOptionsNameToDefinition[longname] - return optList[0] or None - - - def addAdditionalOptions(self): - """ - Add additional options to the optFlags and optParams lists. - These will be defined by 'opt_foo' methods of the Options subclass - @return: C{None} - """ - methodsDict = {} - reflect.accumulateMethods(self.options, methodsDict, 'opt_') - methodToShort = {} - for name in methodsDict.copy(): - if len(name) == 1: - methodToShort[methodsDict[name]] = name - del methodsDict[name] - - for methodName, methodObj in methodsDict.items(): - longname = methodName.replace('_', '-') # t.p.usage does this - # if this option is already defined by the optFlags or - # optParameters then we don't want to override that data - if longname in self.allOptionsNameToDefinition: - continue - - descr = self.getDescription(longname) - - short = None - if methodObj in methodToShort: - short = methodToShort[methodObj] - - reqArgs = methodObj.im_func.func_code.co_argcount - if reqArgs == 2: - self.optParams.append([longname, short, None, descr]) - self.paramNameToDefinition[longname] = [short, None, descr] - self.allOptionsNameToDefinition[longname] = [short, None, descr] - else: - # reqArgs must equal 1. self.options would have failed - # to instantiate if it had opt_ methods with bad signatures. - self.optFlags.append([longname, short, descr]) - self.flagNameToDefinition[longname] = [short, descr] - self.allOptionsNameToDefinition[longname] = [short, None, descr] - - - -def descrFromDoc(obj): - """ - Generate an appropriate description from docstring of the given object - """ - if obj.__doc__ is None or obj.__doc__.isspace(): - return None - - lines = [x.strip() for x in obj.__doc__.split("\n") - if x and not x.isspace()] - return " ".join(lines) - - - -def escape(x): - """ - Shell escape the given string - - Implementation borrowed from now-deprecated commands.mkarg() in the stdlib - """ - if '\'' not in x: - return '\'' + x + '\'' - s = '"' - for c in x: - if c in '\\$"`': - s = s + '\\' - s = s + c - s = s + '"' - return s - |