123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- /*
- Language: Less
- Description: It's CSS, with just a little more.
- Author: Max Mikhailov <seven.phases.max@gmail.com>
- Website: http://lesscss.org
- Category: common, css
- */
- export default function (hljs) {
- var IDENT_RE = '[\\w-]+'; // yes, Less identifiers may begin with a digit
- var INTERP_IDENT_RE = '(' + IDENT_RE + '|@{' + IDENT_RE + '})';
- /* Generic Modes */
- var RULES = [];
- var VALUE = []; // forward def. for recursive modes
- var STRING_MODE = function (c) {
- return {
- // Less strings are not multiline (also include '~' for more consistent coloring of "escaped" strings)
- className: 'string',
- begin: '~?' + c + '.*?' + c
- };
- };
- var IDENT_MODE = function (name, begin, relevance) {
- return {
- className: name,
- begin: begin,
- relevance: relevance
- };
- };
- var PARENS_MODE = {
- // used only to properly balance nested parens inside mixin call, def. arg list
- begin: '\\(',
- end: '\\)',
- contains: VALUE,
- relevance: 0
- };
- // generic Less highlighter (used almost everywhere except selectors):
- VALUE.push(
- hljs.C_LINE_COMMENT_MODE,
- hljs.C_BLOCK_COMMENT_MODE,
- STRING_MODE("'"),
- STRING_MODE('"'),
- hljs.CSS_NUMBER_MODE,
- // fixme: it does not include dot for numbers like .5em :(
- {
- begin: '(url|data-uri)\\(',
- starts: {
- className: 'string',
- end: '[\\)\\n]',
- excludeEnd: true
- }
- },
- IDENT_MODE('number', '#[0-9A-Fa-f]+\\b'),
- PARENS_MODE,
- IDENT_MODE('variable', '@@?' + IDENT_RE, 10),
- IDENT_MODE('variable', '@{' + IDENT_RE + '}'),
- IDENT_MODE('built_in', '~?`[^`]*?`'),
- // inline javascript (or whatever host language) *multiline* string
- {
- // @media features (it’s here to not duplicate things in AT_RULE_MODE with extra PARENS_MODE overriding):
- className: 'attribute',
- begin: IDENT_RE + '\\s*:',
- end: ':',
- returnBegin: true,
- excludeEnd: true
- },
- {
- className: 'meta',
- begin: '!important'
- }
- );
- var VALUE_WITH_RULESETS = VALUE.concat({
- begin: '{',
- end: '}',
- contains: RULES
- });
- var MIXIN_GUARD_MODE = {
- beginKeywords: 'when',
- endsWithParent: true,
- contains: [
- {
- beginKeywords: 'and not'
- }
- ].concat(VALUE) // using this form to override VALUE’s 'function' match
- };
- /* Rule-Level Modes */
- var RULE_MODE = {
- begin: INTERP_IDENT_RE + '\\s*:',
- returnBegin: true,
- end: '[;}]',
- relevance: 0,
- contains: [
- {
- className: 'attribute',
- begin: INTERP_IDENT_RE,
- end: ':',
- excludeEnd: true,
- starts: {
- endsWithParent: true,
- illegal: '[<=$]',
- relevance: 0,
- contains: VALUE
- }
- }
- ]
- };
- var AT_RULE_MODE = {
- className: 'keyword',
- begin: '@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b',
- starts: {
- end: '[;{}]',
- returnEnd: true,
- contains: VALUE,
- relevance: 0
- }
- };
- // variable definitions and calls
- var VAR_RULE_MODE = {
- className: 'variable',
- variants: [
- // using more strict pattern for higher relevance to increase chances of Less detection.
- // this is *the only* Less specific statement used in most of the sources, so...
- // (we’ll still often loose to the css-parser unless there's '//' comment,
- // simply because 1 variable just can't beat 99 properties :)
- {
- begin: '@' + IDENT_RE + '\\s*:',
- relevance: 15
- },
- {
- begin: '@' + IDENT_RE
- }
- ],
- starts: {
- end: '[;}]',
- returnEnd: true,
- contains: VALUE_WITH_RULESETS
- }
- };
- var SELECTOR_MODE = {
- // first parse unambiguous selectors (i.e. those not starting with tag)
- // then fall into the scary lookahead-discriminator variant.
- // this mode also handles mixin definitions and calls
- variants: [
- {
- begin: '[\\.#:&\\[>]',
- end: '[;{}]' // mixin calls end with ';'
- },
- {
- begin: INTERP_IDENT_RE,
- end: '{'
- }
- ],
- returnBegin: true,
- returnEnd: true,
- illegal: '[<=\'$"]',
- relevance: 0,
- contains: [
- hljs.C_LINE_COMMENT_MODE,
- hljs.C_BLOCK_COMMENT_MODE,
- MIXIN_GUARD_MODE,
- IDENT_MODE('keyword', 'all\\b'),
- IDENT_MODE('variable', '@{' + IDENT_RE + '}'),
- // otherwise it’s identified as tag
- IDENT_MODE('selector-tag', INTERP_IDENT_RE + '%?', 0),
- // '%' for more consistent coloring of @keyframes "tags"
- IDENT_MODE('selector-id', '#' + INTERP_IDENT_RE),
- IDENT_MODE('selector-class', '\\.' + INTERP_IDENT_RE, 0),
- IDENT_MODE('selector-tag', '&', 0),
- {
- className: 'selector-attr',
- begin: '\\[',
- end: '\\]'
- },
- {
- className: 'selector-pseudo',
- begin: /:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/
- },
- {
- begin: '\\(',
- end: '\\)',
- contains: VALUE_WITH_RULESETS
- },
- // argument list of parametric mixins
- {
- begin: '!important'
- } // eat !important after mixin call or it will be colored as tag
- ]
- };
- RULES.push(hljs.C_LINE_COMMENT_MODE, hljs.C_BLOCK_COMMENT_MODE, AT_RULE_MODE, VAR_RULE_MODE, RULE_MODE, SELECTOR_MODE);
- return {
- name: 'Less',
- case_insensitive: true,
- illegal: '[=>\'/<($"]',
- contains: RULES
- };
- }
|