1"""Xonsh color styling tools that simulate pygments, when it is unavailable."""
2import builtins
3import string
4from collections import defaultdict
5
6from xonsh.platform import HAS_PYGMENTS
7from xonsh.lazyasd import LazyObject
8from xonsh.color_tools import RE_BACKGROUND
9
10
11class _TokenType(tuple):
12    """
13    Forked from the pygments project
14    https://bitbucket.org/birkenfeld/pygments-main
15    Copyright (c) 2006-2017 by the respective authors, All rights reserved.
16    See https://bitbucket.org/birkenfeld/pygments-main/raw/05818a4ef9891d9ac22c851f7b3ea4b4fce460ab/AUTHORS
17    """
18
19    parent = None
20
21    def split(self):
22        buf = []
23        node = self
24        while node is not None:
25            buf.append(node)
26            node = node.parent
27        buf.reverse()
28        return buf
29
30    def __init__(self, *args):
31        # no need to call super.__init__
32        self.subtypes = set()
33
34    def __contains__(self, val):
35        return self is val or (type(val) is self.__class__ and val[: len(self)] == self)
36
37    def __getattr__(self, val):
38        if not val or not val[0].isupper():
39            return tuple.__getattribute__(self, val)
40        new = _TokenType(self + (val,))
41        setattr(self, val, new)
42        self.subtypes.add(new)
43        new.parent = self
44        return new
45
46    def __repr__(self):
47        return "Token" + (self and "." or "") + ".".join(self)
48
49    def __copy__(self):
50        # These instances are supposed to be singletons
51        return self
52
53    def __deepcopy__(self, memo):
54        # These instances are supposed to be singletons
55        return self
56
57
58Token = _TokenType()
59Color = Token.Color
60
61
62def partial_color_tokenize(template):
63    """Tokenizes a template string containing colors. Will return a list
64    of tuples mapping the token to the string which has that color.
65    These sub-strings maybe templates themselves.
66    """
67    if HAS_PYGMENTS and hasattr(builtins, "__xonsh_shell__"):
68        styles = __xonsh_shell__.shell.styler.styles
69    elif hasattr(builtins, "__xonsh_shell__"):
70        styles = DEFAULT_STYLE_DICT
71    else:
72        styles = None
73    color = Color.NO_COLOR
74    try:
75        toks, color = _partial_color_tokenize_main(template, styles)
76    except Exception:
77        toks = [(Color.NO_COLOR, template)]
78    if styles is not None:
79        styles[color]  # ensure color is available
80    return toks
81
82
83def _partial_color_tokenize_main(template, styles):
84    formatter = string.Formatter()
85    bopen = "{"
86    bclose = "}"
87    colon = ":"
88    expl = "!"
89    color = Color.NO_COLOR
90    fg = bg = None
91    value = ""
92    toks = []
93    for literal, field, spec, conv in formatter.parse(template):
94        if field is None:
95            value += literal
96        elif field in KNOWN_COLORS or "#" in field:
97            value += literal
98            next_color, fg, bg = color_by_name(field, fg, bg)
99            if next_color is not color:
100                if len(value) > 0:
101                    toks.append((color, value))
102                    if styles is not None:
103                        styles[color]  # ensure color is available
104                color = next_color
105                value = ""
106        elif field is not None:
107            parts = [literal, bopen, field]
108            if conv is not None and len(conv) > 0:
109                parts.append(expl)
110                parts.append(conv)
111            if spec is not None and len(spec) > 0:
112                parts.append(colon)
113                parts.append(spec)
114            parts.append(bclose)
115            value += "".join(parts)
116        else:
117            value += literal
118    toks.append((color, value))
119    return toks, color
120
121
122def color_by_name(name, fg=None, bg=None):
123    """Converts a color name to a color token, foreground name,
124    and background name.  Will take into consideration current foreground
125    and background colors, if provided.
126
127    Parameters
128    ----------
129    name : str
130        Color name.
131    fg : str, optional
132        Foreground color name.
133    bg : str, optional
134        Background color name.
135
136    Returns
137    -------
138    tok : Token
139        Pygments Token.Color subclass
140    fg : str or None
141        New computed foreground color name.
142    bg : str or None
143        New computed background color name.
144    """
145    name = name.upper()
146    if name == "NO_COLOR":
147        return Color.NO_COLOR, None, None
148    m = RE_BACKGROUND.search(name)
149    if m is None:  # must be foreground color
150        fg = norm_name(name)
151    else:
152        bg = norm_name(name)
153    # assemble token
154    if fg is None and bg is None:
155        tokname = "NO_COLOR"
156    elif fg is None:
157        tokname = bg
158    elif bg is None:
159        tokname = fg
160    else:
161        tokname = fg + "__" + bg
162    tok = getattr(Color, tokname)
163    return tok, fg, bg
164
165
166def norm_name(name):
167    """Normalizes a color name."""
168    return name.replace("#", "HEX").replace("BGHEX", "BACKGROUND_HEX")
169
170
171KNOWN_COLORS = LazyObject(
172    lambda: frozenset(
173        [
174            "BACKGROUND_BLACK",
175            "BACKGROUND_BLUE",
176            "BACKGROUND_CYAN",
177            "BACKGROUND_GREEN",
178            "BACKGROUND_INTENSE_BLACK",
179            "BACKGROUND_INTENSE_BLUE",
180            "BACKGROUND_INTENSE_CYAN",
181            "BACKGROUND_INTENSE_GREEN",
182            "BACKGROUND_INTENSE_PURPLE",
183            "BACKGROUND_INTENSE_RED",
184            "BACKGROUND_INTENSE_WHITE",
185            "BACKGROUND_INTENSE_YELLOW",
186            "BACKGROUND_PURPLE",
187            "BACKGROUND_RED",
188            "BACKGROUND_WHITE",
189            "BACKGROUND_YELLOW",
190            "BLACK",
191            "BLUE",
192            "BOLD_BLACK",
193            "BOLD_BLUE",
194            "BOLD_CYAN",
195            "BOLD_GREEN",
196            "BOLD_INTENSE_BLACK",
197            "BOLD_INTENSE_BLUE",
198            "BOLD_INTENSE_CYAN",
199            "BOLD_INTENSE_GREEN",
200            "BOLD_INTENSE_PURPLE",
201            "BOLD_INTENSE_RED",
202            "BOLD_INTENSE_WHITE",
203            "BOLD_INTENSE_YELLOW",
204            "BOLD_PURPLE",
205            "BOLD_RED",
206            "BOLD_UNDERLINE_BLACK",
207            "BOLD_UNDERLINE_BLUE",
208            "BOLD_UNDERLINE_CYAN",
209            "BOLD_UNDERLINE_GREEN",
210            "BOLD_UNDERLINE_INTENSE_BLACK",
211            "BOLD_UNDERLINE_INTENSE_BLUE",
212            "BOLD_UNDERLINE_INTENSE_CYAN",
213            "BOLD_UNDERLINE_INTENSE_GREEN",
214            "BOLD_UNDERLINE_INTENSE_PURPLE",
215            "BOLD_UNDERLINE_INTENSE_RED",
216            "BOLD_UNDERLINE_INTENSE_WHITE",
217            "BOLD_UNDERLINE_INTENSE_YELLOW",
218            "BOLD_UNDERLINE_PURPLE",
219            "BOLD_UNDERLINE_RED",
220            "BOLD_UNDERLINE_WHITE",
221            "BOLD_UNDERLINE_YELLOW",
222            "BOLD_WHITE",
223            "BOLD_YELLOW",
224            "CYAN",
225            "GREEN",
226            "INTENSE_BLACK",
227            "INTENSE_BLUE",
228            "INTENSE_CYAN",
229            "INTENSE_GREEN",
230            "INTENSE_PURPLE",
231            "INTENSE_RED",
232            "INTENSE_WHITE",
233            "INTENSE_YELLOW",
234            "NO_COLOR",
235            "PURPLE",
236            "RED",
237            "UNDERLINE_BLACK",
238            "UNDERLINE_BLUE",
239            "UNDERLINE_CYAN",
240            "UNDERLINE_GREEN",
241            "UNDERLINE_INTENSE_BLACK",
242            "UNDERLINE_INTENSE_BLUE",
243            "UNDERLINE_INTENSE_CYAN",
244            "UNDERLINE_INTENSE_GREEN",
245            "UNDERLINE_INTENSE_PURPLE",
246            "UNDERLINE_INTENSE_RED",
247            "UNDERLINE_INTENSE_WHITE",
248            "UNDERLINE_INTENSE_YELLOW",
249            "UNDERLINE_PURPLE",
250            "UNDERLINE_RED",
251            "UNDERLINE_WHITE",
252            "UNDERLINE_YELLOW",
253            "WHITE",
254            "YELLOW",
255        ]
256    ),
257    globals(),
258    "KNOWN_COLORS",
259)
260
261DEFAULT_STYLE_DICT = LazyObject(
262    lambda: defaultdict(
263        lambda: "",
264        {
265            Token: "",
266            Token.Aborted: "ansibrightblack",
267            Token.AutoSuggestion: "ansibrightblack",
268            Token.Color.BACKGROUND_BLACK: "bg:ansiblack",
269            Token.Color.BACKGROUND_BLUE: "bg:ansiblue",
270            Token.Color.BACKGROUND_CYAN: "bg:ansicyan",
271            Token.Color.BACKGROUND_GREEN: "bg:ansigreen",
272            Token.Color.BACKGROUND_INTENSE_BLACK: "bg:ansibrightblack",
273            Token.Color.BACKGROUND_INTENSE_BLUE: "bg:ansibrightblue",
274            Token.Color.BACKGROUND_INTENSE_CYAN: "bg:ansibrightcyan",
275            Token.Color.BACKGROUND_INTENSE_GREEN: "bg:ansibrightgreen",
276            Token.Color.BACKGROUND_INTENSE_PURPLE: "bg:ansibrightmagenta",
277            Token.Color.BACKGROUND_INTENSE_RED: "bg:ansibrightred",
278            Token.Color.BACKGROUND_INTENSE_WHITE: "bg:ansiwhite",
279            Token.Color.BACKGROUND_INTENSE_YELLOW: "bg:ansibrightyellow",
280            Token.Color.BACKGROUND_PURPLE: "bg:ansimagenta",
281            Token.Color.BACKGROUND_RED: "bg:ansired",
282            Token.Color.BACKGROUND_WHITE: "bg:ansigray",
283            Token.Color.BACKGROUND_YELLOW: "bg:ansiyellow",
284            Token.Color.BLACK: "ansiblack",
285            Token.Color.BLUE: "ansiblue",
286            Token.Color.BOLD_BLACK: "bold ansiblack",
287            Token.Color.BOLD_BLUE: "bold ansiblue",
288            Token.Color.BOLD_CYAN: "bold ansicyan",
289            Token.Color.BOLD_GREEN: "bold ansigreen",
290            Token.Color.BOLD_INTENSE_BLACK: "bold ansibrightblack",
291            Token.Color.BOLD_INTENSE_BLUE: "bold ansibrightblue",
292            Token.Color.BOLD_INTENSE_CYAN: "bold ansibrightcyan",
293            Token.Color.BOLD_INTENSE_GREEN: "bold ansibrightgreen",
294            Token.Color.BOLD_INTENSE_PURPLE: "bold ansibrightmagenta",
295            Token.Color.BOLD_INTENSE_RED: "bold ansibrightred",
296            Token.Color.BOLD_INTENSE_WHITE: "bold ansiwhite",
297            Token.Color.BOLD_INTENSE_YELLOW: "bold ansibrightyellow",
298            Token.Color.BOLD_PURPLE: "bold ansimagenta",
299            Token.Color.BOLD_RED: "bold ansired",
300            Token.Color.BOLD_UNDERLINE_BLACK: "bold underline ansiblack",
301            Token.Color.BOLD_UNDERLINE_BLUE: "bold underline ansiblue",
302            Token.Color.BOLD_UNDERLINE_CYAN: "bold underline ansicyan",
303            Token.Color.BOLD_UNDERLINE_GREEN: "bold underline ansigreen",
304            Token.Color.BOLD_UNDERLINE_INTENSE_BLACK: "bold underline ansibrightblack",
305            Token.Color.BOLD_UNDERLINE_INTENSE_BLUE: "bold underline ansibrightblue",
306            Token.Color.BOLD_UNDERLINE_INTENSE_CYAN: "bold underline ansibrightcyan",
307            Token.Color.BOLD_UNDERLINE_INTENSE_GREEN: "bold underline ansibrightgreen",
308            Token.Color.BOLD_UNDERLINE_INTENSE_PURPLE: "bold underline ansibrightmagenta",
309            Token.Color.BOLD_UNDERLINE_INTENSE_RED: "bold underline ansibrightred",
310            Token.Color.BOLD_UNDERLINE_INTENSE_WHITE: "bold underline ansiwhite",
311            Token.Color.BOLD_UNDERLINE_INTENSE_YELLOW: "bold underline ansibrightyellow",
312            Token.Color.BOLD_UNDERLINE_PURPLE: "bold underline ansimagenta",
313            Token.Color.BOLD_UNDERLINE_RED: "bold underline ansired",
314            Token.Color.BOLD_UNDERLINE_WHITE: "bold underline ansigray",
315            Token.Color.BOLD_UNDERLINE_YELLOW: "bold underline ansiyellow",
316            Token.Color.BOLD_WHITE: "bold ansigray",
317            Token.Color.BOLD_YELLOW: "bold ansiyellow",
318            Token.Color.CYAN: "ansicyan",
319            Token.Color.GREEN: "ansigreen",
320            Token.Color.INTENSE_BLACK: "ansibrightblack",
321            Token.Color.INTENSE_BLUE: "ansibrightblue",
322            Token.Color.INTENSE_CYAN: "ansibrightcyan",
323            Token.Color.INTENSE_GREEN: "ansibrightgreen",
324            Token.Color.INTENSE_PURPLE: "ansibrightmagenta",
325            Token.Color.INTENSE_RED: "ansibrightred",
326            Token.Color.INTENSE_WHITE: "ansiwhite",
327            Token.Color.INTENSE_YELLOW: "ansibrightyellow",
328            Token.Color.NO_COLOR: "noinherit",
329            Token.Color.PURPLE: "ansimagenta",
330            Token.Color.RED: "ansired",
331            Token.Color.UNDERLINE_BLACK: "underline ansiblack",
332            Token.Color.UNDERLINE_BLUE: "underline ansiblue",
333            Token.Color.UNDERLINE_CYAN: "underline ansicyan",
334            Token.Color.UNDERLINE_GREEN: "underline ansigreen",
335            Token.Color.UNDERLINE_INTENSE_BLACK: "underline ansibrightblack",
336            Token.Color.UNDERLINE_INTENSE_BLUE: "underline ansibrightblue",
337            Token.Color.UNDERLINE_INTENSE_CYAN: "underline ansibrightcyan",
338            Token.Color.UNDERLINE_INTENSE_GREEN: "underline ansibrightgreen",
339            Token.Color.UNDERLINE_INTENSE_PURPLE: "underline ansibrightmagenta",
340            Token.Color.UNDERLINE_INTENSE_RED: "underline ansibrightred",
341            Token.Color.UNDERLINE_INTENSE_WHITE: "underline ansiwhite",
342            Token.Color.UNDERLINE_INTENSE_YELLOW: "underline ansibrightyellow",
343            Token.Color.UNDERLINE_PURPLE: "underline ansimagenta",
344            Token.Color.UNDERLINE_RED: "underline ansired",
345            Token.Color.UNDERLINE_WHITE: "underline ansigray",
346            Token.Color.UNDERLINE_YELLOW: "underline ansiyellow",
347            Token.Color.WHITE: "ansigray",
348            Token.Color.YELLOW: "ansiyellow",
349            Token.Comment: "underline ansicyan",
350            Token.Comment.Hashbang: "",
351            Token.Comment.Multiline: "",
352            Token.Comment.Preproc: "underline ansiyellow",
353            Token.Comment.PreprocFile: "",
354            Token.Comment.Single: "",
355            Token.Comment.Special: "",
356            Token.Error: "ansibrightred",
357            Token.Escape: "",
358            Token.Generic: "",
359            Token.Generic.Deleted: "ansired",
360            Token.Generic.Emph: "underline",
361            Token.Generic.Error: "bold ansibrightred",
362            Token.Generic.Heading: "bold ansiblue",
363            Token.Generic.Inserted: "ansibrightgreen",
364            Token.Generic.Output: "ansiblue",
365            Token.Generic.Prompt: "bold ansiblue",
366            Token.Generic.Strong: "",
367            Token.Generic.Subheading: "bold ansimagenta",
368            Token.Generic.Traceback: "ansiblue",
369            Token.Keyword: "bold ansigreen",
370            Token.Keyword.Constant: "",
371            Token.Keyword.Declaration: "",
372            Token.Keyword.Namespace: "",
373            Token.Keyword.Pseudo: "nobold",
374            Token.Keyword.Reserved: "",
375            Token.Keyword.Type: "nobold ansired",
376            Token.Literal: "",
377            Token.Literal.Date: "",
378            Token.Literal.Number: "ansibrightblack",
379            Token.Literal.Number.Bin: "",
380            Token.Literal.Number.Float: "",
381            Token.Literal.Number.Hex: "",
382            Token.Literal.Number.Integer: "",
383            Token.Literal.Number.Integer.Long: "",
384            Token.Literal.Number.Oct: "",
385            Token.Literal.String: "ansibrightred",
386            Token.Literal.String.Affix: "",
387            Token.Literal.String.Backtick: "",
388            Token.Literal.String.Char: "",
389            Token.Literal.String.Delimiter: "",
390            Token.Literal.String.Doc: "underline",
391            Token.Literal.String.Double: "",
392            Token.Literal.String.Escape: "bold ansiyellow",
393            Token.Literal.String.Heredoc: "",
394            Token.Literal.String.Interpol: "bold ansimagenta",
395            Token.Literal.String.Other: "ansigreen",
396            Token.Literal.String.Regex: "ansimagenta",
397            Token.Literal.String.Single: "",
398            Token.Literal.String.Symbol: "ansiyellow",
399            Token.Menu.Completions: "bg:ansigray ansiblack",
400            Token.Menu.Completions.Completion: "",
401            Token.Menu.Completions.Completion.Current: "bg:ansibrightblack ansiwhite",
402            Token.Name: "",
403            Token.Name.Attribute: "ansibrightyellow",
404            Token.Name.Builtin: "ansigreen",
405            Token.Name.Builtin.Pseudo: "",
406            Token.Name.Class: "bold ansibrightblue",
407            Token.Name.Constant: "ansired",
408            Token.Name.Decorator: "ansibrightmagenta",
409            Token.Name.Entity: "bold ansigray",
410            Token.Name.Exception: "bold ansibrightred",
411            Token.Name.Function: "ansibrightblue",
412            Token.Name.Function.Magic: "",
413            Token.Name.Label: "ansibrightyellow",
414            Token.Name.Namespace: "bold ansibrightblue",
415            Token.Name.Other: "",
416            Token.Name.Property: "",
417            Token.Name.Tag: "bold ansigreen",
418            Token.Name.Variable: "ansiblue",
419            Token.Name.Variable.Class: "",
420            Token.Name.Variable.Global: "",
421            Token.Name.Variable.Instance: "",
422            Token.Name.Variable.Magic: "",
423            Token.Operator: "ansibrightblack",
424            Token.Operator.Word: "bold ansimagenta",
425            Token.Other: "",
426            Token.Punctuation: "",
427            Token.Scrollbar: "bg:ansibrightblack",
428            Token.Scrollbar.Arrow: "bg:ansiblack ansiwhite bold",
429            Token.Scrollbar.Button: "bg:ansiblack",
430            Token.Text: "",
431            Token.Text.Whitespace: "ansigray",
432        },
433    ),
434    globals(),
435    "DEFAULT_STYLE_DICT",
436)
437