diff --git a/js/language/scss.js b/js/language/scss.js new file mode 100644 index 00000000..26b4658d --- /dev/null +++ b/js/language/scss.js @@ -0,0 +1,832 @@ +/** + * SCSS patterns + * + * @author Fabio Bucci Di Monte + * @version 1.0.1 + */ +!function(){ + + 'use strict'; + + var regexes = { + + /* common */ + anyChars : /(.+)/g,// <- added for SCSS + commonName : /(?=-?[\w#]+)((?:[\w-]+)*(?:#\{[^}]+})?(?:[\w-]*\w+)*)/g,// <- enhanced for SCSS (interpolations) + parameters : /\((.*)\)/g,// <- enhanced for SCSS (accepts void parameters) + parametersEnhanced : /\((.*)\)/g,// <- added for SCSS (same regex as above) + + /* reserved words / symbols */ + atDirective : /(?:@[a-z]+)/g, + exception : /!(?:important|default|optional)(?= *;)/g,// <- enhanced for SCSS + reserved : /(?:and|or|not|in|from|through|to(?! (?:top|bottom|right|left)))/g,// <- enhanced for SCSS + + /* comments */ + commentMulti : /\/\*([^]*?)\*\//gm,// <- enhanced for SCSS (interpolations) + commentSingle : /\/\/(.*?)$/gm,// <- added for SCSS + + /* 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,// <- enhanced for SCSS (grouped string content for interpolations recognition) + 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, + cssMethodEnhanced : /(?=(?:-?[\w#{$} "'!=*/+])+\(.*\))((?:[\w-]+)*(?:#\{[^}]+})?(?:[\w-]*\w+)*)(\(.*\))/g,// <- added for SCSS + cssSelector : /((?:[\w.#:()%+>~\[="\] -]|\{.+}|,\s?|&(?:gt|amp);)+)(?=\{)/g,// <- enhanced for SCSS (interpolations, placeholders, parent selectors) + + /* ie hacks */ + cssPropertyWithHack : /([\*\+#_])?([a-z-]+)( *\/\*(?:\\\*)?\*\/)?(?= *:)/g, + hackValue : /((?:\\0|\\9|\\0\\9|\\9\\0)|!\w+?|\\0\/)(?= *[;}])/g, + ieHacks : /(_)|(\*|#|!.+)|(\*?\+|\+\*?)|(\\9)|(\\0\\9|\\9\\0)|(\/\*(?:\\\*)?\*\/)|(\\0\/)/g, + + // TODO: improve entity regexes - eg. change [\w-]+ into \w+(?:-\w+)* + /* entities */ + entityClass : /\.(?!\.)[\w-]*(#\{[^}]+})?[\w-]*/g,// <- enhanced for SCSS (interpolations) + entityId : /#(?!#[^{])[\w-]*(#\{[^}]+})?[\w-]*/g,// <- enhanced for SCSS (interpolations) + entityPseudo : /::?(?!::?)[a-z-]*(#\{[^}]+})?[a-z-]*/g,// <- enhanced for SCSS (interpolations) + entityTag : /[a-z]+\d?(#\{[^}]+})?(?! *:.*;)/gi,// <- enhanced for SCSS (interpolations) + entityAttribute : /\[([\w#{$}-]+)=(("|')?[\w#{$}-]+\3)]/g,// <- enhanced for SCSS (interpolations) + entityParent : /(?:&|&)(?!(?:&|&))/g,// <- added for SCSS + entityPlaceholder : /%(?!%)\w+(?:-\w+)*/g,// <- added for SCSS + + /* 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, + + /* scss only */ + constant : /\b(?:true|false|null)\b/g, + variable : /\$\w+(?:-\w+)*/g, + operator : /(&[lg]t;|<|>|==|!=|\/|\*|\+|\-)(?!\1)/g, + interpolation : /#\{([^}]+)}/g, + + /* scss directives */ + scssList : /\(((?:[^,\s]+ ?, ?)+)([^,\s]+)\)/g, + scssExtend : /(@extend) +([.#%]?\w+(?:-\w+)*)(?= *;)/g, + scssImport : /(@import) +(('|").+\3)(?= *;)/g, + scssInclude : /(@include) +(\w+(?:-\w+)*)(\(.*\))?(?= *(?:;|\{))/g, + scssMethod : /(@function) +(\w+(?:-\w+)*)(\(.*\))/g, + scssMixin : /(@mixin) +(\w+(?:-\w+)*)(?: *(\(.*\)))?(?= *\{)?/g, + scssLoopFor : /(@for) +(.+)(?= *\{)/g, + scssLoopEach : /(@each) +(.+)(?= *\{)/g, + scssLoopWhile : /(@while)(?: |\((?=.+\)))+(.+?)\)?(?= *\{)/g, + scssCondition : /(@(?:else )?if)(?: |\((?=.+\)))+(.+?)\)?(?= *\{)/g, + scssTernary : /\b(if) *(\(.+,.+,.+\))/g, + scssMaps : /\(((?:\s*(?:("|')?\w+(?:-\w+)*\2 *: *.+|\/\*[^]*?\*\/|\/\/.*?$))+\s*\))(?=;)/gm, + + /* scss directives syntax */ + scssLoopForSyntax : /(.+) +(from) +(.+) +(to|through) +(.+)/g, + scssLoopEachSyntax : /(.+) +(in) +(.+)/g, + scssLoopWhileSyntax : /(.+) +(.+) +(.+)/g, + scssTernarySyntax : /\((.+),(.+),(.+)\)/g, + scssMapsSyntax : /(("|')?\w+(?:-\w+)*\2) *: *((?:[\w"' $\(\),\*\+-]|\/(?!\/))+)(?=,.*\n?|\n?\s*\)| \/\/)/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 operator = { + name: 'constant.operator', + pattern: regexes.operator + }; + + var constant = { + name: 'scss.constant', + pattern: regexes.constant + }; + + var variable = { + name: 'scss.variable', + pattern: regexes.variable + }; + + 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 = [ + operator, + variable, + constant, + type.number, + type.path, + type.text, + type.string, + type.hex + ]; + + var scssList = { + name: 'scss.list', + matches: { + 1: arr_parameters, + 2: arr_parameters + }, + pattern: regexes.scssList + }; + + arr_parameters.unshift(scssList); + + /******************** + * 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: 'method-name', + matches: { + 1: [prefix] + }, + pattern: regexes.commonName + } + ], + 2: [ + { + name: 'method-params', + matches: { + 1: arr_parameters + }, + pattern: regexes.parameters + } + ] + }, + pattern: regexes.cssMethod + }; + + // method inside a method (as parameter) – note: weirdly there is no easier way to achieve the same result.. + var cssMethodsEnhanced = { + name: cssMethods.name, + matches: { + 1: cssMethods.matches[1], + 2: [ + { + name: cssMethods.matches[2][0].name, + matches: { + 1: [cssMethods].concat(arr_parameters) + }, + pattern: regexes.parametersEnhanced// same as regexps.parameters (won't work if using the same) (??) + } + ] + }, + pattern: regexes.cssMethodEnhanced + }; + + var interpolation = { + name: 'scss.interpolation', + matches: { + 1: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.interpolation + }; + + // interpolation inside a string + arr_parameters.unshift({ + name: 'string', + matches: { + 2: [interpolation] + }, + pattern: regexes.valueString + }); + + // interpolation inside method name + // TODO (fix) weirdly will not consider methods inside interpolation that is part of another method's name + // eg: #{unquote($type)}-gradient($params); // unquote() method will not be recognized + cssMethodsEnhanced.matches['1'][0].matches['1'] = [prefix,interpolation]; + + // interpolation inside method parameters + cssMethodsEnhanced.matches['2'][0].matches['1'] = [cssMethods].concat(arr_parameters); + + /******************** + * COMMENTS + ********************/ + + var commentMultiline = { + name: 'comment', + matches: { + 1: [interpolation] + }, + pattern: regexes.commentMulti + }; + + var commentSingleline = { + name: 'scss.comment', + matches: { + 1: [interpolation] + }, + pattern: regexes.commentSingle + }; + + var arr_comments = [ + commentMultiline, + commentSingleline + ]; + + /******************** + * SELECTORS + ********************/ + + var entity = { + scssParent: { + name: 'entity.scss.parent', + pattern: regexes.entityParent + }, + scssPlaceholder: { + name: 'entity.scss.placeholder', + pattern: regexes.entityPlaceholder + }, + cssClass: { + name: 'entity.name.class', + matches: { + 1: [interpolation] + }, + pattern: regexes.entityClass + }, + cssId: { + name: 'entity.name.id', + matches: { + 1: [interpolation] + }, + pattern: regexes.entityId + }, + cssAttribute : { + name: 'entity.name.attribute', + matches: { + 1: [ + interpolation, + type.attribute + ], + 2: [ + interpolation, + type.text, + type.string + ] + }, + pattern: regexes.entityAttribute + }, + cssPseudo: { + name: 'entity.name.pseudo', + matches: { + 1: [interpolation] + }, + pattern: regexes.entityPseudo + }, + cssTag: { + name: 'entity.name.tag', + matches: { + 1: [interpolation] + }, + 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.scssPlaceholder, + entity.cssClass, + entity.cssId, + entity.cssTag + ]; + + var arr_entities = arr_commonEntities.concat([ + entity.cssPseudo, + entity.cssAttribute, + entity.scssParent + ]); + + 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,variable,interpolation], + 2: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.mediaExpression + }; + + media.query = { + name: 'mediaquery.query', + matches: { + 1: [media.reserved], + 2: [ + interpolation, + 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: regexes.mediaQueryRule + }; + + /******************** + * SASS EXTRA + ********************/ + + var maps = { + name: 'scss.map', + matches: { + 1: arr_comments.concat([ + { + name: 'scss.map-pair', + matches: { + 1: 'scss.map-name', + 3: arr_comments.concat([ + { + name: 'scss.map-value', + matches: { + 1: arr_parameters + }, + pattern: regexes.anyChars + } + ]) + }, + pattern: regexes.scssMapsSyntax + } + ]) + }, + pattern: regexes.scssMaps + }; + + var mixin = { + name: 'scss.mixin', + matches: { + 1: [atDirective], + 2: 'scss.mixin-name', + 3: [ + { + name: 'scss.mixin-params', + matches: { + 1: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.parameters + } + ] + }, + pattern: regexes.scssMixin + }; + + // TODO: consider to let all loops recognize methods inside loop expressions + var loops = { + forLoop: { + name: 'scss.loop.for', + matches: { + 1: [atDirective], + 2: [ + { + name: 'scss.loop-condition', + matches: { + 1: [variable], + 2: [reserved], + 3: [ + variable, + type.number + ], + 4: [reserved], + 5: [ + variable, + type.number + ] + }, + pattern: regexes.scssLoopForSyntax + } + ] + }, + pattern: regexes.scssLoopFor + }, + eachLoop: { + name: 'scss.loop.each', + matches: { + 1: [atDirective], + 2: [ + { + name: 'scss.loop-condition', + matches: { + 1: [variable], + 2: [reserved], + 3: [ + scssList, + variable, + type.text + ] + }, + pattern: regexes.scssLoopEachSyntax + } + ] + }, + pattern: regexes.scssLoopEach + }, + whileLoop: { + name: 'scss.loop.while', + matches: { + 1: [atDirective], + 2: [ + { + name: 'scss.loop-condition', + matches: { + 1: [ + variable, + type.number + ], + 2: [operator], + 3: [ + variable, + type.number + ] + }, + pattern: regexes.scssLoopWhileSyntax + } + ] + }, + pattern: regexes.scssLoopWhile + } + }; + + var ternary = { + name: 'scss.condition.ternary', + matches: { + 1: 'scss.ternary-method', + 2: [ + { + name: 'scss.ternary-params', + matches: { + 1: [ + { + name: 'ternary-condition', + matches: { + 1: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.anyChars + } + ], + 2: [ + { + name: 'ternary-true', + matches: { + 1: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.anyChars + } + ], + 3: [ + { + name: 'ternary-false', + matches: { + 1: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.anyChars + } + ] + }, + pattern: regexes.scssTernarySyntax + } + ] + }, + pattern: regexes.scssTernary + }; + + var condition = { + name: 'scss.condition', + matches: { + 1: 'at-directive', + 2: [ + { + name: 'scss.condition-expression', + matches: { + 1: [reserved,cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.anyChars + } + ] + }, + pattern: regexes.scssCondition + }; + + var method = { + name: 'scss.method', + matches: { + 1: [atDirective], + 2: 'scss.method-name', + 3: [ + { + name: 'method-params', + matches: { + 1: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.parameters + } + ] + }, + pattern: regexes.scssMethod + }; + + var extend = { + name: 'scss.extend', + matches: { + 1: [atDirective], + 2: arr_commonEntities + }, + pattern: regexes.scssExtend + }; + + var imports = { + name: 'scss.import', + matches: { + 1: [atDirective], + 2: [type.string] + }, + pattern: regexes.scssImport + }; + + var include = { + name: 'scss.include', + matches: { + 1: [atDirective], + 2: 'scss.mixin-name', + 3: [ + { + name: 'scss.mixin-params', + matches: { + 1: [cssMethodsEnhanced].concat(arr_parameters) + }, + pattern: regexes.parameters + } + ] + }, + pattern: regexes.scssInclude + }; + + /******************** + * RAINBOW EXTENSION + ********************/ + + var cssSyntaxEnhanced = [] + .concat([ + commentMultiline, + exception, + mediaQuery, + atDirective, + cssSelectors, + cssPropertiesHacked, + cssHacks + ]) + .concat(arr_parameters) + .concat([ + cssMethodsEnhanced + ]); + + var scssSyntax = [ + commentSingleline, + interpolation, + maps, + mixin, + loops.forLoop, + loops.eachLoop, + loops.whileLoop, + ternary, + condition, + method, + extend, + imports, + include + ]; + + Rainbow.extend('scss', cssSyntaxEnhanced, true); + Rainbow.extend('scss', scssSyntax, true); + +}(); diff --git a/tests/language/test.scss.js b/tests/language/test.scss.js new file mode 100644 index 00000000..afd50e84 --- /dev/null +++ b/tests/language/test.scss.js @@ -0,0 +1,405 @@ +/* global describe, run */ +var language = 'scss'; + +describe(language, function() { + + /******************** + * FORMER CSS VALIDATION (moved in from test.css.js) + ********************/ + + 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' + + '}' + ); + + /******************** + * CSS ENHANCED + ********************/ + + // attribute selector + run( + language, + + 'attribute selector', + + 'input[type="text"] { cursor: pointer; }\n'+ + 'input[type=text] { cursor: pointer; }', + + 'input[type="text"] { cursor: pointer; }\n'+ + 'input[type=text] { cursor: pointer; }' + ); + + // siblings + run( + language, + + 'child/sibling selectors', + + 'div > p,\n'+ + 'p + p,\n'+ + 'p ~ span {', + + ''+ + 'div > p,\n'+ + 'p + p,\n'+ + 'p ~ span '+ + '{' + ); + + // exception (!important keyword) + run( + language, + + 'keyword exception', + + 'border: none !important;', + + 'border: none !important;' + ); + + // css method + run( + language, + + 'css-method', + + 'rgba(100, 200, 175, .6);', + + ''+ + 'rgba'+ + '('+ + '100, '+ + '200, '+ + '175, '+ + '.6)'+ + ';' + ); + + // asset path + run( + language, + + 'asset path', + + 'url(/path/to/image.jpg);', + + ''+ + 'url'+ + '('+ + '/path/to/image.jpg)'+ + ';' + ); + + // media queries + run( + language, + + 'media query', + + '@media not print and (max-width: 1160px), screen and (orientation: landscape) {', + + ''+ + '@media '+ + ''+ + 'not '+ + 'print '+ + 'and '+ + '('+ + 'max-width: '+ + '1160px)'+ + ', '+ + ''+ + 'screen '+ + 'and '+ + '('+ + 'orientation: '+ + 'landscape)'+ + ' '+ + '{' + ); + + /******************** + * SCSS RESERVED + ********************/ + + // variable + run( + language, + + 'variable', + + '$variable', + + '$variable' + ); + + /******************** + * PLACEHOLDERS + ********************/ + + // placeholder selector + run( + language, + + 'placeholder selector', + + '%placeholder {', + + ''+ + '%placeholder '+ + '{' + ); + + // extend placeholder (@extend directive) + run( + language, + + 'extend placeholder', + + '@extend %placeholder;', + + ''+ + '@extend '+ + '%placeholder'+ + ';' + ); + + /******************** + * MIXINS + ********************/ + + // mixin declaration (@mixin directive) + run( + language, + + 'mixin declaration', + + '@mixin rem($property, $size: 1) {', + + ''+ + '@mixin '+ + 'rem'+ + '('+ + '$property, '+ + '$size: '+ + '1)'+ + ' {' + ); + + // mixin usage (@include directive) + run( + language, + + 'mixin usage', + + '@include rem(\'margin-bottom\', 16);', + + ''+ + '@include '+ + 'rem'+ + '('+ + '\'margin-bottom\', '+ + '16)'+ + ';' + ); + + /******************** + * LOOPS + ********************/ + + // for loop (@for directive) + run( + language, + + 'for loop', + + '@for $i from 1 through 3 {', + + ''+ + '@for '+ + ''+ + '$i '+ + 'from '+ + '1 '+ + 'through '+ + '3 '+ + '{' + ); + + // each loop (@each directive) + run( + language, + + 'each loop', + + '@each $animal in puma, sea-slug, egret, salamander {', + + ''+ + '@each '+ + ''+ + '$animal '+ + 'in '+ + 'puma, '+ + 'sea-slug, '+ + 'egret, '+ + 'salamander '+ + '{' + ); + + // while loop (@while directive) + run( + language, + + 'while loop', + + '@while $i > 0 {', + + ''+ + '@while '+ + ''+ + '$i '+ + '> '+ + '0'+ + ' {' + ); + + /******************** + * FUNCTIONS + ********************/ + + // function declaration (@function directive) + run( + language, + + 'function declaration', + + '@function grid-width($n) {', + + ''+ + '@function '+ + 'grid-width'+ + '('+ + '$n)'+ + ' {' + ); + + /******************** + * CONDITIONS + ********************/ + + // if/else condition (@if/@else directive) + run( + language, + + 'if/else condition', + + '@if $var==true {\n'+ + ' // result if true\n'+ + '} @else if $var==false {\n'+ + ' // result if false\n'+ + '} @else {\n'+ + ' // result if null\n'+ + '}', + + '@if $var==true {\n'+ + ' // result if true\n'+ + '} @else if $var==false {\n'+ + ' // result if false\n'+ + '} @else {\n'+ + ' // result if null\n'+ + '}' + ); + + // ternary condition + run( + language, + + 'ternary condition', + + 'if($bigger==true,28px,24px);', + + ''+ + 'if'+ + '('+ + ''+ + '$bigger'+ + '=='+ + 'true'+ + ','+ + ''+ + '28px'+ + ','+ + ''+ + '24px'+ + ')'+ + ';' + ); + + /******************** + * INTERPOLATIONS + ********************/ + + // simple interpolation + run( + language, + + 'simple interpolation', + + '#{$variable}', + + ''+ + '#{$variable}'+ + '' + ); + + // interpolation as part of selector + run( + language, + + 'interpolation as part of selector', + + '.#{$animal}-icon {', + + ''+ + '.'+ + ''+ + '#{$animal}'+ + ''+ + '-icon '+ + '{' + ); + + // interpolation inside a string + run( + language, + + 'interpolation inside a string', + + '"/images/#{$animal}.png"', + + ''+ + '"/images/'+ + ''+ + '#{$animal}'+ + '.png"'+ + '' + ); + +}); diff --git a/tests/rainbow.html b/tests/rainbow.html index 2ac44d7d..15330280 100644 --- a/tests/rainbow.html +++ b/tests/rainbow.html @@ -18,6 +18,7 @@ + @@ -48,6 +49,7 @@ + diff --git a/themes/solarized-dark.css b/themes/solarized-dark.css index 7f77841e..8511a81f 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 and SCSS syntax) + * @version 1.1.1 */ 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,74 @@ pre .support.property { pre .variable.global, pre .variable.class, pre .variable.instance { color: #839496; /* base0 */ } + +/** + * Additional styles for enhanced CSS syntax and SCSS syntax + */ + +pre .entity, pre .mediaquery.type { + font: inherit; +} + +pre .pseudo, pre .vendor-prefix, +pre .scss.interpolation { + font-style: italic; +} + +pre .at-directive, pre .reserved, pre .exception, +pre .scss.constant, pre .scss.ternary-method { + font-weight: bold; +} + +pre .hack { + color: #ff0000; /* red */ +} + +pre .selector, +pre .scss.interpolation, pre .scss.map-pair { + color: #839496; /* base0 */ +} + +pre .at-directive, pre .reserved, pre .exception, pre .attribute-name, pre .mediaquery.type, +pre .scss.ternary-method { + color: #b58900; /* yellow */ +} + +pre .method-name, +pre .scss.method-name, pre .scss.mixin-name { + color: #c5ab0b; /* light yellow */ +} + +pre .constant.numeric, pre .constant.hex-color { + color: #2aa198; /* cyan */ +} + +pre .css-property, pre .mediaquery.feature, +pre .scss.map-name, pre .scss.map-value { + color: #8866dd; /* purple */ +} + +pre .entity.tag { + color: #ad5a18; /* orange */ +} + +pre .constant.path, +pre .scss.variable { + color: #268bd2; /* blue */ +} + +pre .scss.constant { + color: #859900; /* green */ +} + +pre .scss.interpolation { + background-color: #17436e; /* dark blue */ +} + +pre .scss.map-pair { + background-color: #26254a; /* dark purple */ +} + +pre .vendor-prefix { + opacity: 0.7; +}