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.

526 lines
19KB

  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.definition.parameters.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.definition.parameters.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.definition.parameters.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.definition.parameters.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: (::)
  161. captures:
  162. 0: punctuation.binary.elixir
  163. push:
  164. - match: (,|>>|$)
  165. captures:
  166. 0: punctuation.binary.elixir
  167. pop: true
  168. - match: '\b[a-z]\w*\b'
  169. scope: support.type.binary.elixir
  170. - 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'
  171. scope: constant.numeric.elixir
  172. - 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(?![?!:])'
  173. scope: keyword.control.elixir
  174. - match: (?<!\.)\b(and|not|or|when|xor|in)\b
  175. comment: as above, just doesn't need a 'end' and does a logic operation
  176. scope: keyword.operator.elixir
  177. - match: '\b[A-Z]\w*\b'
  178. scope: entity.name.class.elixir
  179. - match: '\b(nil|true|false)\b(?![?!])'
  180. scope: constant.language.elixir
  181. - match: '\b(__(CALLER|ENV|MODULE|DIR)__)\b(?![?!])'
  182. scope: variable.language.elixir
  183. - match: '(@)[a-zA-Z_]\w*'
  184. scope: variable.other.readwrite.module.elixir
  185. captures:
  186. 1: punctuation.definition.variable.elixir
  187. - match: (&)\d+
  188. scope: variable.other.anonymous.elixir
  189. captures:
  190. 1: punctuation.definition.variable.elixir
  191. - match: '\^[a-z_]\w*'
  192. scope: variable.other.capture.elixir
  193. captures:
  194. 1: punctuation.definition.variable.elixir
  195. - 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'
  196. scope: constant.numeric.elixir
  197. - match: ":'"
  198. captures:
  199. 0: punctuation.definition.constant.elixir
  200. push:
  201. - meta_scope: constant.other.symbol.single-quoted.elixir
  202. - match: "'"
  203. captures:
  204. 0: punctuation.definition.constant.elixir
  205. pop: true
  206. - include: interpolated_elixir
  207. - include: escaped_char
  208. - match: ':"'
  209. captures:
  210. 0: punctuation.definition.constant.elixir
  211. push:
  212. - meta_scope: constant.other.symbol.double-quoted.elixir
  213. - match: '"'
  214. captures:
  215. 0: punctuation.definition.constant.elixir
  216. pop: true
  217. - include: interpolated_elixir
  218. - include: escaped_char
  219. - match: (?>''')
  220. comment: Single-quoted heredocs
  221. captures:
  222. 0: punctuation.definition.string.begin.elixir
  223. push:
  224. - meta_scope: string.quoted.single.heredoc.elixir
  225. - match: ^\s*'''
  226. captures:
  227. 0: punctuation.definition.string.end.elixir
  228. pop: true
  229. - include: interpolated_elixir
  230. - include: escaped_char
  231. - match: "'"
  232. comment: single quoted string (allows for interpolation)
  233. captures:
  234. 0: punctuation.definition.string.begin.elixir
  235. push:
  236. - meta_scope: string.quoted.single.elixir
  237. - match: "'"
  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 heredocs
  245. captures:
  246. 0: punctuation.definition.string.begin.elixir
  247. push:
  248. - meta_scope: string.quoted.double.heredoc.elixir
  249. - match: ^\s*"""
  250. captures:
  251. 0: punctuation.definition.string.end.elixir
  252. pop: true
  253. - include: interpolated_elixir
  254. - include: escaped_char
  255. - match: '"'
  256. comment: double quoted string (allows for interpolation)
  257. captures:
  258. 0: punctuation.definition.string.begin.elixir
  259. push:
  260. - meta_scope: string.quoted.double.elixir
  261. - match: '"'
  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: Double-quoted heredocs sigils
  269. captures:
  270. 0: punctuation.definition.string.begin.elixir
  271. push:
  272. - meta_scope: string.quoted.double.heredoc.elixir
  273. - match: ^\s*"""
  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]\('
  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: '\)[a-z]*'
  322. captures:
  323. 0: punctuation.definition.string.end.elixir
  324. pop: true
  325. - include: interpolated_elixir
  326. - include: escaped_char
  327. - match: '~[a-z]([^\w])'
  328. comment: sigil (allow for interpolation)
  329. captures:
  330. 0: punctuation.definition.string.begin.elixir
  331. push:
  332. - meta_scope: string.interpolated.elixir
  333. - match: '\1[a-z]*'
  334. captures:
  335. 0: punctuation.definition.string.end.elixir
  336. pop: true
  337. - include: interpolated_elixir
  338. - include: escaped_char
  339. - include: escaped_char
  340. - match: '~[A-Z](?>""")'
  341. comment: Double-quoted heredocs sigils
  342. captures:
  343. 0: punctuation.definition.string.begin.elixir
  344. push:
  345. - meta_scope: string.quoted.other.literal.upper.elixir
  346. - match: ^\s*"""
  347. captures:
  348. 0: punctuation.definition.string.end.elixir
  349. pop: true
  350. - match: '~[A-Z]\{'
  351. comment: sigil (without interpolation)
  352. captures:
  353. 0: punctuation.definition.string.begin.elixir
  354. push:
  355. - meta_scope: string.quoted.other.literal.upper.elixir
  356. - match: '\}[a-z]*'
  357. captures:
  358. 0: punctuation.definition.string.end.elixir
  359. pop: true
  360. - match: '~[A-Z]\['
  361. comment: sigil (without interpolation)
  362. captures:
  363. 0: punctuation.definition.string.begin.elixir
  364. push:
  365. - meta_scope: string.quoted.other.literal.upper.elixir
  366. - match: '\][a-z]*'
  367. captures:
  368. 0: punctuation.definition.string.end.elixir
  369. pop: true
  370. - match: '~[A-Z]\<'
  371. comment: sigil (without interpolation)
  372. captures:
  373. 0: punctuation.definition.string.begin.elixir
  374. push:
  375. - meta_scope: string.quoted.other.literal.upper.elixir
  376. - match: '\>[a-z]*'
  377. captures:
  378. 0: punctuation.definition.string.end.elixir
  379. pop: true
  380. - match: '~[A-Z]\('
  381. comment: sigil (without interpolation)
  382. captures:
  383. 0: punctuation.definition.string.begin.elixir
  384. push:
  385. - meta_scope: string.quoted.other.literal.upper.elixir
  386. - match: '\)[a-z]*'
  387. captures:
  388. 0: punctuation.definition.string.end.elixir
  389. pop: true
  390. - match: '~[A-Z]([^\w])'
  391. comment: sigil (without interpolation)
  392. captures:
  393. 0: punctuation.definition.string.begin.elixir
  394. push:
  395. - meta_scope: string.quoted.other.literal.upper.elixir
  396. - match: '\1[a-z]*'
  397. captures:
  398. 0: punctuation.definition.string.end.elixir
  399. pop: true
  400. - match: '(?<!:)(:)(?>[a-zA-Z_][\w@]*(?>[?!]|=(?![>=]))?|\<\>|===?|!==?|<<>>|<<<|>>>|~~~|::|<\-|\|>|=>|=~|=|/|\\\\|\*\*?|\.\.?\.?|>=?|<=?|&&?&?|\+\+?|\-\-?|\|\|?\|?|\!|@|\%?\{\}|%|\[\]|\^(\^\^)?)'
  401. comment: symbols
  402. scope: constant.other.symbol.elixir
  403. captures:
  404. 1: punctuation.definition.constant.elixir
  405. - match: '(?>[a-zA-Z_][\w@]*(?>[?!])?)(:)(?!:)'
  406. comment: symbols
  407. scope: constant.other.keywords.elixir
  408. captures:
  409. 1: punctuation.definition.constant.elixir
  410. - match: ^\s*(##).*$\n?
  411. scope: comment.line.section.elixir
  412. captures:
  413. 1: punctuation.definition.comment.elixir
  414. - match: '(?:^[ \t]+)?(#).*$\n?'
  415. scope: comment.line.number-sign.elixir
  416. captures:
  417. 1: punctuation.definition.comment.elixir
  418. - match: '(?<!\w)\?(\\(x[0-9A-Fa-f]{1,2}(?![0-9A-Fa-f])\b|[^xMC])|[^\s\\])'
  419. comment: |
  420. matches questionmark-letters.
  421. examples (1st alternation = hex):
  422. ?\x1 ?\x61
  423. examples (2rd alternation = escaped):
  424. ?\n ?\b
  425. examples (3rd alternation = normal):
  426. ?a ?A ?0
  427. ?* ?" ?(
  428. ?. ?#
  429. the negative lookbehind prevents against matching
  430. p(42.tainted?)
  431. scope: constant.numeric.elixir
  432. - match: "===?|!==?|<=?|>=?"
  433. scope: keyword.operator.comparison.elixir
  434. - match: (\|\|\||&&&|^^^|<<<|>>>|~~~)
  435. scope: keyword.operator.bitwise.elixir
  436. - match: '(?<=[ \t])!+|\bnot\b|&&|\band\b|\|\||\bor\b|\bxor\b'
  437. scope: keyword.operator.logical.elixir
  438. - match: (\*|\+|\-|/)
  439. scope: keyword.operator.arithmetic.elixir
  440. - match: \||\+\+|\-\-|\*\*|\\\\|\<\-|\<\>|\<\<|\>\>|\:\:|\.\.|\|>|~|=>|&
  441. scope: keyword.operator.other.elixir
  442. - match: "="
  443. scope: keyword.operator.assignment.elixir
  444. - match: ":"
  445. scope: punctuation.separator.other.elixir
  446. - match: \;
  447. scope: punctuation.separator.statement.elixir
  448. - match: ","
  449. scope: punctuation.separator.object.elixir
  450. - match: \.
  451. scope: punctuation.separator.method.elixir
  452. - match: '\{|\}'
  453. scope: punctuation.section.scope.elixir
  454. - match: '\[|\]'
  455. scope: punctuation.section.array.elixir
  456. - match: \(|\)
  457. scope: punctuation.section.function.elixir
  458. escaped_char:
  459. - match: '\\(x[\da-fA-F]{1,2}|.)'
  460. scope: constant.character.escaped.elixir
  461. interpolated_elixir:
  462. - match: '#\{(\})'
  463. scope: source.elixir.embedded.source
  464. captures:
  465. 0: punctuation.section.embedded.elixir
  466. 1: source.elixir.embedded.source.empty
  467. - match: '#\{'
  468. captures:
  469. 0: punctuation.section.embedded.elixir
  470. push:
  471. - meta_scope: source.elixir.embedded.source
  472. - match: '\}'
  473. captures:
  474. 0: punctuation.section.embedded.elixir
  475. pop: true
  476. - include: nest_curly_and_self
  477. - include: main
  478. nest_curly_and_self:
  479. - match: '\{'
  480. captures:
  481. 0: punctuation.section.scope.elixir
  482. push:
  483. - match: '\}'
  484. captures:
  485. 0: punctuation.section.scope.elixir
  486. pop: true
  487. - include: nest_curly_and_self
  488. - include: main
  489. regex_sub:
  490. - include: interpolated_elixir
  491. - include: escaped_char
  492. - match: '(\{)\d+(,\d+)?(\})'
  493. scope: string.regexp.arbitrary-repitition.elixir
  494. captures:
  495. 1: punctuation.definition.arbitrary-repitition.elixir
  496. 3: punctuation.definition.arbitrary-repitition.elixir
  497. - match: '\[(?:\^?\])?'
  498. captures:
  499. 0: punctuation.definition.character-class.elixir
  500. push:
  501. - meta_scope: string.regexp.character-class.elixir
  502. - match: '\]'
  503. captures:
  504. 0: punctuation.definition.character-class.elixir
  505. pop: true
  506. - include: escaped_char
  507. - match: \(
  508. captures:
  509. 0: punctuation.definition.group.elixir
  510. push:
  511. - meta_scope: string.regexp.group.elixir
  512. - match: \)
  513. captures:
  514. 0: punctuation.definition.group.elixir
  515. pop: true
  516. - include: regex_sub
  517. - match: '(?<=^|\s)(#)\s[[a-zA-Z0-9,. \t?!-][^\x{00}-\x{7F}]]*$'
  518. 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.
  519. scope: comment.line.number-sign.elixir
  520. captures:
  521. 1: punctuation.definition.comment.elixir