You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

522 lines
18KB

  1. %YAML 1.2
  2. ---
  3. # http://www.sublimetext.com/docs/3/syntax.html
  4. name: Elixir
  5. comment: Textmate bundle for Elixir Programming Language.
  6. file_extensions:
  7. - ex
  8. - exs
  9. first_line_match: ^#!/.*\belixir
  10. scope: source.elixir
  11. contexts:
  12. main:
  13. - match: \b(fn)\b(?!.*->)
  14. captures:
  15. 1: keyword.control.elixir
  16. push:
  17. - match: $
  18. pop: true
  19. - include: core_syntax
  20. - match: \b(fn)\b(?=.*->)
  21. captures:
  22. 1: keyword.control.elixir
  23. push:
  24. - match: (?>(->)|(when)|(\)))
  25. captures:
  26. 1: keyword.operator.other.elixir
  27. 2: keyword.control.elixir
  28. 3: punctuation.section.function.elixir
  29. pop: true
  30. - include: core_syntax
  31. - include: core_syntax
  32. - match: '^(?=.*->)((?![^"'']*("|'')[^"'']*->)|(?=.*->[^"'']*("|'')[^"'']*->))((?!.*\([^\)]*->)|(?=[^\(\)]*->)|(?=\s*\(.*\).*->))((?!.*\b(fn)\b)|(?=.*->.*\bfn\b))'
  33. captures:
  34. 1: keyword.control.elixir
  35. push:
  36. - match: (?>(->)|(when)|(\)))
  37. captures:
  38. 1: keyword.operator.other.elixir
  39. 2: keyword.control.elixir
  40. 3: punctuation.section.function.elixir
  41. pop: true
  42. - include: core_syntax
  43. core_syntax:
  44. - match: ^\s*(defmodule)\b
  45. captures:
  46. 1: keyword.control.module.elixir
  47. push:
  48. - meta_scope: meta.module.elixir
  49. - match: \b(do)\b
  50. captures:
  51. 1: keyword.control.module.elixir
  52. pop: true
  53. - match: '\b[A-Z]\w*\b'
  54. scope: entity.name.class.elixir
  55. - match: ^\s*(defprotocol)\b
  56. captures:
  57. 1: keyword.control.protocol.elixir
  58. push:
  59. - meta_scope: meta.protocol_declaration.elixir
  60. - match: \b(do)\b
  61. captures:
  62. 1: keyword.control.protocol.elixir
  63. pop: true
  64. - match: '\b[A-Z]\w*\b'
  65. scope: entity.name.protocol.elixir
  66. - match: ^\s*(defimpl)\b
  67. captures:
  68. 1: keyword.control.protocol.elixir
  69. push:
  70. - meta_scope: meta.protocol_implementation.elixir
  71. - match: \b(do)\b
  72. captures:
  73. 1: keyword.control.protocol.elixir
  74. pop: true
  75. - match: '\b[A-Z]\w*\b'
  76. scope: entity.name.protocol.elixir
  77. - match: '^\s*(def|defmacro)\s+((?>[a-zA-Z_]\w*(?>\.|::))?(?>[a-zA-Z_]\w*(?>[?!]|=(?!>))?|===?|>[>=]?|<=>|<[<=]?|[%&`/\|]|\*\*?|=?~|[-+]@?|\[\]=?))((\()|\s*)'
  78. captures:
  79. 1: keyword.control.module.elixir
  80. 2: entity.name.function.public.elixir
  81. 4: punctuation.section.function.elixir
  82. push:
  83. - meta_scope: meta.function.public.elixir
  84. - match: (\bdo:)|(\bdo\b)|(?=\s+(def|defmacro)\b)
  85. captures:
  86. 1: constant.other.keywords.elixir
  87. 2: keyword.control.module.elixir
  88. pop: true
  89. - include: main
  90. - match: \s(\\\\)
  91. captures:
  92. 1: keyword.operator.other.elixir
  93. push:
  94. - match: ',|\)|$'
  95. pop: true
  96. - include: main
  97. - match: \b(is_atom|is_binary|is_bitstring|is_boolean|is_float|is_function|is_integer|is_list|is_map|is_nil|is_number|is_pid|is_port|is_record|is_reference|is_tuple|is_exception|abs|bit_size|byte_size|div|elem|hd|length|map_size|node|rem|round|tl|trunc|tuple_size)\b
  98. scope: keyword.control.elixir
  99. - match: '^\s*(defp|defmacrop)\s+((?>[a-zA-Z_]\w*(?>\.|::))?(?>[a-zA-Z_]\w*(?>[?!]|=(?!>))?|===?|>[>=]?|<=>|<[<=]?|[%&`/\|]|\*\*?|=?~|[-+]@?|\[\]=?))((\()|\s*)'
  100. captures:
  101. 1: keyword.control.module.elixir
  102. 2: entity.name.function.private.elixir
  103. 4: punctuation.section.function.elixir
  104. push:
  105. - meta_scope: meta.function.private.elixir
  106. - match: (\bdo:)|(\bdo\b)|(?=\s+(defp|defmacrop)\b)
  107. captures:
  108. 1: constant.other.keywords.elixir
  109. 2: keyword.control.module.elixir
  110. pop: true
  111. - include: main
  112. - match: \s(\\\\)
  113. captures:
  114. 1: keyword.operator.other.elixir
  115. push:
  116. - match: ',|\)|$'
  117. pop: true
  118. - include: main
  119. - match: \b(is_atom|is_binary|is_bitstring|is_boolean|is_float|is_function|is_integer|is_list|is_map|is_nil|is_number|is_pid|is_port|is_record|is_reference|is_tuple|is_exception|abs|bit_size|byte_size|div|elem|hd|length|map_size|node|rem|round|tl|trunc|tuple_size)\b
  120. scope: keyword.control.elixir
  121. - match: '@(module|type)?doc (~[a-z])?"""'
  122. comment: "@doc with heredocs is treated as documentation"
  123. push:
  124. - meta_scope: comment.documentation.heredoc
  125. - match: \s*"""
  126. pop: true
  127. - include: interpolated_elixir
  128. - include: escaped_char
  129. - match: '@(module|type)?doc ~[A-Z]"""'
  130. comment: "@doc with heredocs is treated as documentation"
  131. push:
  132. - meta_scope: comment.documentation.heredoc
  133. - match: \s*"""
  134. pop: true
  135. - match: "@(module|type)?doc (~[a-z])?'''"
  136. comment: "@doc with heredocs is treated as documentation"
  137. push:
  138. - meta_scope: comment.documentation.heredoc
  139. - match: \s*'''
  140. pop: true
  141. - include: interpolated_elixir
  142. - include: escaped_char
  143. - match: "@(module|type)?doc ~[A-Z]'''"
  144. comment: "@doc with heredocs is treated as documentation"
  145. push:
  146. - meta_scope: comment.documentation.heredoc
  147. - match: \s*'''
  148. pop: true
  149. - match: "@(module|type)?doc false"
  150. comment: "@doc false is treated as documentation"
  151. scope: comment.documentation.false
  152. - match: '@(module|type)?doc "'
  153. comment: "@doc with string is treated as documentation"
  154. push:
  155. - meta_scope: comment.documentation.string
  156. - match: '"'
  157. pop: true
  158. - include: interpolated_elixir
  159. - include: escaped_char
  160. - match: '(?<!\.)\b(do|end|case|bc|lc|for|if|cond|unless|try|receive|fn|defmodule|defp?|defprotocol|defimpl|defrecord|defstruct|defmacrop?|defdelegate|defcallback|defmacrocallback|defexception|defoverridable|exit|after|rescue|catch|else|raise|throw|import|require|alias|use|quote|unquote|super|with)\b(?![?!:])'
  161. scope: keyword.control.elixir
  162. - match: (?<!\.)\b(and|not|or|when|xor|in)\b
  163. comment: as above, just doesn't need a 'end' and does a logic operation
  164. scope: keyword.operator.elixir
  165. - match: '\b[A-Z]\w*\b'
  166. scope: entity.name.class.elixir
  167. - match: '\b(nil|true|false)\b(?![?!])'
  168. scope: constant.language.elixir
  169. - match: '\b(__(CALLER|ENV|MODULE|DIR)__)\b(?![?!])'
  170. scope: variable.language.elixir
  171. - match: '(@)[a-zA-Z_]\w*'
  172. scope: variable.other.readwrite.module.elixir
  173. captures:
  174. 1: punctuation.definition.variable.elixir
  175. - match: (&)\d+
  176. scope: variable.other.anonymous.elixir
  177. captures:
  178. 1: punctuation.definition.variable.elixir
  179. - match: '\^[a-z_]\w*'
  180. scope: variable.other.capture.elixir
  181. captures:
  182. 1: punctuation.definition.variable.elixir
  183. - match: '\b(0x[0-9A-Fa-f](?>_?[0-9A-Fa-f])*|\d(?>_?\d)*(\.(?![^[:space:][:digit:]])(?>_?\d)*)?([eE][-+]?\d(?>_?\d)*)?|0b[01]+|0o[0-7]+)\b'
  184. scope: constant.numeric.elixir
  185. - match: ":'"
  186. captures:
  187. 0: punctuation.definition.constant.elixir
  188. push:
  189. - meta_scope: constant.other.symbol.single-quoted.elixir
  190. - match: "'"
  191. captures:
  192. 0: punctuation.definition.constant.elixir
  193. pop: true
  194. - include: interpolated_elixir
  195. - include: escaped_char
  196. - match: ':"'
  197. captures:
  198. 0: punctuation.definition.constant.elixir
  199. push:
  200. - meta_scope: constant.other.symbol.double-quoted.elixir
  201. - match: '"'
  202. captures:
  203. 0: punctuation.definition.constant.elixir
  204. pop: true
  205. - include: interpolated_elixir
  206. - include: escaped_char
  207. - match: (?>''')
  208. comment: Single-quoted heredocs
  209. captures:
  210. 0: punctuation.definition.string.begin.elixir
  211. push:
  212. - meta_scope: string.quoted.single.heredoc.elixir
  213. - match: ^\s*'''
  214. captures:
  215. 0: punctuation.definition.string.end.elixir
  216. pop: true
  217. - include: interpolated_elixir
  218. - include: escaped_char
  219. - match: "'"
  220. comment: single quoted string (allows for interpolation)
  221. captures:
  222. 0: punctuation.definition.string.begin.elixir
  223. push:
  224. - meta_scope: string.quoted.single.elixir
  225. - match: "'"
  226. captures:
  227. 0: punctuation.definition.string.end.elixir
  228. pop: true
  229. - include: interpolated_elixir
  230. - include: escaped_char
  231. - match: (?>""")
  232. comment: Double-quoted heredocs
  233. captures:
  234. 0: punctuation.definition.string.begin.elixir
  235. push:
  236. - meta_scope: string.quoted.double.heredoc.elixir
  237. - match: ^\s*"""
  238. captures:
  239. 0: punctuation.definition.string.end.elixir
  240. pop: true
  241. - include: interpolated_elixir
  242. - include: escaped_char
  243. - match: '"'
  244. comment: double quoted string (allows for interpolation)
  245. captures:
  246. 0: punctuation.definition.string.begin.elixir
  247. push:
  248. - meta_scope: string.quoted.double.elixir
  249. - match: '"'
  250. captures:
  251. 0: punctuation.definition.string.end.elixir
  252. pop: true
  253. - include: interpolated_elixir
  254. - include: escaped_char
  255. - match: '~[a-z](?>""")'
  256. comment: Double-quoted heredocs sigils
  257. captures:
  258. 0: punctuation.definition.string.begin.elixir
  259. push:
  260. - meta_scope: string.quoted.double.heredoc.elixir
  261. - match: ^\s*"""
  262. captures:
  263. 0: punctuation.definition.string.end.elixir
  264. pop: true
  265. - include: interpolated_elixir
  266. - include: escaped_char
  267. - match: '~[a-z]\{'
  268. comment: sigil (allow for interpolation)
  269. captures:
  270. 0: punctuation.definition.string.begin.elixir
  271. push:
  272. - meta_scope: string.interpolated.elixir
  273. - match: '\}[a-z]*'
  274. captures:
  275. 0: punctuation.definition.string.end.elixir
  276. pop: true
  277. - include: interpolated_elixir
  278. - include: escaped_char
  279. - match: '~[a-z]\['
  280. comment: sigil (allow for interpolation)
  281. captures:
  282. 0: punctuation.definition.string.begin.elixir
  283. push:
  284. - meta_scope: string.interpolated.elixir
  285. - match: '\][a-z]*'
  286. captures:
  287. 0: punctuation.definition.string.end.elixir
  288. pop: true
  289. - include: interpolated_elixir
  290. - include: escaped_char
  291. - match: '~[a-z]\<'
  292. comment: sigil (allow for interpolation)
  293. captures:
  294. 0: punctuation.definition.string.begin.elixir
  295. push:
  296. - meta_scope: string.interpolated.elixir
  297. - match: '\>[a-z]*'
  298. captures:
  299. 0: punctuation.definition.string.end.elixir
  300. pop: true
  301. - include: interpolated_elixir
  302. - include: escaped_char
  303. - match: '~[a-z]\('
  304. comment: sigil (allow for interpolation)
  305. captures:
  306. 0: punctuation.definition.string.begin.elixir
  307. push:
  308. - meta_scope: string.interpolated.elixir
  309. - match: '\)[a-z]*'
  310. captures:
  311. 0: punctuation.definition.string.end.elixir
  312. pop: true
  313. - include: interpolated_elixir
  314. - include: escaped_char
  315. - match: '~[a-z]([^\w])'
  316. comment: sigil (allow for interpolation)
  317. captures:
  318. 0: punctuation.definition.string.begin.elixir
  319. push:
  320. - meta_scope: string.interpolated.elixir
  321. - match: '\1[a-z]*'
  322. captures:
  323. 0: punctuation.definition.string.end.elixir
  324. pop: true
  325. - include: interpolated_elixir
  326. - include: escaped_char
  327. - include: escaped_char
  328. - match: '~[A-Z](?>""")'
  329. comment: Double-quoted heredocs sigils
  330. captures:
  331. 0: punctuation.definition.string.begin.elixir
  332. push:
  333. - meta_scope: string.quoted.other.literal.upper.elixir
  334. - match: ^\s*"""
  335. captures:
  336. 0: punctuation.definition.string.end.elixir
  337. pop: true
  338. - match: '~[A-Z]\{'
  339. comment: sigil (without interpolation)
  340. captures:
  341. 0: punctuation.definition.string.begin.elixir
  342. push:
  343. - meta_scope: string.quoted.other.literal.upper.elixir
  344. - match: '\}[a-z]*'
  345. captures:
  346. 0: punctuation.definition.string.end.elixir
  347. pop: true
  348. - match: '~[A-Z]\['
  349. comment: sigil (without interpolation)
  350. captures:
  351. 0: punctuation.definition.string.begin.elixir
  352. push:
  353. - meta_scope: string.quoted.other.literal.upper.elixir
  354. - match: '\][a-z]*'
  355. captures:
  356. 0: punctuation.definition.string.end.elixir
  357. pop: true
  358. - match: '~[A-Z]\<'
  359. comment: sigil (without interpolation)
  360. captures:
  361. 0: punctuation.definition.string.begin.elixir
  362. push:
  363. - meta_scope: string.quoted.other.literal.upper.elixir
  364. - match: '\>[a-z]*'
  365. captures:
  366. 0: punctuation.definition.string.end.elixir
  367. pop: true
  368. - match: '~[A-Z]\('
  369. comment: sigil (without interpolation)
  370. captures:
  371. 0: punctuation.definition.string.begin.elixir
  372. push:
  373. - meta_scope: string.quoted.other.literal.upper.elixir
  374. - match: '\)[a-z]*'
  375. captures:
  376. 0: punctuation.definition.string.end.elixir
  377. pop: true
  378. - match: '~[A-Z]([^\w])'
  379. comment: sigil (without interpolation)
  380. captures:
  381. 0: punctuation.definition.string.begin.elixir
  382. push:
  383. - meta_scope: string.quoted.other.literal.upper.elixir
  384. - match: '\1[a-z]*'
  385. captures:
  386. 0: punctuation.definition.string.end.elixir
  387. pop: true
  388. - match: '(?<!:)(:)(?>[a-zA-Z_][\w@]*(?>[?!]|=(?![>=]))?|\<\>|===?|!==?|<<>>|<<<|>>>|~~~|::|<\-|\|>|=>|=~|=|/|\\\\|\*\*?|\.\.?\.?|>=?|<=?|&&?&?|\+\+?|\-\-?|\|\|?\|?|\!|@|\%?\{\}|%|\[\]|\^(\^\^)?)'
  389. comment: symbols
  390. scope: constant.other.symbol.elixir
  391. captures:
  392. 1: punctuation.definition.constant.elixir
  393. - match: '(?>[a-zA-Z_][\w@]*(?>[?!])?)(:)(?!:)'
  394. comment: symbols
  395. scope: constant.other.keywords.elixir
  396. captures:
  397. 1: punctuation.definition.constant.elixir
  398. - match: ^\s*(##).*$\n?
  399. scope: comment.line.section.elixir
  400. captures:
  401. 1: punctuation.definition.comment.elixir
  402. - match: '(?:^[ \t]+)?(#).*$\n?'
  403. scope: comment.line.number-sign.elixir
  404. captures:
  405. 1: punctuation.definition.comment.elixir
  406. - match: '(?<!\w)\?(\\(x[0-9A-Fa-f]{1,2}(?![0-9A-Fa-f])\b|[^xMC])|[^\s\\])'
  407. comment: |
  408. matches questionmark-letters.
  409. examples (1st alternation = hex):
  410. ?\x1 ?\x61
  411. examples (2rd alternation = escaped):
  412. ?\n ?\b
  413. examples (3rd alternation = normal):
  414. ?a ?A ?0
  415. ?* ?" ?(
  416. ?. ?#
  417. the negative lookbehind prevents against matching
  418. p(42.tainted?)
  419. scope: constant.numeric.elixir
  420. - match: \+\+|\-\-|<\|>
  421. scope: keyword.operator.concatenation.elixir
  422. - match: \|\>|<~>|<>|<<<|>>>|~>>|<<~|~>|<~|<\|>
  423. scope: keyword.operator.sigils_1.elixir
  424. - match: "&&&|&&"
  425. scope: keyword.operator.sigils_2.elixir
  426. - match: <\-|\\\\
  427. scope: keyword.operator.sigils_3.elixir
  428. - match: "===?|!==?|<=?|>=?"
  429. scope: keyword.operator.comparison.elixir
  430. - match: (\|\|\||&&&|^^^|<<<|>>>|~~~)
  431. scope: keyword.operator.bitwise.elixir
  432. - match: '(?<=[ \t])!+|\bnot\b|&&|\band\b|\|\||\bor\b|\bxor\b'
  433. scope: keyword.operator.logical.elixir
  434. - match: (\*|\+|\-|/)
  435. scope: keyword.operator.arithmetic.elixir
  436. - match: \||\+\+|\-\-|\*\*|\\\\|\<\-|\<\>|\<\<|\>\>|\:\:|\.\.|\|>|~|=>|&
  437. scope: keyword.operator.other.elixir
  438. - match: "="
  439. scope: keyword.operator.assignment.elixir
  440. - match: ":"
  441. scope: punctuation.separator.other.elixir
  442. - match: \;
  443. scope: punctuation.separator.statement.elixir
  444. - match: ","
  445. scope: punctuation.separator.object.elixir
  446. - match: \.
  447. scope: punctuation.separator.method.elixir
  448. - match: '\{|\}'
  449. scope: punctuation.section.scope.elixir
  450. - match: '\[|\]'
  451. scope: punctuation.section.array.elixir
  452. - match: \(|\)
  453. scope: punctuation.section.function.elixir
  454. escaped_char:
  455. - match: '\\(x[\da-fA-F]{1,2}|.)'
  456. scope: constant.character.escaped.elixir
  457. interpolated_elixir:
  458. - match: '#\{(\})'
  459. scope: source.elixir.embedded.source
  460. captures:
  461. 0: punctuation.section.embedded.elixir
  462. 1: source.elixir.embedded.source.empty
  463. - match: '#\{'
  464. captures:
  465. 0: punctuation.section.embedded.elixir
  466. push:
  467. - meta_scope: source.elixir.embedded.source
  468. - match: '\}'
  469. captures:
  470. 0: punctuation.section.embedded.elixir
  471. pop: true
  472. - include: nest_curly_and_self
  473. - include: main
  474. nest_curly_and_self:
  475. - match: '\{'
  476. captures:
  477. 0: punctuation.section.scope.elixir
  478. push:
  479. - match: '\}'
  480. captures:
  481. 0: punctuation.section.scope.elixir
  482. pop: true
  483. - include: nest_curly_and_self
  484. - include: main
  485. regex_sub:
  486. - include: interpolated_elixir
  487. - include: escaped_char
  488. - match: '(\{)\d+(,\d+)?(\})'
  489. scope: string.regexp.arbitrary-repitition.elixir
  490. captures:
  491. 1: punctuation.definition.arbitrary-repitition.elixir
  492. 3: punctuation.definition.arbitrary-repitition.elixir
  493. - match: '\[(?:\^?\])?'
  494. captures:
  495. 0: punctuation.definition.character-class.elixir
  496. push:
  497. - meta_scope: string.regexp.character-class.elixir
  498. - match: '\]'
  499. captures:
  500. 0: punctuation.definition.character-class.elixir
  501. pop: true
  502. - include: escaped_char
  503. - match: \(
  504. captures:
  505. 0: punctuation.definition.group.elixir
  506. push:
  507. - meta_scope: string.regexp.group.elixir
  508. - match: \)
  509. captures:
  510. 0: punctuation.definition.group.elixir
  511. pop: true
  512. - include: regex_sub
  513. - match: '(?<=^|\s)(#)\s[[a-zA-Z0-9,. \t?!-][^\x{00}-\x{7F}]]*$'
  514. comment: We are restrictive in what we allow to go after the comment character to avoid false positives, since the availability of comments depend on regexp flags.
  515. scope: comment.line.number-sign.elixir
  516. captures:
  517. 1: punctuation.definition.comment.elixir