Rainbow.extend('html', [
    {
        'name': 'source.php.embedded',
        'matches': {
            2: {
                'language': 'php'
            }
        },
        'pattern': /<\?=?(?!xml)(php)?([\s\S]*?)(\?>)/gm
    },
    {
        'name': 'source.css.embedded',
        'matches': {
            1: {
                'matches': {
                    1: 'support.tag.style',
                    2: [
                        {
                            'name': 'entity.tag.style',
                            'pattern': /^style/g
                        },
                        {
                            'name': 'string',
                            'pattern': /('|")(.*?)(\1)/g
                        },
                        {
                            'name': 'entity.tag.style.attribute',
                            'pattern': /(\w+)/g
                        }
                    ],
                    3: 'support.tag.style'
                },
                'pattern': /(<\/?)(style.*?)(>)/g
            },
            2: {
                'language': 'css'
            },
            3: 'support.tag.style',
            4: 'entity.tag.style',
            5: 'support.tag.style'
        },
        'pattern': /(<style.*?>)([\s\S]*?)(<\/)(style)(>)/gm
    },
    {
        'name': 'source.js.embedded',
        'matches': {
            1: {
                'matches': {
                    1: 'support.tag.script',
                    2: [
                        {
                            'name': 'entity.tag.script',
                            'pattern': /^script/g
                        },

                        {
                            'name': 'string',
                            'pattern': /('|")(.*?)(\1)/g
                        },
                        {
                            'name': 'entity.tag.script.attribute',
                            'pattern': /(\w+)/g
                        }
                    ],
                    3: 'support.tag.script'
                },
                'pattern': /(<\/?)(script.*?)(>)/g
            },
            2: {
                'language': 'javascript'
            },
            3: 'support.tag.script',
            4: 'entity.tag.script',
            5: 'support.tag.script'
        },
        'pattern': /(<script(?! src).*?>)([\s\S]*?)(<\/)(script)(>)/gm
    },
    {
        'name': 'comment.html',
        'pattern': /<\!--[\S\s]*?-->/g
    },
    {
        'matches': {
            1: 'support.tag.open',
            2: 'support.tag.close'
        },
        'pattern': /(<)|(\/?\??>)/g
    },
    {
        'name': 'support.tag',
        'matches': {
            1: 'support.tag',
            2: 'support.tag.special',
            3: 'support.tag-name'
        },
        'pattern': /(<\??)(\/|\!?)(\w+)/g
    },
    {
        'matches': {
            1: 'support.attribute'
        },
        'pattern': /([a-z-]+)(?=\=)/gi
    },
    {
        'matches': {
            1: 'support.operator',
            2: 'string.quote',
            3: 'string.value',
            4: 'string.quote'
        },
        'pattern': /(=)('|")(.*?)(\2)/g
    },
    {
        'matches': {
            1: 'support.operator',
            2: 'support.value'
        },
        'pattern': /(=)([a-zA-Z\-0-9]*)\b/g
    },
    {
        'matches': {
            1: 'support.attribute'
        },
        'pattern': /\s(\w+)(?=\s|>)(?![\s\S]*<)/g
    }
], true);

Rainbow.extend('css', [
    {
        'name': 'comment',
        'pattern': /\/\*[\s\S]*?\*\//gm
    },
    {
        'name': 'constant.hex-color',
        'pattern': /#([a-f0-9]{3}|[a-f0-9]{6})(?=;|\s|,|\))/gi
    },
    {
        'matches': {
            1: 'constant.numeric',
            2: 'keyword.unit'
        },
        'pattern': /(\d+)(px|em|cm|s|%)?/g
    },
    {
        'name': 'string',
        'pattern': /('|")(.*?)\1/g
    },
    {
        'name': 'support.css-property',
        'matches': {
            1: 'support.vendor-prefix'
        },
        'pattern': /(-o-|-moz-|-webkit-|-ms-)?[\w-]+(?=\s?:)(?!.*\{)/g
    },
    {
        'matches': {
            1: [
                {
                    'name': 'entity.name.sass',
                    'pattern': /&/g
                },
                {
                    'name': 'direct-descendant',
                    'pattern': />/g
                },
                {
                    'name': 'entity.name.class',
                    'pattern': /\.[\w\-_]+/g
                },
                {
                    'name': 'entity.name.id',
                    'pattern': /\#[\w\-_]+/g
                },
                {
                    'name': 'entity.name.pseudo',
                    'pattern': /:[\w\-_]+/g
                },
                {
                    'name': 'entity.name.tag',
                    'pattern': /\w+/g
                }
            ]
        },
        'pattern': /([\w\ ,\n:\.\#\&\;\-_]+)(?=.*\{)/g
    },
    {
        'matches': {
            2: 'support.vendor-prefix',
            3: 'support.css-value'
        },
        'pattern': /(:|,)\s*(-o-|-moz-|-webkit-|-ms-)?([a-zA-Z-]*)(?=\b)(?!.*\{)/g
    }
], true);

Rainbow.extend('javascript', [

    /**
     * matches $. or $(
     */
    {
        'name': 'selector',
        'pattern': /(\s|^)\$(?=\.|\()/g
    },
    {
        'name': 'support',
        'pattern': /\b(window|document)\b/g
    },
    {
        'matches': {
            1: 'support.property'
        },
        'pattern': /\.(length|node(Name|Value))\b/g
    },
    {
        'matches': {
            1: 'support.function'
        },
        'pattern': /(setTimeout|setInterval)(?=\()/g

    },
    {
        'matches': {
            1: 'support.method'
        },
        'pattern': /\.(getAttribute|push|getElementById|getElementsByClassName|log|setTimeout|setInterval)(?=\()/g
    },

    /**
     * matches any escaped characters inside of a js regex pattern
     *
     * @see https://github.com/ccampbell/rainbow/issues/22
     *
     * this was causing single line comments to fail so it now makes sure
     * the opening / is not directly followed by a *
     *
     * @todo check that there is valid regex in match group 1
     */
    {
        'name': 'string.regexp',
        'matches': {
            1: 'string.regexp.open',
            2: {
                'name': 'constant.regexp.escape',
                'pattern': /\\(.){1}/g
            },
            3: 'string.regexp.close',
            4: 'string.regexp.modifier'
        },
        'pattern': /(\/)(?!\*)(.+)(\/)([igm]{0,3})/g
    },

    /**
     * matches runtime function declarations
     */
    {
        'matches': {
            1: 'storage',
            3: 'entity.function'
        },
        'pattern': /(var)?(\s|^)(\S*)(?=\s?=\s?function\()/g
    },

    /**
     * matches constructor call
     */
    {
        'matches': {
            1: 'keyword',
            2: 'entity.function'
        },
        'pattern': /(new)\s+(.*)(?=\()/g
    },

    /**
     * matches any function call in the style functionName: function()
     */
    {
        'name': 'entity.function',
        'pattern': /(\w+)(?=:\s{0,}function)/g
    }
]);

Rainbow.extend('coffeescript', [
    {
        'name': 'comment.block',
        'pattern': /(\#{3})[\s\S]*\1/gm
    },
    {
        'name': 'string.block',
        'pattern': /('{3}|"{3})[\s\S]*\1/gm
    },

    /**
     * multiline regex with comments
     */
    {
        'name': 'string.regex',
        'matches': {
            2: {
                'name': 'comment',
                'pattern': /\#(.*?)\n/g
            }
        },
        'pattern': /(\/{3})([\s\S]*)\1/gm
    },
    {
        'matches': {
            1: 'keyword'
        },
        'pattern': /\b(in|when|is|isnt|of|not|unless|until|super)(?=\b)/gi
    },
    {
        'name': 'keyword.operator',
        'pattern': /\?/g
    },
    {
        'name': 'constant.language',
        'pattern': /\b(undefined|yes|on|no|off)\b/g
    },
    {
        'name': 'keyword.variable.coffee',
        'pattern': /@(\w+)/gi
    },

    /**
     * reset global keywards from generic
     */
    {
        'name': 'reset',
        'pattern': /object|class|print/gi
    },

    /**
     * named function
     */
    {
        'matches' : {
            1: 'entity.name.function',
            2: 'keyword.operator',
            3: {
                    'name': 'function.argument.coffee',
                    'pattern': /([\@\w]+)/g
            },
            4: 'keyword.function'
        },
        'pattern': /(\w+)\s{0,}(=|:)\s{0,}\((.*?)((-|=)>)/gi
    },

    /**
     * anonymous function
     */
    {
        'matches': {
            1: {
                    'name': 'function.argument.coffee',
                    'pattern': /([\@\w]+)/g
            },
            2: 'keyword.function'
        },
        'pattern': /\s\((.*?)\)\s{0,}((-|=)>)/gi
    },

    /**
     * direct function no arguments
     */
    {
        'matches' : {
            1: 'entity.name.function',
            2: 'keyword.operator',
            3: 'keyword.function'
        },
        'pattern': /(\w+)\s{0,}(=|:)\s{0,}((-|=)>)/gi
    },

    /**
     * class definitions
     */
    {
        'matches': {
            1: 'storage.class',
            2: 'entity.name.class',
            3: 'storage.modifier.extends',
            4: 'entity.other.inherited-class'
        },
        'pattern': /\b(class)\s(\w+)(\sextends\s)?([\w\\]*)?\b/g
    },

    /**
     * object instantiation
     */
    {
        'matches': {
            1: 'keyword.new',
            2: {
                'name': 'support.class',
                'pattern': /\w+/g
            }
        },
        'pattern': /\b(new)\s(.*?)(?=\s)/g
    }
]);

Rainbow.extend('php', [
    {
        'name': 'support',
        'pattern': /\becho\b/g
    },
    {
        'matches': {
            1: 'variable.dollar-sign',
            2: 'variable'
        },
        'pattern': /(\$)(\w+)\b/g
    },
    {
        'name': 'constant.language',
        'pattern': /true|false|null/ig
    },
    {
        'name': 'constant',
        'pattern': /\b[A-Z0-9_]{2,}\b/g
    },
    {
        'name': 'keyword.dot',
        'pattern': /\./g
    },
    {
        'name': 'keyword',
        'pattern': /\b(die|end(for(each)?|switch|if)|case|require(_once)?|include(_once)?)(?=\(|\b)/g
    },
    {
        'matches': {
            1: 'keyword',
            2: {
                'name': 'support.class',
                'pattern': /\w+/g
            }
        },
        'pattern': /(instanceof)\s([^\$].*?)(\)|;)/g
    },

    /**
     * these are the top 50 most used PHP functions
     * found from running a script and checking the frequency of each function
     * over a bunch of popular PHP frameworks then combining the results
     */
    {
        'matches': {
            1: 'support.function'
        },
        'pattern': /\b(array(_key_exists|_merge|_keys|_shift)?|isset|count|empty|unset|printf|is_(array|string|numeric|object)|sprintf|each|date|time|substr|pos|str(len|pos|tolower|_replace|totime)?|ord|trim|in_array|implode|end|preg_match|explode|fmod|define|link|list|get_class|serialize|file|sort|mail|dir|idate|log|intval|header|chr|function_exists|dirname|preg_replace|file_exists)(?=\()/g
    },
    {
        'name': 'variable.language.php-tag',
        'pattern': /(<\?(php)?|\?>)/g
    },
    {
        'matches': {
            1: 'keyword.namespace',
            2: {
                'name': 'support.namespace',
                'pattern': /\w+/g
            }
        },
        'pattern': /\b(namespace|use)\s(.*?);/g
    },
    {
        'matches': {
            1: 'storage.modifier',
            2: 'storage.class',
            3: 'entity.name.class',
            4: 'storage.modifier.extends',
            5: 'entity.other.inherited-class',
            6: 'storage.modifier.extends',
            7: 'entity.other.inherited-class'
        },
        'pattern': /\b(abstract|final)?\s?(class|interface|trait)\s(\w+)(\sextends\s)?([\w\\]*)?(\simplements\s)?([\w\\]*)?\s?\{?(\n|\})/g
    },
    {
        'name': 'keyword.static',
        'pattern': /self::|static::/g
    },
    {
        'matches': {
            1: 'storage.function',
            2: 'support.magic'
        },
        'pattern': /(function)\s(__.*?)(?=\()/g
    },
    {
        'matches': {
            1: 'keyword.new',
            2: {
                'name': 'support.class',
                'pattern': /\w+/g
            }
        },
        'pattern': /\b(new)\s([^\$].*?)(?=\)|\(|;)/g
    },
    {
        'matches': {
            1: {
                'name': 'support.class',
                'pattern': /\w+/g
            },
            2: 'keyword.static'
        },
        'pattern': /([\w\\]*?)(::)(?=\b|\$)/g
    },
    {
        'matches': {
            2: {
                'name': 'support.class',
                'pattern': /\w+/g
            }
        },
        'pattern': /(\(|,\s?)([\w\\]*?)(?=\s\$)/g
    }
]);

Rainbow.extend('ruby', [
    /**
    * __END__ DATA
    */
    {
        'matches': {
            1: 'variable.language',
            2: {
              'language': null
            }
        },
        //find __END__ and consume remaining text
        'pattern': /^(__END__)\n((?:.*\n)*)/gm
    },
    /**
     * Strings
     *   1. No support for multi-line strings
     */
    {
        'name': 'string',
        'matches': {
            1: 'string.open',
            2: [{
                'name': 'string.interpolation',
                'matches': {
                    1: 'string.open',
                    2: {
                      'language': 'ruby'
                    },
                    3: 'string.close'
                },
                'pattern': /(\#\{)(.*?)(\})/g
            }],
            3: 'string.close'
        },
        'pattern': /("|`)(.*?[^\\\1])?(\1)/g
    },
    {
        'name': 'string',
        'pattern': /('|"|`)([^\\\1\n]|\\.)*?\1/g
    },
    {
        'name': 'string',
        'pattern': /%[qQ](?=(\(|\[|\{|<|.)(.*?)(?:'|\)|\]|\}|>|\1))(?:\(\2\)|\[\2\]|\{\2\}|\<\2>|\1\2\1)/g
    },
    /**
     * Heredocs
     * Heredocs of the form `<<'HTML' ... HTML` are unsupported.
     */
    {
        'matches': {
            1: 'string',
            2: 'string',
            3: 'string'
        },
        'pattern': /(&lt;&lt;)(\w+).*?$([\s\S]*?^\2)/gm
    },
    {
        'matches': {
            1: 'string',
            2: 'string',
            3: 'string'
        },
        'pattern': /(&lt;&lt;\-)(\w+).*?$([\s\S]*?\2)/gm
    },
    /**
     * Regular expressions
     * Escaped delimiter (`/\//`) is unsupported.
     */
    {
        'name': 'string.regexp',
        'matches': {
            1: 'string.regexp',
            2: {
                'name': 'string.regexp',
                'pattern': /\\(.){1}/g
            },
            3: 'string.regexp',
            4: 'string.regexp'
        },
        'pattern': /(\/)(.*?)(\/)([a-z]*)/g
    },
    {
        'name': 'string.regexp',
        'matches': {
            1: 'string.regexp',
            2: {
                'name': 'string.regexp',
                'pattern': /\\(.){1}/g
            },
            3: 'string.regexp',
            4: 'string.regexp'
        },
        'pattern': /%r(?=(\(|\[|\{|&lt;|.)(.*?)('|\)|\]|\}|&gt;|\1))(?:\(\2\)|\[\2\]|\{\2\}|\&lt;\2&gt;|\1\2\1)([a-z]*)/g
    },
    /**
     * Comments
     */
    {
        'name': 'comment',
        'pattern': /#.*$/gm
    },
    {
        'name': 'comment',
        'pattern': /^\=begin[\s\S]*?\=end$/gm
    },
    /**
     * Symbols
     */
    {
        'matches': {
            1: 'constant'
        },
        'pattern': /(\w+:)[^:]/g
    },
    {
        'matches': {
            1: 'constant.symbol'
        },
        'pattern': /[^:](:(?:\w+|(?=['"](.*?)['"])(?:"\2"|'\2')))/g
    },
    {
        'name': 'constant.numeric',
        'pattern': /\b(0x[\da-f]+|\d+)\b/g
    },
    {
        'name': 'support.class',
        'pattern': /\b[A-Z]\w*(?=((\.|::)[A-Za-z]|\[))/g
    },
    {
        'name': 'constant',
        'pattern': /\b[A-Z]\w*\b/g
    },
    /**
     * Keywords, variables, constants, and operators
     *   In Ruby some keywords are valid method names, e.g., MyClass#yield
     *   Don't mark those instances as "keywords"
     */
    {
        'matches': {
            1: 'storage.class',
            2: 'entity.name.class',
            3: 'entity.other.inherited-class'
        },
        'pattern': /\s*(class)\s+((?:(?:::)?[A-Z]\w*)+)(?:\s+&lt;\s+((?:(?:::)?[A-Z]\w*)+))?/g
    },
    {
        'matches': {
            1: 'storage.module',
            2: 'entity.name.class'
        },
        'pattern': /\s*(module)\s+((?:(?:::)?[A-Z]\w*)+)/g
    },
    {
        'name': 'variable.global',
        'pattern': /\$([a-zA-Z_]\w*)\b/g
    },
    {
        'name': 'variable.class',
        'pattern': /@@([a-zA-Z_]\w*)\b/g
    },
    {
        'name': 'variable.instance',
        'pattern': /@([a-zA-Z_]\w*)\b/g
    },
    {
        'matches': {
            1: 'keyword.control'
        },
        'pattern': /[^\.]\b(BEGIN|begin|case|class|do|else|elsif|END|end|ensure|for|if|in|module|rescue|then|unless|until|when|while)\b(?![?!])/g
    },
    {
        'matches': {
            1: 'keyword.control.pseudo-method'
        },
        'pattern': /[^\.]\b(alias|alias_method|break|next|redo|retry|return|super|undef|yield)\b(?![?!])|\bdefined\?|\bblock_given\?/g
    },
    {
        'matches': {
            1: 'constant.language'
        },
        'pattern': /\b(nil|true|false)\b(?![?!])/g
    },
    {
        'matches': {
            1: 'variable.language'
        },
        'pattern': /\b(__(FILE|LINE)__|self)\b(?![?!])/g
    },
    {
        'matches': {
            1: 'keyword.special-method'
        },
        'pattern': /\b(require|gem|initialize|new|loop|include|extend|raise|attr_reader|attr_writer|attr_accessor|attr|catch|throw|private|module_function|public|protected)\b(?![?!])/g
    },
    {
        'name': 'keyword.operator',
        'pattern': /\s\?\s|=|&lt;&lt;|&lt;&lt;=|%=|&=|\*=|\*\*=|\+=|\-=|\^=|\|{1,2}=|&lt;&lt;|&lt;=&gt;|&lt;(?!&lt;|=)|&gt;(?!&lt;|=|&gt;)|&lt;=|&gt;=|===|==|=~|!=|!~|%|&amp;|\*\*|\*|\+|\-|\/|\||~|&gt;&gt;/g
    },
    {
        'matches': {
            1: 'keyword.operator.logical'
        },
        'pattern': /[^\.]\b(and|not|or)\b/g
    },

    /**
    * Functions
    *   1. No support for marking function parameters
    */
    {
        'matches': {
            1: 'storage.function',
            2: 'entity.name.function'
        },
        'pattern': /(def)\s(.*?)(?=(\s|\())/g
    }
], true);

Rainbow.extend('go', [
    {
        'matches': {
            1: {
                'name': 'keyword.operator',
                'pattern': /\=/g
            },
            2: {
                'name': 'string',
                'matches': {
                    'name': 'constant.character.escape',
                    'pattern': /\\(`|"){1}/g
                }
            }
        },
        'pattern': /(\(|\s|\[|\=|:)((`|")([^\\\1]|\\.)*?(\3))/gm
    },
    {
        'name': 'comment',
        'pattern': /\/\*[\s\S]*?\*\/|(\/\/)[\s\S]*?$/gm
    },
    {
        'name': 'constant.numeric',
        'pattern': /\b(\d+(\.\d+)?(e(\+|\-)?\d+)?(f|d)?|0x[\da-f]+)\b/gi
    },
    {
        'matches': {
            1: 'keyword'
        },
        'pattern': /\b(break|c(ase|onst|ontinue)|d(efault|efer)|else|fallthrough|for|go(to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)(?=\(|\b)/gi
    },
    {
        'name': 'constant.language',
        'pattern': /true|false|null|string|byte|rune|u?int(8|16|32|64)?|float(32|64)|complex(64|128)/g
    },
    {
        'name': 'keyword.operator',
        'pattern': /\+|\!|\-|&(gt|lt|amp);|\||\*|\:?=/g
    },
    {
        'matches': {
            1: 'function.call'
        },
        'pattern': /(\w+?)(?=\()/g
    },
    {
        'matches': {
            1: 'storage.function',
            2: 'entity.name.function'
        },
        'pattern': /(func)\s(.*?)(?=\()/g
    }
]);