diff --git a/js/language/css.js b/js/language/css.js index e3bc6f53..b5243eef 100644 --- a/js/language/css.js +++ b/js/language/css.js @@ -2,71 +2,429 @@ * CSS patterns * * @author Craig Campbell - * @version 1.0.9 + * @author Fabio Bucci Di Monte + * @version 1.1.0 */ -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': { +!function(){ + + 'use strict'; + + var regexes = { + + /* common */ + commonName : /(-?\w+(?:-\w+)*)/g, + parameters : /\((.+)\)/g, + + /* reserved words / symbols */ + atDirective : /(?:@[a-z]+)/g, + exception : /!important(?= *;)/g, + reserved : /(?:from|to(?! (?:top|bottom|right|left)))/g, + + /* comments */ + commentMulti : /\/\*[^]*?\*\//gm, + + /* units */ + unitAbsolute : /(?:p[xtc]|[cm]m|in)/g, + unitRelative : /(?:e[mx]|rem|ch)/g, + unitViewport : /(?:v(?:h|w|m(?:in|ax)))/g, + unitAngle : /(?:deg|g?rad|turn)/g, + unitTime : /(?:m?s)/g, + unitFrequency : /(?:k?Hz)/g, + unitResolution : /(?:dp(?:i|cm|px))/g, + unitPercentage : /%/g, + + /* values */ + valueText : /(-(?:webkit|moz|ms|o)-)\b\w+(?:-\w+)*\b/g, + valueString : /('|").*?\1/g, + valuePath : /[\w/-]+\.[a-z0-9]{3,4}\b(?!["'])/gi, + valueHex : /#(?:[a-f0-9]{6}|[a-f0-9]{3})\b/gi, + valueNumber : /(-?(?:\d*\.)?\d+)((?:p[xtc]|[cm]m|in)|(?:e[mx]|rem|ch)|(?:v(?:h|w|m(?:in|ax)))|(?:deg|g?rad|turn)|(?:m?s)|(?:k?Hz)|(?:dp(?:i|cm|px))|%)?/g, + + /* css rules */ + prefix : /-(?:webkit|moz|ms|o)-/g, + cssProperty : /([a-z-]+)/g, + cssMethod : /(-?\w+(?:-\w+)*)(\(.+\))/g, + cssSelector : /((?:[\w.#:()+>~\[="\] -]|,\s?|>)+)(?=\{)/g, + + /* ie hacks */ + cssPropertyWithHack : /([\*\+#_])?([a-z-]+)( *\/\*(?:\\\*)?\*\/)?(?= *:)/g, + hackValue : /((?:\\0|\\9|\\0\\9|\\9\\0)|!\w+?|\\0\/)(?= *[;}])/g, + ieHacks : /(_)|(\*|#|!.+)|(\*?\+|\+\*?)|(\\9)|(\\0\\9|\\9\\0)|(\/\*(?:\\\*)?\*\/)|(\\0\/)/g, + + /* entities */ + entityClass : /\.(?!\.)\w+(?:-\w+)*/g, + entityId : /#(?!#)\w+(?:-\w+)*/g, + entityPseudo : /::?(?!::?)[a-z-]+/g, + entityTag : /[a-z]+\d?(?! *:.*;)/gi, + entityAttribute : /\[(\w+(?:-\w+)*)=(("|')?\w+(?:-\w+)*\3)]/g, + + /* siblings */ + directChild : / ?(?:>|>) ?/g, + siblingGeneral : / ?~ ?/g, + siblingAdjacent : / ?\+ ?/g, + + /* media queries */ + mediaReserved : /\b(?:not|only|and)\b/g, + mediaType : /\b(?:all|aural|braille|handheld|print|projection|screen|tty|tv|embossed)\b/g, + mediaFeature : /(-(?:webkit|moz|ms|o)-)?\b(?:(?:(?:min|max)-)?(?:(?:device-)?(?:width|height|(?:pixel|aspect)-ratio)|color(?:-index)?|monochrome|resolution)|scan|grid|orientation)\b/g, + mediaExpression : /\(([^:]+)(?: *: *([^)]+))?\)/g, + mediaQuery : /(?:(not|only) +)?(.+)/g, + mediaQueryList : / *([^,\n\r]+) */g, + mediaQueryRule : /(@media) +(.+)(?=\{)/g + + }; + + /******************** + * @ DIRECTIVES + ********************/ + + var atDirective = { + name: 'at-directive', + pattern: regexes.atDirective + }; + + /******************** + * RESERVED WORDS / SYMBOLS + ********************/ + + var reserved = { + name: 'reserved', + pattern: regexes.reserved + }; + + var exception = { + name: 'keyword.exception', + pattern: regexes.exception + }; + + var prefix = { + name: 'vendor-prefix', + pattern: regexes.prefix + }; + + /******************** + * TYPES + ********************/ + + var unit = { + absolute: { + name: 'keyword.unit.absolute', + pattern: regexes.unitAbsolute + }, + relative: { + name: 'keyword.unit.relative', + pattern: regexes.unitRelative + }, + viewport: { + name: 'keyword.unit.viewport', + pattern: regexes.unitViewport + }, + angle: { + name: 'keyword.unit.angle', + pattern: regexes.unitAngle + }, + time: { + name: 'keyword.unit.time', + pattern: regexes.unitTime + }, + frequency: { + name: 'keyword.unit.frequency', + pattern: regexes.unitFrequency + }, + resolution: { + name: 'keyword.unit.resolution', + pattern: regexes.unitResolution + }, + percentage: { + name: 'keyword.unit.percentage', + pattern: regexes.unitPercentage + } + }; + + var type = { + attribute: { + name: 'support.attribute-name', + pattern: regexes.valueText + }, + text: { + name: 'support.text-value', + matches: { + 1: [prefix] + }, + pattern: regexes.valueText + }, + string: { + name: 'string', + pattern: regexes.valueString + }, + path: { + name: 'constant.path', + pattern: regexes.valuePath + }, + hex: { + name: 'constant.hex-color', + pattern: regexes.valueHex + }, + number: { + name: 'constant.numeric', + matches: { + 2: [ + unit.absolute, + unit.relative, + unit.viewport, + unit.angle, + unit.time, + unit.frequency, + unit.resolution, + unit.percentage + ] + }, + pattern: regexes.valueNumber + } + }; + + var arr_parameters = [ + type.number, + type.path, + type.text, + type.string, + type.hex + ]; + + /******************** + * HACKS (css attributes) + ********************/ + + var ieHacks = { + name: 'hack', + matches: { + 1: 'ie-6', + 2: 'ie-lte7', + 3: 'ie-7', + 4: 'ie-lte9', + 5: 'ie-9', + 6: 'ie-gt6', + 7: 'ie-8-9' + }, + pattern: regexes.ieHacks + }; + + var cssHacks = { + matches: { + 1: [ieHacks] + }, + pattern: regexes.hackValue + }; + + /******************** + * CSS PROPERTIES / METHODS + ********************/ + + var cssProperties = { + name: 'css-property', + matches: { + 1: [prefix] + }, + pattern: regexes.cssProperty + }; + + var cssPropertiesHacked = { + matches: { + 1: [ieHacks], + 2: [cssProperties], + 3: [ieHacks] + }, + pattern: regexes.cssPropertyWithHack + }; + + var cssMethods = { + name: 'css-method', + 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: 'method-name', + matches: { + 1: [prefix] + }, + pattern: regexes.commonName + } + ], + 2: [ { - 'name': 'entity.name.tag', - 'pattern': /\w+/g + name: 'method-params', + matches: { + 1: arr_parameters + }, + pattern: regexes.parameters } ] }, - 'pattern': /([\w\ ,\n:\.\#\&\;\-_]+)(?=.*\{)/g - }, - { - 'matches': { - 2: 'support.vendor-prefix', - 3: 'support.css-value' + pattern: regexes.cssMethod + }; + + /******************** + * COMMENTS + ********************/ + + var commentMultiline = { + name: 'comment', + pattern: regexes.commentMulti + }; + + /******************** + * SELECTORS + ********************/ + + var entity = { + cssClass: { + name: 'entity.name.class', + pattern: regexes.entityClass + }, + cssId: { + name: 'entity.name.id', + pattern: regexes.entityId + }, + cssAttribute : { + name: 'entity.name.attribute', + matches: { + 1: [type.attribute], + 2: [ + type.text, + type.string + ] + }, + pattern: regexes.entityAttribute + }, + cssPseudo: { + name: 'entity.name.pseudo', + pattern: regexes.entityPseudo + }, + cssTag: { + name: 'entity.name.tag', + pattern: regexes.entityTag + } + }; + + var sibling = { + direct: { + name: 'direct-child', + pattern: regexes.directChild + }, + general: { + name: 'general-sibling', + pattern: regexes.siblingGeneral + }, + adjacent: { + name: 'adjacent-sibling', + pattern: regexes.siblingAdjacent + } + }; + + var arr_siblings = [ + sibling.direct, + sibling.general, + sibling.adjacent + ]; + + var arr_commonEntities = [ + entity.cssClass, + entity.cssId, + entity.cssTag + ]; + + var arr_entities = arr_commonEntities.concat([ + entity.cssPseudo, + entity.cssAttribute + ]); + + var cssSelectors = { + name: 'selector', + matches: { + 1: arr_siblings.concat([reserved]).concat(arr_entities) + }, + pattern: regexes.cssSelector + }; + + /******************** + * MEDIA QUERIES + * ref: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#Pseudo-BNF_%28for_those_of_you_that_like_that_kind_of_thing%29 + ********************/ + + var media = { + reserved: { + name: 'mediaquery.reserved', + pattern: regexes.mediaReserved + }, + types: { + name: 'mediaquery.type', + pattern: regexes.mediaType + }, + features: { + name: 'mediaquery.feature', + matches: { + 1: [prefix] + }, + pattern: regexes.mediaFeature + } + }; + + media.expression = { + name: 'mediaquery.expression', + matches: { + 1: [media.features], + 2: arr_parameters + }, + pattern: regexes.mediaExpression + }; + + media.query = { + name: 'mediaquery.query', + matches: { + 1: [media.reserved], + 2: [ + media.reserved, + media.types, + media.expression + ] + }, + pattern: regexes.mediaQuery + }; + + var mediaQuery = { + name: 'media-query', + matches: { + 1: 'at-directive', + 2: [ + { + matches: { + 1: [media.query] + }, + pattern: regexes.mediaQueryList + } + ] }, - 'pattern': /(:|,)\s*(-o-|-moz-|-webkit-|-ms-)?([a-zA-Z-]*)(?=\b)(?!.*\{)/g - } -], true); + pattern: regexes.mediaQueryRule + }; + + /******************** + * RAINBOW EXTENSION + ********************/ + + var cssSyntaxEnhanced = [] + .concat([ + commentMultiline, + exception, + mediaQuery, + atDirective, + cssSelectors, + cssPropertiesHacked, + cssHacks + ]) + .concat(arr_parameters) + .concat([ + cssMethods + ]); + + Rainbow.extend('css', cssSyntaxEnhanced, true); + +}(); diff --git a/tests/language/test.css.js b/tests/language/test.css.js index a7d473ad..c1e094d5 100644 --- a/tests/language/test.css.js +++ b/tests/language/test.css.js @@ -33,7 +33,7 @@ describe(language, function() { 'margin:10px 20px 5px 30px;', - 'margin:10px 20px 5px 30px;' + 'margin:10px 20px 5px 30px;' ); run( @@ -43,7 +43,7 @@ describe(language, function() { 'margin: 1cm 2cm 1.3cm 4cm;', - 'margin: 1cm 2cm 1.3cm 4cm;' + 'margin: 1cm 2cm 1.3cm 4cm;' ); run( @@ -53,7 +53,7 @@ describe(language, function() { 'font-size: 1.2em;', - 'font-size: 1.2em;' + 'font-size: 1.2em;' ); run( @@ -64,8 +64,8 @@ describe(language, function() { 'width: 100%\n' + 'height: 100%', - 'width: 100%\n' + - 'height: 100%' + 'width: 100%\n' + + 'height: 100%' ); run( @@ -100,11 +100,11 @@ describe(language, function() { ' transition: color .8s ease-in;\n' + '}', - 'code span {\n' + - ' -moz-transition: color .8s ease-in;\n' + - ' -o-transition: color .8s ease-in;\n' + - ' -webkit-transition: color .8s ease-in;\n' + - ' transition: color .8s ease-in;\n' + + 'code span {\n' + + ' -moz-transition: color .8s ease-in;\n' + + ' -o-transition: color .8s ease-in;\n' + + ' -webkit-transition: color .8s ease-in;\n' + + ' transition: color .8s ease-in;\n' + '}' ); @@ -115,7 +115,7 @@ describe(language, function() { 'p {', - 'p {' + 'p {' ); run( @@ -125,7 +125,7 @@ describe(language, function() { 'p.intro {', - 'p.intro {' + 'p.intro {' ); run( @@ -135,7 +135,7 @@ describe(language, function() { 'p#intro {', - 'p#intro {' + 'p#intro {' ); run( @@ -145,29 +145,7 @@ describe(language, function() { 'p > span {', - 'p > span {' - ); - - run( - language, - - 'scss', - - 'article {\n' + - ' &.cool {\n' + - ' p {\n' + - ' margin-top: 20px;\n' + - ' }\n' + - ' }\n' + - '}', - - 'article {\n' + - ' &.cool {\n' + - ' p {\n' + - ' margin-top: 20px;\n' + - ' }\n' + - ' }\n' + - '}' + 'p > span {' ); run( @@ -177,7 +155,7 @@ describe(language, function() { 'p { color: #fff; margin-top: 10px; }', - 'p { color: #fff; margin-top: 10px; }' + 'p { color: #fff; margin-top: 10px; }' ); run( @@ -192,11 +170,11 @@ describe(language, function() { ' background: linear-gradient(#f7f7f7, #e8e8e8);\n' + '}', - '.gradient {\n' + - ' background: -webkit-linear-gradient(#f7f7f7, #e8e8e8);\n' + - ' background: -moz-linear-gradient(#f7f7f7, #e8e8e8);\n' + - ' background: -o-linear-gradient(#f7f7f7, #e8e8e8);\n' + - ' background: linear-gradient(#f7f7f7, #e8e8e8);\n' + + '.gradient {\n' + + ' background: -webkit-linear-gradient(#f7f7f7, #e8e8e8);\n' + + ' background: -moz-linear-gradient(#f7f7f7, #e8e8e8);\n' + + ' background: -o-linear-gradient(#f7f7f7, #e8e8e8);\n' + + ' background: linear-gradient(#f7f7f7, #e8e8e8);\n' + '}' ); @@ -212,11 +190,80 @@ describe(language, function() { ' font-weight: bold;\n' + '}', - '.maps-headline,\n' + + '.maps-headline,\n' + '.maps-subline,\n' + '.chart-headline,\n' + - '.chart-subline {\n' + - ' font-weight: bold;\n' + + '.chart-subline {\n' + + ' font-weight: bold;\n' + '}' ); + + /** + * IE HACKS + */ + + run( + language, + + 'hack for ie6 only', + + '_color: blue;', + + '_color: blue;' + ); + + run( + language, + + 'hack for ie6 and ie7 (aka lte7)', + + '*color: blue;\n'+ + '#color: blue;\n'+ + 'color: blue !ie;', + + '*color: blue;\n'+ + '#color: blue;\n'+ + 'color: blue !ie;' + ); + + run( + language, + + 'hack for ie7+ (aka gt6)', + + 'color/**/: blue;', + + 'color/**/: blue;' + ); + + run( + language, + + 'hack for ie7 and ie8', + + 'color/*\\**/: blue\\9;', + + 'color/*\\**/: blue\\9;' + ); + + run( + language, + + 'hack for ie6+ (aka lte9)', + + 'color: blue\\9;', + + 'color: blue\\9;' + ); + + run( + language, + + 'hack for ie8 and ie9', + + 'color: blue\\0/;', + + 'color: blue\\0/;' + ); + }); diff --git a/tests/language/test.html.js b/tests/language/test.html.js index 5df646f3..49461fd1 100644 --- a/tests/language/test.html.js +++ b/tests/language/test.html.js @@ -93,9 +93,9 @@ describe(language, function() { '', '<style type="text/css">\n' + - ' body span.blah {\n' + - ' background: #000;\n' + - ' color: #fff;\n' + + ' body span.blah {\n' + + ' background: #000;\n' + + ' color: #fff;\n' + ' }\n' + '</style>' ); @@ -114,9 +114,9 @@ describe(language, function() { '', '<style>\n' + - ' body span.blah {\n' + - ' background: #000;\n' + - ' color: #fff;\n' + + ' body span.blah {\n' + + ' background: #000;\n' + + ' color: #fff;\n' + ' }\n' + '</style>' ); diff --git a/themes/solarized-dark.css b/themes/solarized-dark.css index 7f77841e..22107692 100644 --- a/themes/solarized-dark.css +++ b/themes/solarized-dark.css @@ -5,16 +5,18 @@ * * @author Ethan Schoonover * @author David Litmark - * @version 1.0.0 + * @author Fabio Bucci Di Monte (Additional styles for enhanced CSS syntax) + * @version 1.1.0 */ pre { background: #002b36; /* base03 */ - word-wrap: break-word; - margin: 0px; - padding: 10px; + border-color: #333333; color: #839496; /* base0 */ - font-size: 14px; - margin-bottom: 20px; + font-size: 16px; + line-height: 20px; + margin: 0 0 20px 0; + padding: 10px; + word-wrap: break-word; } pre, code { @@ -84,3 +86,55 @@ pre .support.property { pre .variable.global, pre .variable.class, pre .variable.instance { color: #839496; /* base0 */ } + +/** + * Additional styles for enhanced CSS syntax + */ + +pre .entity, pre .mediaquery.type { + font: inherit; +} + +pre .pseudo, pre .vendor-prefix { + font-style: italic; +} + +pre .at-directive, pre .reserved, pre .exception { + font-weight: bold; +} + +pre .hack { + color: #ff0000; /* red */ +} + +pre .selector { + color: #839496; /* base0 */ +} + +pre .at-directive, pre .reserved, pre .exception, pre .attribute-name, pre .mediaquery.type { + color: #b58900; /* yellow */ +} + +pre .method-name { + color: #c5ab0b; /* light yellow */ +} + +pre .constant.numeric, pre .constant.hex-color { + color: #2aa198; /* cyan */ +} + +pre .css-property, pre .mediaquery.feature { + color: #8866dd; /* purple */ +} + +pre .entity.tag { + color: #ad5a18; /* orange */ +} + +pre .constant.path { + color: #268bd2; /* blue */ +} + +pre .vendor-prefix { + opacity: 0.7; +}