1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | function elixir(hljs) {
|
11 | const regex = hljs.regex;
|
12 | const ELIXIR_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_.]*(!|\\?)?';
|
13 | const ELIXIR_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?';
|
14 | const KEYWORDS = [
|
15 | "after",
|
16 | "alias",
|
17 | "and",
|
18 | "case",
|
19 | "catch",
|
20 | "cond",
|
21 | "defstruct",
|
22 | "do",
|
23 | "else",
|
24 | "end",
|
25 | "fn",
|
26 | "for",
|
27 | "if",
|
28 | "import",
|
29 | "in",
|
30 | "not",
|
31 | "or",
|
32 | "quote",
|
33 | "raise",
|
34 | "receive",
|
35 | "require",
|
36 | "reraise",
|
37 | "rescue",
|
38 | "try",
|
39 | "unless",
|
40 | "unquote",
|
41 | "unquote_splicing",
|
42 | "use",
|
43 | "when",
|
44 | "with|0"
|
45 | ];
|
46 | const LITERALS = [
|
47 | "false",
|
48 | "nil",
|
49 | "true"
|
50 | ];
|
51 | const KWS = {
|
52 | $pattern: ELIXIR_IDENT_RE,
|
53 | keyword: KEYWORDS,
|
54 | literal: LITERALS
|
55 | };
|
56 | const SUBST = {
|
57 | className: 'subst',
|
58 | begin: /#\{/,
|
59 | end: /\}/,
|
60 | keywords: KWS
|
61 | };
|
62 | const NUMBER = {
|
63 | className: 'number',
|
64 | begin: '(\\b0o[0-7_]+)|(\\b0b[01_]+)|(\\b0x[0-9a-fA-F_]+)|(-?\\b[0-9][0-9_]*(\\.[0-9_]+([eE][-+]?[0-9]+)?)?)',
|
65 | relevance: 0
|
66 | };
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | const ESCAPES_RE = /\\[\s\S]/;
|
73 |
|
74 | const BACKSLASH_ESCAPE = {
|
75 | match: ESCAPES_RE,
|
76 | scope: "char.escape",
|
77 | relevance: 0
|
78 | };
|
79 | const SIGIL_DELIMITERS = '[/|([{<"\']';
|
80 | const SIGIL_DELIMITER_MODES = [
|
81 | {
|
82 | begin: /"/,
|
83 | end: /"/
|
84 | },
|
85 | {
|
86 | begin: /'/,
|
87 | end: /'/
|
88 | },
|
89 | {
|
90 | begin: /\//,
|
91 | end: /\//
|
92 | },
|
93 | {
|
94 | begin: /\|/,
|
95 | end: /\|/
|
96 | },
|
97 | {
|
98 | begin: /\(/,
|
99 | end: /\)/
|
100 | },
|
101 | {
|
102 | begin: /\[/,
|
103 | end: /\]/
|
104 | },
|
105 | {
|
106 | begin: /\{/,
|
107 | end: /\}/
|
108 | },
|
109 | {
|
110 | begin: /</,
|
111 | end: />/
|
112 | }
|
113 | ];
|
114 | const escapeSigilEnd = (end) => {
|
115 | return {
|
116 | scope: "char.escape",
|
117 | begin: regex.concat(/\\/, end),
|
118 | relevance: 0
|
119 | };
|
120 | };
|
121 | const LOWERCASE_SIGIL = {
|
122 | className: 'string',
|
123 | begin: '~[a-z]' + '(?=' + SIGIL_DELIMITERS + ')',
|
124 | contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
|
125 | {
|
126 | contains: [
|
127 | escapeSigilEnd(x.end),
|
128 | BACKSLASH_ESCAPE,
|
129 | SUBST
|
130 | ]
|
131 | }
|
132 | ))
|
133 | };
|
134 |
|
135 | const UPCASE_SIGIL = {
|
136 | className: 'string',
|
137 | begin: '~[A-Z]' + '(?=' + SIGIL_DELIMITERS + ')',
|
138 | contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
|
139 | {
|
140 | contains: [ escapeSigilEnd(x.end) ]
|
141 | }
|
142 | ))
|
143 | };
|
144 |
|
145 | const REGEX_SIGIL = {
|
146 | className: 'regex',
|
147 | variants: [
|
148 | {
|
149 | begin: '~r' + '(?=' + SIGIL_DELIMITERS + ')',
|
150 | contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
|
151 | {
|
152 | end: regex.concat(x.end, /[uismxfU]{0,7}/),
|
153 | contains: [
|
154 | escapeSigilEnd(x.end),
|
155 | BACKSLASH_ESCAPE,
|
156 | SUBST
|
157 | ]
|
158 | }
|
159 | ))
|
160 | },
|
161 | {
|
162 | begin: '~R' + '(?=' + SIGIL_DELIMITERS + ')',
|
163 | contains: SIGIL_DELIMITER_MODES.map(x => hljs.inherit(x,
|
164 | {
|
165 | end: regex.concat(x.end, /[uismxfU]{0,7}/),
|
166 | contains: [ escapeSigilEnd(x.end) ]
|
167 | })
|
168 | )
|
169 | }
|
170 | ]
|
171 | };
|
172 |
|
173 | const STRING = {
|
174 | className: 'string',
|
175 | contains: [
|
176 | hljs.BACKSLASH_ESCAPE,
|
177 | SUBST
|
178 | ],
|
179 | variants: [
|
180 | {
|
181 | begin: /"""/,
|
182 | end: /"""/
|
183 | },
|
184 | {
|
185 | begin: /'''/,
|
186 | end: /'''/
|
187 | },
|
188 | {
|
189 | begin: /~S"""/,
|
190 | end: /"""/,
|
191 | contains: []
|
192 | },
|
193 | {
|
194 | begin: /~S"/,
|
195 | end: /"/,
|
196 | contains: []
|
197 | },
|
198 | {
|
199 | begin: /~S'''/,
|
200 | end: /'''/,
|
201 | contains: []
|
202 | },
|
203 | {
|
204 | begin: /~S'/,
|
205 | end: /'/,
|
206 | contains: []
|
207 | },
|
208 | {
|
209 | begin: /'/,
|
210 | end: /'/
|
211 | },
|
212 | {
|
213 | begin: /"/,
|
214 | end: /"/
|
215 | }
|
216 | ]
|
217 | };
|
218 | const FUNCTION = {
|
219 | className: 'function',
|
220 | beginKeywords: 'def defp defmacro defmacrop',
|
221 | end: /\B\b/,
|
222 | contains: [
|
223 | hljs.inherit(hljs.TITLE_MODE, {
|
224 | begin: ELIXIR_IDENT_RE,
|
225 | endsParent: true
|
226 | })
|
227 | ]
|
228 | };
|
229 | const CLASS = hljs.inherit(FUNCTION, {
|
230 | className: 'class',
|
231 | beginKeywords: 'defimpl defmodule defprotocol defrecord',
|
232 | end: /\bdo\b|$|;/
|
233 | });
|
234 | const ELIXIR_DEFAULT_CONTAINS = [
|
235 | STRING,
|
236 | REGEX_SIGIL,
|
237 | UPCASE_SIGIL,
|
238 | LOWERCASE_SIGIL,
|
239 | hljs.HASH_COMMENT_MODE,
|
240 | CLASS,
|
241 | FUNCTION,
|
242 | {
|
243 | begin: '::'
|
244 | },
|
245 | {
|
246 | className: 'symbol',
|
247 | begin: ':(?![\\s:])',
|
248 | contains: [
|
249 | STRING,
|
250 | {
|
251 | begin: ELIXIR_METHOD_RE
|
252 | }
|
253 | ],
|
254 | relevance: 0
|
255 | },
|
256 | {
|
257 | className: 'symbol',
|
258 | begin: ELIXIR_IDENT_RE + ':(?!:)',
|
259 | relevance: 0
|
260 | },
|
261 | NUMBER,
|
262 | {
|
263 | className: 'variable',
|
264 | begin: '(\\$\\W)|((\\$|@@?)(\\w+))'
|
265 | },
|
266 | {
|
267 | begin: '->'
|
268 | }
|
269 | ];
|
270 | SUBST.contains = ELIXIR_DEFAULT_CONTAINS;
|
271 |
|
272 | return {
|
273 | name: 'Elixir',
|
274 | aliases: ['ex', 'exs'],
|
275 | keywords: KWS,
|
276 | contains: ELIXIR_DEFAULT_CONTAINS
|
277 | };
|
278 | }
|
279 |
|
280 | export { elixir as default };
|