1%YAML 1.2
2---
3# http://www.sublimetext.com/docs/3/syntax.html
4name: Nix
5file_extensions:
6  - nix
7scope: source.nix
8contexts:
9  main:
10    - include: expression
11  comment:
12    - match: '/\*([^*]|\*[^\/])*'
13      push:
14        - meta_scope: comment.block.nix
15        - match: \*\/
16          pop: true
17        - include: comment-remark
18    - match: '\#'
19      push:
20        - meta_scope: comment.line.number-sign.nix
21        - match: $
22          pop: true
23        - include: comment-remark
24  attribute-bind:
25    - include: attribute-name
26    - include: attribute-bind-from-equals
27  attribute-bind-from-equals:
28    - match: \=
29      captures:
30        0: keyword.operator.bind.nix
31      push:
32        - match: \;
33          captures:
34            0: punctuation.terminator.bind.nix
35          pop: true
36        - include: expression
37  attribute-inherit:
38    - match: \binherit\b
39      captures:
40        0: keyword.other.inherit.nix
41      push:
42        - match: \;
43          captures:
44            0: punctuation.terminator.inherit.nix
45          pop: true
46        - match: \(
47          captures:
48            0: punctuation.section.function.arguments.nix
49          push:
50            - match: (?=\;)
51              pop: true
52            - match: \)
53              captures:
54                0: punctuation.section.function.arguments.nix
55              push:
56                - match: (?=\;)
57                  pop: true
58                - include: bad-reserved
59                - include: attribute-name-single
60                - include: others
61            - include: expression
62        - match: '(?=[a-zA-Z\_])'
63          push:
64            - match: (?=\;)
65              pop: true
66            - include: bad-reserved
67            - include: attribute-name-single
68            - include: others
69        - include: others
70  attribute-name:
71    - match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
72      scope: entity.other.attribute-name.multipart.nix
73    - match: \.
74    - include: string-quoted
75    - include: interpolation
76  attribute-name-single:
77    - match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
78      scope: entity.other.attribute-name.single.nix
79  attrset-contents:
80    - include: attribute-inherit
81    - include: bad-reserved
82    - include: attribute-bind
83    - include: others
84  attrset-definition:
85    - match: '(?=\{)'
86      push:
87        - match: '(?=([\])};,]|\b(else|then)\b))'
88          pop: true
89        - match: '(\{)'
90          captures:
91            0: punctuation.definition.attrset.nix
92          push:
93            - match: '(\})'
94              captures:
95                0: punctuation.definition.attrset.nix
96              pop: true
97            - include: attrset-contents
98        - match: '(?<=\})'
99          push:
100            - match: '(?=([\])};,]|\b(else|then)\b))'
101              pop: true
102            - include: expression-cont
103  attrset-definition-brace-opened:
104    - match: '(?<=\})'
105      push:
106        - match: '(?=([\])};,]|\b(else|then)\b))'
107          pop: true
108        - include: expression-cont
109    - match: (?=.?)
110      push:
111        - match: '\}'
112          captures:
113            0: punctuation.definition.attrset.nix
114          pop: true
115        - include: attrset-contents
116  attrset-for-sure:
117    - match: (?=\brec\b)
118      push:
119        - match: '(?=([\])};,]|\b(else|then)\b))'
120          pop: true
121        - match: \brec\b
122          captures:
123            0: keyword.other.nix
124          push:
125            - match: '(?=\{)'
126              pop: true
127            - include: others
128        - include: attrset-definition
129        - include: others
130    - match: '(?=\{\s*(\}|[^,?]*(=|;)))'
131      push:
132        - match: '(?=([\])};,]|\b(else|then)\b))'
133          pop: true
134        - include: attrset-definition
135        - include: others
136  attrset-or-function:
137    - match: '\{'
138      captures:
139        0: punctuation.definition.attrset-or-function.nix
140      push:
141        - match: '(?=([\])};]|\b(else|then)\b))'
142          pop: true
143        - match: '(?=(\s*\}|\"|\binherit\b|\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*(\s*\.|\s*=[^=])|\$\{[a-zA-z0-9\_\''\-]+\}(\s*\.|\s*=[^=])))'
144          push:
145            - match: '(?=([\])};,]|\b(else|then)\b))'
146              pop: true
147            - include: attrset-definition-brace-opened
148        - match: '(?=(\.\.\.|\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*\s*[,?]))'
149          push:
150            - match: '(?=([\])};,]|\b(else|then)\b))'
151              pop: true
152            - include: function-definition-brace-opened
153        - include: bad-reserved
154        - match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
155          captures:
156            0: variable.parameter.function.maybe.nix
157          push:
158            - match: '(?=([\])};]|\b(else|then)\b))'
159              pop: true
160            - match: (?=\.)
161              push:
162                - match: '(?=([\])};,]|\b(else|then)\b))'
163                  pop: true
164                - include: attrset-definition-brace-opened
165            - match: \s*(\,)
166              captures:
167                1: keyword.operator.nix
168              push:
169                - match: '(?=([\])};,]|\b(else|then)\b))'
170                  pop: true
171                - include: function-definition-brace-opened
172            - match: (?=\=)
173              push:
174                - match: '(?=([\])};,]|\b(else|then)\b))'
175                  pop: true
176                - include: attribute-bind-from-equals
177                - include: attrset-definition-brace-opened
178            - match: (?=\?)
179              push:
180                - match: '(?=([\])};,]|\b(else|then)\b))'
181                  pop: true
182                - include: function-parameter-default
183                - match: \,
184                  captures:
185                    0: keyword.operator.nix
186                  push:
187                    - match: '(?=([\])};,]|\b(else|then)\b))'
188                      pop: true
189                    - include: function-definition-brace-opened
190            - include: others
191        - include: others
192  bad-reserved:
193    - match: '(?<![\w''-])(if|then|else|assert|with|let|in|rec|inherit)(?![\w''-])'
194      scope: invalid.illegal.reserved.nix
195  comment-remark:
196    - match: (TODO|FIXME|BUG|\!\!\!):?
197      captures:
198        1: markup.bold.comment.nix
199  constants:
200    - match: \b(builtins|true|false|null)\b
201      captures:
202        0: constant.language.nix
203      push:
204        - match: '(?=([\])};,]|\b(else|then)\b))'
205          pop: true
206        - include: expression-cont
207    - match: \b(scopedImport|import|isNull|abort|throw|baseNameOf|dirOf|removeAttrs|map|toString|derivationStrict|derivation)\b
208      captures:
209        0: support.function.nix
210      push:
211        - match: '(?=([\])};,]|\b(else|then)\b))'
212          pop: true
213        - include: expression-cont
214    - match: '\b[0-9]+\b'
215      captures:
216        0: constant.numeric.nix
217      push:
218        - match: '(?=([\])};,]|\b(else|then)\b))'
219          pop: true
220        - include: expression-cont
221  expression:
222    - include: parens-and-cont
223    - include: list-and-cont
224    - include: string
225    - include: interpolation
226    - include: with-assert
227    - include: function-for-sure
228    - include: attrset-for-sure
229    - include: attrset-or-function
230    - include: let
231    - include: if
232    - include: operator-unary
233    - include: constants
234    - include: bad-reserved
235    - include: parameter-name-and-cont
236    - include: others
237  expression-cont:
238    - match: (?=.?)
239      push:
240        - match: '(?=([\])};,]|\b(else|then)\b))'
241          pop: true
242        - include: parens
243        - include: list
244        - include: string
245        - include: interpolation
246        - include: function-for-sure
247        - include: attrset-for-sure
248        - include: attrset-or-function
249        - match: '(\bor\b|\.|==|!=|!|\<\=|\<|\>\=|\>|&&|\|\||-\>|//|\?|\+\+|-|\*|/(?=([^*]|$))|\+)'
250          scope: keyword.operator.nix
251        - include: constants
252        - include: bad-reserved
253        - include: parameter-name
254        - include: others
255  function-body:
256    - match: '(@\s*([a-zA-Z\_][a-zA-Z0-9\_\''\-]*)\s*)?(\:)'
257      push:
258        - match: '(?=([\])};,]|\b(else|then)\b))'
259          pop: true
260        - include: expression
261  function-body-from-colon:
262    - match: (\:)
263      captures:
264        0: punctuation.definition.function.nix
265      push:
266        - match: '(?=([\])};,]|\b(else|then)\b))'
267          pop: true
268        - include: expression
269  function-contents:
270    - include: bad-reserved
271    - include: function-parameter
272    - include: others
273  function-definition:
274    - match: (?=.?)
275      push:
276        - match: '(?=([\])};,]|\b(else|then)\b))'
277          pop: true
278        - include: function-body-from-colon
279        - match: (?=.?)
280          push:
281            - match: (?=\:)
282              pop: true
283            - match: '(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*)'
284              captures:
285                0: variable.parameter.function.4.nix
286              push:
287                - match: (?=\:)
288                  pop: true
289                - match: \@
290                  push:
291                    - match: (?=\:)
292                      pop: true
293                    - include: function-header-until-colon-no-arg
294                    - include: others
295                - include: others
296            - match: '(?=\{)'
297              push:
298                - match: (?=\:)
299                  pop: true
300                - include: function-header-until-colon-with-arg
301        - include: others
302  function-definition-brace-opened:
303    - match: (?=.?)
304      push:
305        - match: '(?=([\])};,]|\b(else|then)\b))'
306          pop: true
307        - include: function-body-from-colon
308        - match: (?=.?)
309          push:
310            - match: (?=\:)
311              pop: true
312            - include: function-header-close-brace-with-arg
313            - match: (?=.?)
314              push:
315                - match: '(?=\})'
316                  pop: true
317                - include: function-contents
318        - include: others
319  function-for-sure:
320    - match: '(?=(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*\s*[:@]|\{[^}]*\}\s*:|\{[^#}"''/=]*[,\?]))'
321      push:
322        - match: '(?=([\])};,]|\b(else|then)\b))'
323          pop: true
324        - include: function-definition
325  function-header-close-brace-no-arg:
326    - match: '\}'
327      captures:
328        0: punctuation.definition.entity.function.nix
329      push:
330        - match: (?=\:)
331          pop: true
332        - include: others
333  function-header-close-brace-with-arg:
334    - match: '\}'
335      captures:
336        0: punctuation.definition.entity.function.nix
337      push:
338        - match: (?=\:)
339          pop: true
340        - include: function-header-terminal-arg
341        - include: others
342  function-header-open-brace:
343    - match: '\{'
344      captures:
345        0: punctuation.definition.entity.function.2.nix
346      push:
347        - match: '(?=\})'
348          pop: true
349        - include: function-contents
350  function-header-terminal-arg:
351    - match: (?=@)
352      push:
353        - match: (?=\:)
354          pop: true
355        - match: \@
356          push:
357            - match: (?=\:)
358              pop: true
359            - match: '(\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*)'
360              push:
361                - meta_scope: variable.parameter.function.3.nix
362                - match: (?=\:)
363                  pop: true
364            - include: others
365        - include: others
366  function-header-until-colon-no-arg:
367    - match: '(?=\{)'
368      push:
369        - match: (?=\:)
370          pop: true
371        - include: function-header-open-brace
372        - include: function-header-close-brace-no-arg
373  function-header-until-colon-with-arg:
374    - match: '(?=\{)'
375      push:
376        - match: (?=\:)
377          pop: true
378        - include: function-header-open-brace
379        - include: function-header-close-brace-with-arg
380  function-parameter:
381    - match: (\.\.\.)
382      push:
383        - meta_scope: keyword.operator.nix
384        - match: '(,|(?=\}))'
385          pop: true
386        - include: others
387    - match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
388      captures:
389        0: variable.parameter.function.1.nix
390      push:
391        - match: '(,|(?=\}))'
392          captures:
393            0: keyword.operator.nix
394          pop: true
395        - include: whitespace
396        - include: comment
397        - include: function-parameter-default
398        - include: expression
399    - include: others
400  function-parameter-default:
401    - match: \?
402      captures:
403        0: keyword.operator.nix
404      push:
405        - match: "(?=[,}])"
406          pop: true
407        - include: expression
408  if:
409    - match: (?=\bif\b)
410      push:
411        - match: '(?=([\])};,]|\b(else|then)\b))'
412          pop: true
413        - match: \bif\b
414          captures:
415            0: keyword.other.nix
416          push:
417            - match: \bth(?=en\b)
418              captures:
419                0: keyword.other.nix
420              pop: true
421            - include: expression
422        - match: (?<=th)en\b
423          captures:
424            0: keyword.other.nix
425          push:
426            - match: \bel(?=se\b)
427              captures:
428                0: keyword.other.nix
429              pop: true
430            - include: expression
431        - match: (?<=el)se\b
432          captures:
433            0: keyword.other.nix
434          push:
435            - match: '(?=([\])};,]|\b(else|then)\b))'
436              captures:
437                0: keyword.other.nix
438              pop: true
439            - include: expression
440  illegal:
441    - match: .
442      scope: invalid.illegal
443  interpolation:
444    - match: '\$\{'
445      captures:
446        0: punctuation.section.embedded.begin.nix
447      push:
448        - meta_scope: markup.italic
449        - match: '\}'
450          captures:
451            0: punctuation.section.embedded.end.nix
452          pop: true
453        - include: expression
454  let:
455    - match: (?=\blet\b)
456      push:
457        - match: '(?=([\])};,]|\b(else|then)\b))'
458          pop: true
459        - match: \blet\b
460          captures:
461            0: keyword.other.nix
462          push:
463            - match: '(?=([\])};,]|\b(in|else|then)\b))'
464              pop: true
465            - match: '(?=\{)'
466              push:
467                - match: '(?=([\])};,]|\b(else|then)\b))'
468                  pop: true
469                - match: '\{'
470                  push:
471                    - match: '\}'
472                      pop: true
473                    - include: attrset-contents
474                - match: '(^|(?<=\}))'
475                  push:
476                    - match: '(?=([\])};,]|\b(else|then)\b))'
477                      pop: true
478                    - include: expression-cont
479                - include: others
480            - include: attrset-contents
481            - include: others
482        - match: \bin\b
483          captures:
484            0: keyword.other.nix
485          push:
486            - match: '(?=([\])};,]|\b(else|then)\b))'
487              pop: true
488            - include: expression
489  list:
490    - match: '\['
491      captures:
492        0: punctuation.definition.list.nix
493      push:
494        - match: '\]'
495          captures:
496            0: punctuation.definition.list.nix
497          pop: true
498        - include: expression
499  list-and-cont:
500    - match: '(?=\[)'
501      push:
502        - match: '(?=([\])};,]|\b(else|then)\b))'
503          pop: true
504        - include: list
505        - include: expression-cont
506  operator-unary:
507    - match: (!|-)
508      scope: keyword.operator.unary.nix
509  others:
510    - include: whitespace
511    - include: comment
512    - include: illegal
513  parameter-name:
514    - match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
515      captures:
516        0: variable.parameter.name.nix
517  parameter-name-and-cont:
518    - match: '\b[a-zA-Z\_][a-zA-Z0-9\_\''\-]*'
519      captures:
520        0: variable.parameter.name.nix
521      push:
522        - match: '(?=([\])};,]|\b(else|then)\b))'
523          pop: true
524        - include: expression-cont
525  parens:
526    - match: \(
527      captures:
528        0: punctuation.definition.expression.nix
529      push:
530        - match: \)
531          captures:
532            0: punctuation.definition.expression.nix
533          pop: true
534        - include: expression
535  parens-and-cont:
536    - match: (?=\()
537      push:
538        - match: '(?=([\])};,]|\b(else|then)\b))'
539          pop: true
540        - include: parens
541        - include: expression-cont
542  string:
543    - match: (?=\'\')
544      push:
545        - match: '(?=([\])};,]|\b(else|then)\b))'
546          pop: true
547        - match: \'\'
548          captures:
549            0: punctuation.definition.string.other.start.nix
550          push:
551            - meta_scope: string.quoted.other.nix
552            - match: \'\'(?!\$|\'|\\.)
553              captures:
554                0: punctuation.definition.string.other.end.nix
555              pop: true
556            - match: \'\'(\$|\'|\\.)
557              scope: constant.character.escape.nix
558            - include: interpolation
559        - include: expression-cont
560    - match: (?=\")
561      push:
562        - match: '(?=([\])};,]|\b(else|then)\b))'
563          pop: true
564        - include: string-quoted
565        - include: expression-cont
566    - match: '(~?[a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+)'
567      captures:
568        0: string.unquoted.path.nix
569      push:
570        - match: '(?=([\])};,]|\b(else|then)\b))'
571          pop: true
572        - include: expression-cont
573    - match: '(\<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>)'
574      captures:
575        0: string.unquoted.spath.nix
576      push:
577        - match: '(?=([\])};,]|\b(else|then)\b))'
578          pop: true
579        - include: expression-cont
580    - match: '([a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\'']+)'
581      captures:
582        0: string.unquoted.url.nix
583      push:
584        - match: '(?=([\])};,]|\b(else|then)\b))'
585          pop: true
586        - include: expression-cont
587  string-quoted:
588    - match: \"
589      captures:
590        0: punctuation.definition.string.double.start.nix
591      push:
592        - meta_scope: string.quoted.double.nix
593        - match: \"
594          captures:
595            0: punctuation.definition.string.double.end.nix
596          pop: true
597        - match: \\.
598          scope: constant.character.escape.nix
599        - include: interpolation
600  whitespace:
601    - match: \s+
602  with-assert:
603    - match: '(?<![\w''-])(with|assert)(?![\w''-])'
604      captures:
605        0: keyword.other.nix
606      push:
607        - match: \;
608          pop: true
609        - include: expression
610