1# -*- coding: utf-8 -*-
2
3"""
4clint.colored
5~~~~~~~~~~~~~
6
7This module provides a simple and elegant wrapper for colorama.
8
9"""
10
11import os
12import re
13import sys
14
15from pipenv.vendor import shellingham
16from pipenv.vendor import colorama
17
18PY3 = sys.version_info[0] >= 3
19
20__all__ = (
21    "red",
22    "green",
23    "yellow",
24    "blue",
25    "black",
26    "magenta",
27    "cyan",
28    "white",
29    "normal",
30    "clean",
31    "disable",
32)
33
34COLORS = __all__[:-2]
35
36is_ipython = "get_ipython" in dir()
37
38if (
39    os.environ.get("CMDER_ROOT")
40    or os.environ.get("VSCODE_PID")
41    or os.environ.get("TERM_PROGRAM") == "Hyper"
42    or "VSCODE_CWD" in os.environ
43):
44    is_native_powershell = False
45else:
46    is_native_powershell = True
47
48try:
49    is_powershell = "powershell" in shellingham.detect_shell()[0]
50except shellingham.ShellDetectionFailure:
51    is_powershell = False
52
53DISABLE_COLOR = False
54REPLACE_BLUE = False
55if is_ipython:
56    """when ipython is fired lot of variables like _oh, etc are used.
57       There are so many ways to find current python interpreter is ipython.
58       get_ipython is easiest is most appealing for readers to understand.
59    """
60    DISABLE_COLOR = True
61elif is_powershell and is_native_powershell:
62    REPLACE_BLUE = True
63
64
65class ColoredString(object):
66    """Enhanced string for __len__ operations on Colored output."""
67
68    def __init__(self, color, s, always_color=False, bold=False):
69        super(ColoredString, self).__init__()
70        if not PY3 and isinstance(s, unicode):
71            self.s = s.encode("utf-8")
72        else:
73            self.s = s
74
75        if color == "BLUE" and REPLACE_BLUE:
76            color = "MAGENTA"
77        self.color = color
78        self.always_color = always_color
79        self.bold = bold
80        if os.environ.get("PIPENV_FORCE_COLOR"):
81            self.always_color = True
82
83    def __getattr__(self, att):
84        def func_help(*args, **kwargs):
85            result = getattr(self.s, att)(*args, **kwargs)
86            try:
87                is_result_string = isinstance(result, basestring)
88            except NameError:
89                is_result_string = isinstance(result, str)
90            if is_result_string:
91                return self._new(result)
92            elif isinstance(result, list):
93                return [self._new(x) for x in result]
94            else:
95                return result
96
97        return func_help
98
99    @property
100    def color_str(self):
101        style = "BRIGHT" if self.bold else "NORMAL"
102        c = "%s%s%s%s%s" % (
103            getattr(colorama.Fore, self.color),
104            getattr(colorama.Style, style),
105            self.s,
106            colorama.Fore.RESET,
107            getattr(colorama.Style, "NORMAL"),
108        )
109
110        if self.always_color:
111            return c
112        elif sys.stdout.isatty() and not DISABLE_COLOR:
113            return c
114        else:
115            return self.s
116
117    def __len__(self):
118        return len(self.s)
119
120    def __repr__(self):
121        return "<%s-string: '%s'>" % (self.color, self.s)
122
123    def __unicode__(self):
124        value = self.color_str
125        if isinstance(value, bytes):
126            return value.decode("utf8")
127        return value
128
129    if PY3:
130        __str__ = __unicode__
131    else:
132
133        def __str__(self):
134            return self.color_str
135
136    def __iter__(self):
137        return iter(self.color_str)
138
139    def __add__(self, other):
140        return str(self.color_str) + str(other)
141
142    def __radd__(self, other):
143        return str(other) + str(self.color_str)
144
145    def __mul__(self, other):
146        return self.color_str * other
147
148    def _new(self, s):
149        return ColoredString(self.color, s)
150
151
152def clean(s):
153    strip = re.compile(
154        "([^-_a-zA-Z0-9!@#%&=,/'\";:~`\$\^\*\(\)\+\[\]\.\{\}\|\?\<\>\\]+|[^\s]+)"
155    )
156    txt = strip.sub("", str(s))
157
158    strip = re.compile(r"\[\d+m")
159    txt = strip.sub("", txt)
160
161    return txt
162
163
164def normal(string, always=False, bold=False):
165    return ColoredString("RESET", string, always_color=always, bold=bold)
166
167
168def black(string, always=False, bold=False):
169    return ColoredString("BLACK", string, always_color=always, bold=bold)
170
171
172def red(string, always=False, bold=False):
173    return ColoredString("RED", string, always_color=always, bold=bold)
174
175
176def green(string, always=False, bold=False):
177    return ColoredString("GREEN", string, always_color=always, bold=bold)
178
179
180def yellow(string, always=False, bold=False):
181    return ColoredString("YELLOW", string, always_color=always, bold=bold)
182
183
184def blue(string, always=False, bold=False):
185    return ColoredString("BLUE", string, always_color=always, bold=bold)
186
187
188def magenta(string, always=False, bold=False):
189    return ColoredString("MAGENTA", string, always_color=always, bold=bold)
190
191
192def cyan(string, always=False, bold=False):
193    return ColoredString("CYAN", string, always_color=always, bold=bold)
194
195
196def white(string, always=False, bold=False):
197    # This upsets people...
198    return ColoredString("WHITE", string, always_color=always, bold=bold)
199
200
201def disable():
202    """Disables colors."""
203    global DISABLE_COLOR
204
205    DISABLE_COLOR = True
206