## ecr.ui.helper.BashLexer

src/ecr/ui/helper/BashLexer.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    # pylint: disable=W0611,E0213,E1101,R1710
    import re

    from pygments.lexer import Lexer, RegexLexer, do_insertions, bygroups, \
        include, default, this, using, words
    from pygments.token import Punctuation, \
        Text, Comment, Operator, Keyword, Name, String, Number, Generic
    from pygments.util import shebang_matches

    class BashLexer(RegexLexer):
        """
        Lexer for (ba|k|z|)sh shell scripts.

        .. versionadded:: 0.6
        """

        name = 'Bash'
        aliases = ['bash', 'sh', 'ksh', 'zsh', 'shell']
        filenames = ['*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass',
                     '*.exheres-0', '*.exlib', '*.zsh',
                     '.bashrc', 'bashrc', '.bash_*', 'bash_*', 'zshrc', '.zshrc',
                     'PKGBUILD']
        mimetypes = ['application/x-sh', 'application/x-shellscript']

        tokens = {
            'root': [
                include('basic'),
                (r'`', String.Backtick, 'backticks'),
                include('data'),
                include('interp'),
            ],
            'interp': [
                (r'\$\(\(', Keyword, 'math'),
                (r'\$\(', Keyword, 'paren'),
                (r'\$\{#?', String.Interpol, 'curly'),
                (r'\$[a-zA-Z_]\w*', Name.Variable),  # user variable
                (r'\$(?:\d+|[#$?!_*@-])', Name.Variable),      # builtin
                (r'\$', Text),
            ],
            'basic': [
                # (r'\b(if|fi|else|while|do|done|for|then|return|function|case|'
                #  r'select|continue|until|esac|elif)(\s*)\b',
                #  bygroups(Keyword, Text)),
                (r'\b(init|clear|new|now|edit|run|test|clean|pwd|cd|'
                 r'version|cls|exit|debug|status|template|reload|show)', # (?=[\s)`])
                 Name.Builtin),
                (r'\A#!.+\n', Comment.Hashbang),
                (r'#.*\n', Comment.Single),
                (r'\\[\w\W]', String.Escape),
                (r'(\b\w+)(\s*)(\+?=)', bygroups(Name.Variable, Text, Operator)),
                (r'[\[\]{}()=]', Operator),
                (r'<<<', Operator),  # here-string
                (r'<<-?\s*(\'?)\\?(\w+)[\w\W]+?\2', String),
                (r'&&|\|\|', Operator),
            ],
            'data': [
                (r'(?s)\$?"(\\\\|\\[0-7]+|\\.|[^"\\$])*"', String.Double),
                (r'"', String.Double, 'string'),
                (r"(?s)\$'(\\\\|\\[0-7]+|\\.|[^'\\])*'", String.Single),
                (r"(?s)'.*?'", String.Single),
                (r';', Punctuation),
                (r'&', Punctuation),
                (r'\|', Punctuation),
                (r'\s+', Text),
                (r'\d+\b', Number),
                (r'[^=\s\[\]{}()$"\'`\\<&|;]+', Text),
                (r'<', Text),
            ],
            'string': [
                (r'"', String.Double, '#pop'),
                (r'(?s)(\\\\|\\[0-7]+|\\.|[^"\\$])+', String.Double),
                include('interp'),
            ],
            'curly': [
                (r'\}', String.Interpol, '#pop'),
                (r':-', Keyword),
                (r'\w+', Name.Variable),
                (r'[^}:"\'`$\\]+', Punctuation),
                (r':', Punctuation),
                include('root'),
            ],
            'paren': [
                (r'\)', Keyword, '#pop'),
                include('root'),
            ],
            'math': [
                (r'\)\)', Keyword, '#pop'),
                (r'[-+*/%^|&]|\*\*|\|\|', Operator),
                (r'\d+#\d+', Number),
                (r'\d+#(?! )', Number),
                (r'\d+', Number),
                include('root'),
            ],
            'backticks': [
                (r'`', String.Backtick, '#pop'),
                include('root'),
            ],
        }

        def analyse_text(text):
            if shebang_matches(text, r'(ba|z|)sh'):
                return 1
            if text.startswith('$ '):
                return 0.2