1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | function crystal(hljs) {
|
9 | const INT_SUFFIX = '(_?[ui](8|16|32|64|128))?';
|
10 | const FLOAT_SUFFIX = '(_?f(32|64))?';
|
11 | const CRYSTAL_IDENT_RE = '[a-zA-Z_]\\w*[!?=]?';
|
12 | const CRYSTAL_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|[=!]~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~|]|//|//=|&[-+*]=?|&\\*\\*|\\[\\][=?]?';
|
13 | const CRYSTAL_PATH_RE = '[A-Za-z_]\\w*(::\\w+)*(\\?|!)?';
|
14 | const CRYSTAL_KEYWORDS = {
|
15 | $pattern: CRYSTAL_IDENT_RE,
|
16 | keyword:
|
17 | 'abstract alias annotation as as? asm begin break case class def do else elsif end ensure enum extend for fun if ' +
|
18 | 'include instance_sizeof is_a? lib macro module next nil? of out pointerof private protected rescue responds_to? ' +
|
19 | 'return require select self sizeof struct super then type typeof union uninitialized unless until verbatim when while with yield ' +
|
20 | '__DIR__ __END_LINE__ __FILE__ __LINE__',
|
21 | literal: 'false nil true'
|
22 | };
|
23 | const SUBST = {
|
24 | className: 'subst',
|
25 | begin: /#\{/,
|
26 | end: /\}/,
|
27 | keywords: CRYSTAL_KEYWORDS
|
28 | };
|
29 |
|
30 | const VARIABLE = {
|
31 |
|
32 |
|
33 | className: "variable",
|
34 | begin: '(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])' + `(?![A-Za-z])(?![@$?'])`
|
35 | };
|
36 | const EXPANSION = {
|
37 | className: 'template-variable',
|
38 | variants: [
|
39 | {
|
40 | begin: '\\{\\{',
|
41 | end: '\\}\\}'
|
42 | },
|
43 | {
|
44 | begin: '\\{%',
|
45 | end: '%\\}'
|
46 | }
|
47 | ],
|
48 | keywords: CRYSTAL_KEYWORDS
|
49 | };
|
50 |
|
51 | function recursiveParen(begin, end) {
|
52 | const
|
53 | contains = [
|
54 | {
|
55 | begin: begin,
|
56 | end: end
|
57 | }
|
58 | ];
|
59 | contains[0].contains = contains;
|
60 | return contains;
|
61 | }
|
62 | const STRING = {
|
63 | className: 'string',
|
64 | contains: [
|
65 | hljs.BACKSLASH_ESCAPE,
|
66 | SUBST
|
67 | ],
|
68 | variants: [
|
69 | {
|
70 | begin: /'/,
|
71 | end: /'/
|
72 | },
|
73 | {
|
74 | begin: /"/,
|
75 | end: /"/
|
76 | },
|
77 | {
|
78 | begin: /`/,
|
79 | end: /`/
|
80 | },
|
81 | {
|
82 | begin: '%[Qwi]?\\(',
|
83 | end: '\\)',
|
84 | contains: recursiveParen('\\(', '\\)')
|
85 | },
|
86 | {
|
87 | begin: '%[Qwi]?\\[',
|
88 | end: '\\]',
|
89 | contains: recursiveParen('\\[', '\\]')
|
90 | },
|
91 | {
|
92 | begin: '%[Qwi]?\\{',
|
93 | end: /\}/,
|
94 | contains: recursiveParen(/\{/, /\}/)
|
95 | },
|
96 | {
|
97 | begin: '%[Qwi]?<',
|
98 | end: '>',
|
99 | contains: recursiveParen('<', '>')
|
100 | },
|
101 | {
|
102 | begin: '%[Qwi]?\\|',
|
103 | end: '\\|'
|
104 | },
|
105 | {
|
106 | begin: /<<-\w+$/,
|
107 | end: /^\s*\w+$/
|
108 | }
|
109 | ],
|
110 | relevance: 0
|
111 | };
|
112 | const Q_STRING = {
|
113 | className: 'string',
|
114 | variants: [
|
115 | {
|
116 | begin: '%q\\(',
|
117 | end: '\\)',
|
118 | contains: recursiveParen('\\(', '\\)')
|
119 | },
|
120 | {
|
121 | begin: '%q\\[',
|
122 | end: '\\]',
|
123 | contains: recursiveParen('\\[', '\\]')
|
124 | },
|
125 | {
|
126 | begin: '%q\\{',
|
127 | end: /\}/,
|
128 | contains: recursiveParen(/\{/, /\}/)
|
129 | },
|
130 | {
|
131 | begin: '%q<',
|
132 | end: '>',
|
133 | contains: recursiveParen('<', '>')
|
134 | },
|
135 | {
|
136 | begin: '%q\\|',
|
137 | end: '\\|'
|
138 | },
|
139 | {
|
140 | begin: /<<-'\w+'$/,
|
141 | end: /^\s*\w+$/
|
142 | }
|
143 | ],
|
144 | relevance: 0
|
145 | };
|
146 | const REGEXP = {
|
147 | begin: '(?!%\\})(' + hljs.RE_STARTERS_RE + '|\\n|\\b(case|if|select|unless|until|when|while)\\b)\\s*',
|
148 | keywords: 'case if select unless until when while',
|
149 | contains: [
|
150 | {
|
151 | className: 'regexp',
|
152 | contains: [
|
153 | hljs.BACKSLASH_ESCAPE,
|
154 | SUBST
|
155 | ],
|
156 | variants: [
|
157 | {
|
158 | begin: '//[a-z]*',
|
159 | relevance: 0
|
160 | },
|
161 | {
|
162 | begin: '/(?!\\/)',
|
163 | end: '/[a-z]*'
|
164 | }
|
165 | ]
|
166 | }
|
167 | ],
|
168 | relevance: 0
|
169 | };
|
170 | const REGEXP2 = {
|
171 | className: 'regexp',
|
172 | contains: [
|
173 | hljs.BACKSLASH_ESCAPE,
|
174 | SUBST
|
175 | ],
|
176 | variants: [
|
177 | {
|
178 | begin: '%r\\(',
|
179 | end: '\\)',
|
180 | contains: recursiveParen('\\(', '\\)')
|
181 | },
|
182 | {
|
183 | begin: '%r\\[',
|
184 | end: '\\]',
|
185 | contains: recursiveParen('\\[', '\\]')
|
186 | },
|
187 | {
|
188 | begin: '%r\\{',
|
189 | end: /\}/,
|
190 | contains: recursiveParen(/\{/, /\}/)
|
191 | },
|
192 | {
|
193 | begin: '%r<',
|
194 | end: '>',
|
195 | contains: recursiveParen('<', '>')
|
196 | },
|
197 | {
|
198 | begin: '%r\\|',
|
199 | end: '\\|'
|
200 | }
|
201 | ],
|
202 | relevance: 0
|
203 | };
|
204 | const ATTRIBUTE = {
|
205 | className: 'meta',
|
206 | begin: '@\\[',
|
207 | end: '\\]',
|
208 | contains: [
|
209 | hljs.inherit(hljs.QUOTE_STRING_MODE, {
|
210 | className: 'string'
|
211 | })
|
212 | ]
|
213 | };
|
214 | const CRYSTAL_DEFAULT_CONTAINS = [
|
215 | EXPANSION,
|
216 | STRING,
|
217 | Q_STRING,
|
218 | REGEXP2,
|
219 | REGEXP,
|
220 | ATTRIBUTE,
|
221 | VARIABLE,
|
222 | hljs.HASH_COMMENT_MODE,
|
223 | {
|
224 | className: 'class',
|
225 | beginKeywords: 'class module struct',
|
226 | end: '$|;',
|
227 | illegal: /=/,
|
228 | contains: [
|
229 | hljs.HASH_COMMENT_MODE,
|
230 | hljs.inherit(hljs.TITLE_MODE, {
|
231 | begin: CRYSTAL_PATH_RE
|
232 | }),
|
233 | {
|
234 | begin: '<'
|
235 | }
|
236 | ]
|
237 | },
|
238 | {
|
239 | className: 'class',
|
240 | beginKeywords: 'lib enum union',
|
241 | end: '$|;',
|
242 | illegal: /=/,
|
243 | contains: [
|
244 | hljs.HASH_COMMENT_MODE,
|
245 | hljs.inherit(hljs.TITLE_MODE, {
|
246 | begin: CRYSTAL_PATH_RE
|
247 | })
|
248 | ]
|
249 | },
|
250 | {
|
251 | beginKeywords: 'annotation',
|
252 | end: '$|;',
|
253 | illegal: /=/,
|
254 | contains: [
|
255 | hljs.HASH_COMMENT_MODE,
|
256 | hljs.inherit(hljs.TITLE_MODE, {
|
257 | begin: CRYSTAL_PATH_RE
|
258 | })
|
259 | ],
|
260 | relevance: 2
|
261 | },
|
262 | {
|
263 | className: 'function',
|
264 | beginKeywords: 'def',
|
265 | end: /\B\b/,
|
266 | contains: [
|
267 | hljs.inherit(hljs.TITLE_MODE, {
|
268 | begin: CRYSTAL_METHOD_RE,
|
269 | endsParent: true
|
270 | })
|
271 | ]
|
272 | },
|
273 | {
|
274 | className: 'function',
|
275 | beginKeywords: 'fun macro',
|
276 | end: /\B\b/,
|
277 | contains: [
|
278 | hljs.inherit(hljs.TITLE_MODE, {
|
279 | begin: CRYSTAL_METHOD_RE,
|
280 | endsParent: true
|
281 | })
|
282 | ],
|
283 | relevance: 2
|
284 | },
|
285 | {
|
286 | className: 'symbol',
|
287 | begin: hljs.UNDERSCORE_IDENT_RE + '(!|\\?)?:',
|
288 | relevance: 0
|
289 | },
|
290 | {
|
291 | className: 'symbol',
|
292 | begin: ':',
|
293 | contains: [
|
294 | STRING,
|
295 | {
|
296 | begin: CRYSTAL_METHOD_RE
|
297 | }
|
298 | ],
|
299 | relevance: 0
|
300 | },
|
301 | {
|
302 | className: 'number',
|
303 | variants: [
|
304 | {
|
305 | begin: '\\b0b([01_]+)' + INT_SUFFIX
|
306 | },
|
307 | {
|
308 | begin: '\\b0o([0-7_]+)' + INT_SUFFIX
|
309 | },
|
310 | {
|
311 | begin: '\\b0x([A-Fa-f0-9_]+)' + INT_SUFFIX
|
312 | },
|
313 | {
|
314 | begin: '\\b([1-9][0-9_]*[0-9]|[0-9])(\\.[0-9][0-9_]*)?([eE]_?[-+]?[0-9_]*)?' + FLOAT_SUFFIX + '(?!_)'
|
315 | },
|
316 | {
|
317 | begin: '\\b([1-9][0-9_]*|0)' + INT_SUFFIX
|
318 | }
|
319 | ],
|
320 | relevance: 0
|
321 | }
|
322 | ];
|
323 | SUBST.contains = CRYSTAL_DEFAULT_CONTAINS;
|
324 | EXPANSION.contains = CRYSTAL_DEFAULT_CONTAINS.slice(1);
|
325 |
|
326 | return {
|
327 | name: 'Crystal',
|
328 | aliases: [ 'cr' ],
|
329 | keywords: CRYSTAL_KEYWORDS,
|
330 | contains: CRYSTAL_DEFAULT_CONTAINS
|
331 | };
|
332 | }
|
333 |
|
334 | export { crystal as default };
|