2017-05-24 15:10:37 +02:00
|
|
|
module.exports = function(hljs) {
|
|
|
|
var NUM_SUFFIX = '(_[uif](8|16|32|64))?';
|
|
|
|
var CRYSTAL_IDENT_RE = '[a-zA-Z_]\\w*[!?=]?';
|
|
|
|
var RE_STARTER = '!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|' +
|
|
|
|
'>>|>|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';
|
|
|
|
var CRYSTAL_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\][=?]?';
|
|
|
|
var CRYSTAL_KEYWORDS = {
|
|
|
|
keyword:
|
2017-08-14 05:01:11 +02:00
|
|
|
'abstract alias as as? asm begin break case class def do else elsif end ensure enum extend for fun if ' +
|
|
|
|
'include instance_sizeof is_a? lib macro module next nil? of out pointerof private protected rescue responds_to? ' +
|
|
|
|
'return require select self sizeof struct super then type typeof union uninitialized unless until when while with yield ' +
|
|
|
|
'__DIR__ __END_LINE__ __FILE__ __LINE__',
|
2017-05-24 15:10:37 +02:00
|
|
|
literal: 'false nil true'
|
|
|
|
};
|
|
|
|
var SUBST = {
|
|
|
|
className: 'subst',
|
|
|
|
begin: '#{', end: '}',
|
|
|
|
keywords: CRYSTAL_KEYWORDS
|
|
|
|
};
|
|
|
|
var EXPANSION = {
|
|
|
|
className: 'template-variable',
|
|
|
|
variants: [
|
|
|
|
{begin: '\\{\\{', end: '\\}\\}'},
|
|
|
|
{begin: '\\{%', end: '%\\}'}
|
|
|
|
],
|
|
|
|
keywords: CRYSTAL_KEYWORDS
|
|
|
|
};
|
|
|
|
|
|
|
|
function recursiveParen(begin, end) {
|
|
|
|
var
|
|
|
|
contains = [{begin: begin, end: end}];
|
|
|
|
contains[0].contains = contains;
|
|
|
|
return contains;
|
|
|
|
}
|
|
|
|
var STRING = {
|
|
|
|
className: 'string',
|
|
|
|
contains: [hljs.BACKSLASH_ESCAPE, SUBST],
|
|
|
|
variants: [
|
|
|
|
{begin: /'/, end: /'/},
|
|
|
|
{begin: /"/, end: /"/},
|
|
|
|
{begin: /`/, end: /`/},
|
|
|
|
{begin: '%w?\\(', end: '\\)', contains: recursiveParen('\\(', '\\)')},
|
|
|
|
{begin: '%w?\\[', end: '\\]', contains: recursiveParen('\\[', '\\]')},
|
|
|
|
{begin: '%w?{', end: '}', contains: recursiveParen('{', '}')},
|
|
|
|
{begin: '%w?<', end: '>', contains: recursiveParen('<', '>')},
|
|
|
|
{begin: '%w?/', end: '/'},
|
|
|
|
{begin: '%w?%', end: '%'},
|
|
|
|
{begin: '%w?-', end: '-'},
|
|
|
|
{begin: '%w?\\|', end: '\\|'},
|
2017-08-14 05:01:11 +02:00
|
|
|
{begin: /<<-\w+$/, end: /^\s*\w+$/},
|
|
|
|
],
|
|
|
|
relevance: 0,
|
|
|
|
};
|
|
|
|
var Q_STRING = {
|
|
|
|
className: 'string',
|
|
|
|
variants: [
|
|
|
|
{begin: '%q\\(', end: '\\)', contains: recursiveParen('\\(', '\\)')},
|
|
|
|
{begin: '%q\\[', end: '\\]', contains: recursiveParen('\\[', '\\]')},
|
|
|
|
{begin: '%q{', end: '}', contains: recursiveParen('{', '}')},
|
|
|
|
{begin: '%q<', end: '>', contains: recursiveParen('<', '>')},
|
|
|
|
{begin: '%q/', end: '/'},
|
|
|
|
{begin: '%q%', end: '%'},
|
|
|
|
{begin: '%q-', end: '-'},
|
|
|
|
{begin: '%q\\|', end: '\\|'},
|
|
|
|
{begin: /<<-'\w+'$/, end: /^\s*\w+$/},
|
2017-05-24 15:10:37 +02:00
|
|
|
],
|
|
|
|
relevance: 0,
|
|
|
|
};
|
|
|
|
var REGEXP = {
|
|
|
|
begin: '(' + RE_STARTER + ')\\s*',
|
|
|
|
contains: [
|
|
|
|
{
|
|
|
|
className: 'regexp',
|
|
|
|
contains: [hljs.BACKSLASH_ESCAPE, SUBST],
|
|
|
|
variants: [
|
|
|
|
{begin: '//[a-z]*', relevance: 0},
|
|
|
|
{begin: '/', end: '/[a-z]*'},
|
|
|
|
{begin: '%r\\(', end: '\\)', contains: recursiveParen('\\(', '\\)')},
|
|
|
|
{begin: '%r\\[', end: '\\]', contains: recursiveParen('\\[', '\\]')},
|
|
|
|
{begin: '%r{', end: '}', contains: recursiveParen('{', '}')},
|
|
|
|
{begin: '%r<', end: '>', contains: recursiveParen('<', '>')},
|
|
|
|
{begin: '%r/', end: '/'},
|
|
|
|
{begin: '%r%', end: '%'},
|
|
|
|
{begin: '%r-', end: '-'},
|
|
|
|
{begin: '%r\\|', end: '\\|'},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
],
|
|
|
|
relevance: 0
|
|
|
|
};
|
|
|
|
var REGEXP2 = {
|
|
|
|
className: 'regexp',
|
|
|
|
contains: [hljs.BACKSLASH_ESCAPE, SUBST],
|
|
|
|
variants: [
|
|
|
|
{begin: '%r\\(', end: '\\)', contains: recursiveParen('\\(', '\\)')},
|
|
|
|
{begin: '%r\\[', end: '\\]', contains: recursiveParen('\\[', '\\]')},
|
|
|
|
{begin: '%r{', end: '}', contains: recursiveParen('{', '}')},
|
|
|
|
{begin: '%r<', end: '>', contains: recursiveParen('<', '>')},
|
|
|
|
{begin: '%r/', end: '/'},
|
|
|
|
{begin: '%r%', end: '%'},
|
|
|
|
{begin: '%r-', end: '-'},
|
|
|
|
{begin: '%r\\|', end: '\\|'},
|
|
|
|
],
|
|
|
|
relevance: 0
|
|
|
|
};
|
|
|
|
var ATTRIBUTE = {
|
|
|
|
className: 'meta',
|
|
|
|
begin: '@\\[', end: '\\]',
|
|
|
|
contains: [
|
|
|
|
hljs.inherit(hljs.QUOTE_STRING_MODE, {className: 'meta-string'})
|
|
|
|
]
|
|
|
|
};
|
|
|
|
var CRYSTAL_DEFAULT_CONTAINS = [
|
|
|
|
EXPANSION,
|
|
|
|
STRING,
|
2017-08-14 05:01:11 +02:00
|
|
|
Q_STRING,
|
2017-05-24 15:10:37 +02:00
|
|
|
REGEXP,
|
|
|
|
REGEXP2,
|
|
|
|
ATTRIBUTE,
|
|
|
|
hljs.HASH_COMMENT_MODE,
|
|
|
|
{
|
|
|
|
className: 'class',
|
|
|
|
beginKeywords: 'class module struct', end: '$|;',
|
|
|
|
illegal: /=/,
|
|
|
|
contains: [
|
|
|
|
hljs.HASH_COMMENT_MODE,
|
|
|
|
hljs.inherit(hljs.TITLE_MODE, {begin: '[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?'}),
|
|
|
|
{begin: '<'} // relevance booster for inheritance
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
className: 'class',
|
|
|
|
beginKeywords: 'lib enum union', end: '$|;',
|
|
|
|
illegal: /=/,
|
|
|
|
contains: [
|
|
|
|
hljs.HASH_COMMENT_MODE,
|
|
|
|
hljs.inherit(hljs.TITLE_MODE, {begin: '[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?'}),
|
|
|
|
],
|
|
|
|
relevance: 10
|
|
|
|
},
|
|
|
|
{
|
|
|
|
className: 'function',
|
|
|
|
beginKeywords: 'def', end: /\B\b/,
|
|
|
|
contains: [
|
|
|
|
hljs.inherit(hljs.TITLE_MODE, {
|
|
|
|
begin: CRYSTAL_METHOD_RE,
|
|
|
|
endsParent: true
|
|
|
|
})
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
className: 'function',
|
|
|
|
beginKeywords: 'fun macro', end: /\B\b/,
|
|
|
|
contains: [
|
|
|
|
hljs.inherit(hljs.TITLE_MODE, {
|
|
|
|
begin: CRYSTAL_METHOD_RE,
|
|
|
|
endsParent: true
|
|
|
|
})
|
|
|
|
],
|
|
|
|
relevance: 5
|
|
|
|
},
|
|
|
|
{
|
|
|
|
className: 'symbol',
|
|
|
|
begin: hljs.UNDERSCORE_IDENT_RE + '(\\!|\\?)?:',
|
|
|
|
relevance: 0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
className: 'symbol',
|
|
|
|
begin: ':',
|
|
|
|
contains: [STRING, {begin: CRYSTAL_METHOD_RE}],
|
|
|
|
relevance: 0
|
|
|
|
},
|
|
|
|
{
|
|
|
|
className: 'number',
|
|
|
|
variants: [
|
|
|
|
{ begin: '\\b0b([01_]*[01])' + NUM_SUFFIX },
|
|
|
|
{ begin: '\\b0o([0-7_]*[0-7])' + NUM_SUFFIX },
|
|
|
|
{ begin: '\\b0x([A-Fa-f0-9_]*[A-Fa-f0-9])' + NUM_SUFFIX },
|
|
|
|
{ begin: '\\b(([0-9][0-9_]*[0-9]|[0-9])(\\.[0-9_]*[0-9])?([eE][+-]?[0-9_]*[0-9])?)' + NUM_SUFFIX}
|
|
|
|
],
|
|
|
|
relevance: 0
|
|
|
|
}
|
|
|
|
];
|
|
|
|
SUBST.contains = CRYSTAL_DEFAULT_CONTAINS;
|
|
|
|
EXPANSION.contains = CRYSTAL_DEFAULT_CONTAINS.slice(1); // without EXPANSION
|
|
|
|
|
|
|
|
return {
|
|
|
|
aliases: ['cr'],
|
|
|
|
lexemes: CRYSTAL_IDENT_RE,
|
|
|
|
keywords: CRYSTAL_KEYWORDS,
|
|
|
|
contains: CRYSTAL_DEFAULT_CONTAINS
|
|
|
|
};
|
|
|
|
};
|