1#!/usr/bin/env python
2# -*- coding:utf-8 -*-
3
4from __future__ import print_function, absolute_import
5
6import six
7
8from click import ParamType
9from enum import Enum
10
11from click_completion.core import completion_configuration, get_code, install, shells, resolve_ctx, get_choices, \
12    startswith, Shell
13from click_completion.lib import get_auto_shell
14from click_completion.patch import patch as _patch
15
16__version__ = '0.5.2'
17
18_initialized = False
19
20
21def init(complete_options=False, match_incomplete=None):
22    """Initialize the enhanced click completion
23
24    Parameters
25    ----------
26    complete_options : bool
27        always complete the options, even when the user hasn't typed a first dash (Default value = False)
28    match_incomplete : func
29        a function with two parameters choice and incomplete. Must return True
30        if incomplete is a correct match for choice, False otherwise.
31    """
32    global _initialized
33    if not _initialized:
34        _patch()
35        completion_configuration.complete_options = complete_options
36        if match_incomplete is not None:
37            completion_configuration.match_incomplete = match_incomplete
38        _initialized = True
39
40
41class DocumentedChoice(ParamType):
42    """The choice type allows a value to be checked against a fixed set of
43    supported values.  All of these values have to be strings. Each value may
44    be associated to a help message that will be display in the error message
45    and during the completion.
46
47    Parameters
48    ----------
49    choices : dict or Enum
50        A dictionary with the possible choice as key, and the corresponding help string as value
51    """
52    name = 'choice'
53
54    def __init__(self, choices):
55        if isinstance(choices, Enum):
56            self.choices = dict((choice.name, choice.value) for choice in choices)
57        else:
58            self.choices = dict(choices)
59
60    def get_metavar(self, param):
61        return '[%s]' % '|'.join(self.choices.keys())
62
63    def get_missing_message(self, param):
64        formated_choices = ['{:<12} {}'.format(k, self.choices[k] or '') for k in sorted(self.choices.keys())]
65        return 'Choose from\n  ' + '\n  '.join(formated_choices)
66
67    def convert(self, value, param, ctx):
68        # Exact match
69        if value in self.choices:
70            return value
71
72        # Match through normalization
73        if ctx is not None and \
74           ctx.token_normalize_func is not None:
75            value = ctx.token_normalize_func(value)
76            for choice in self.choices:
77                if ctx.token_normalize_func(choice) == value:
78                    return choice
79
80        self.fail('invalid choice: %s. %s' %
81                  (value, self.get_missing_message(param)), param, ctx)
82
83    def __repr__(self):
84        return 'DocumentedChoice(%r)' % list(self.choices.keys())
85
86    def complete(self, ctx, incomplete):
87        match = completion_configuration.match_incomplete
88        return [(c, v) for c, v in six.iteritems(self.choices) if match(c, incomplete)]
89