Makefile.sublime-syntax (21730B)
1 %YAML 1.2 2 # http://www.sublimetext.com/docs/3/syntax.html 3 # https://www.gnu.org/software/make/manual/make.html 4 --- #--------------------------------------------------------------------------- 5 # Converted from Makefile Improved by Kay-Uwe (Kiwi) Lorenz 6 # Includes a few improvement like special-target, a bit more shell command, 7 # better variable recognition, fix ifeq/ifneq missing highlight ... 8 # Rewritten by Raoul Wols on May 2017. 9 # 10 # All number references refer to the "Make manual" (see link above). 11 name: Makefile 12 file_extensions: 13 - make 14 - GNUmakefile 15 - makefile 16 - Makefile 17 - makefile.am 18 - Makefile.am 19 - makefile.in 20 - Makefile.in 21 - OCamlMakefile 22 - mak 23 - mk 24 first_line_match: |- 25 (?xi: 26 ^\#! .* \bmake\b | # shebang 27 ^\# \s* -\*- [^*]* makefile [^*]* -\*- # editorconfig 28 ) 29 scope: source.makefile 30 #------------------------------------------------------------------------------- 31 variables: 32 33 varassign: (\?|\+|::?)?= 34 shellassign: '!=' 35 startdirective: ifn?(def|eq) 36 include: '[s-]?include' 37 ruleassign: :(?!=) 38 function_call_token_begin: \$\$?\( 39 40 # The big "rule lookahead". What we want to do is here is detect if the 41 # line that we are parsing is going to define a rule. So we need to check 42 # if we have something of the form <rule-name> : <rule-prerequisites> 43 # However matters become complicated by the fact that we can have arbitrary 44 # variable substitutions anywhere. We try to remedy this by hacking in a 45 # regex that matches up to four levels of nested parentheses, and ignores 46 # whatever's inside the parentheses. 47 nps: '[^()]*' 48 open: '(?:\(' 49 close: '\))?' # ignore this invalid.illegal 50 just_eat: | # WARNING: INSANITY FOLLOWS! 51 (?x) # ignore whitespace in this regex 52 {{nps}} # level 0 53 {{open}} # start level 1 __ 54 {{nps}} # level 1 _______ /*_>-< 55 {{open}} # start level 2 ___/ _____ \__/ / 56 {{nps}} # level 2 <____/ \____/ 57 {{open}} # start level 3 is like snek... (by Valerie Haecky) 58 {{nps}} # level 3 59 {{open}} # start level 4 60 {{nps}} # level 4 61 {{close}} # end level 4 62 {{nps}} # level 3 63 {{close}} # end level 3 64 {{nps}} # level 2 65 {{open}} # start level 3 66 {{nps}} # level 3 67 {{open}} # start level 4 68 {{nps}} # level 4 69 {{close}} # end level 4 70 {{nps}} # level 3 71 {{close}} # end level 3 72 {{nps}} # level 2 73 {{close}} # end level 2 74 {{nps}} # level 1 75 {{open}} # start level 2 76 {{nps}} # level 2 77 {{open}} # start level 3 78 {{nps}} # level 3 79 {{open}} # start level 4 80 {{nps}} # level 4 81 {{close}} # end level 4 82 {{nps}} # level 3 83 {{close}} # end level 3 84 {{nps}} # level 2 85 {{open}} # start level 3 86 {{nps}} # level 3 87 {{open}} # start level 4 88 {{nps}} # level 4 89 {{close}} # end level 4 90 {{nps}} # level 3 91 {{close}} # end level 3 92 {{nps}} # level 2 93 {{open}} # start level 3 94 {{nps}} # level 3 95 {{open}} # start level 4 96 {{nps}} # level 4 97 {{close}} # end level 4 98 {{nps}} # level 3 99 {{close}} # end level 3 100 {{nps}} # level 2 101 {{close}} # end level 2 102 {{nps}} # level 1 103 {{close}} # end level 1 104 {{nps}} # level 0 105 rule_lookahead: '{{just_eat}}{{ruleassign}}{{just_eat}}' 106 107 var_lookahead_base: '{{just_eat}}({{varassign}}|{{shellassign}}){{just_eat}}' 108 # Just as with rules we want to look ahead if we are going to define a var. 109 # However, due to the possibility of "target-specific" variables (see 6.11), 110 # we want to NOT match if there's a {{ruleassign}} before a {{varassign}}. 111 var_lookahead: (?!{{rule_lookahead}}){{var_lookahead_base}} 112 113 first_assign_then_colon: | 114 (?x) 115 {{just_eat}} 116 {{varassign}} 117 {{just_eat}} 118 {{ruleassign}} 119 {{just_eat}} 120 121 #------------------------------------------------------------------------------- 122 contexts: 123 124 # 3.1 What Makefiles Contain 125 # Makefiles contain five kinds of things: explicit rules, implicit rules, 126 # variable definitions, directives, and comments. 127 main: 128 - include: comments 129 - include: variable-definitions 130 - match: (?={{rule_lookahead}}) 131 push: expect-rule 132 - include: variable-substitutions 133 - include: control-flow 134 - match: ^\s*(endef) 135 captures: 136 1: invalid.illegal.stray.endef.makefile 137 138 inside-control-flow: 139 - meta_scope: meta.group.makefile 140 - match: "'" 141 scope: punctuation.definition.string.begin.makefile 142 push: 143 - meta_scope: meta.string.makefile string.quoted.single.makefile 144 - match: "'" 145 scope: punctuation.definition.string.end.makefile 146 pop: true 147 - include: escape-literals 148 - include: line-continuation 149 - include: variable-substitutions 150 - match: '"' 151 scope: punctuation.definition.string.begin.makefile 152 push: 153 - meta_scope: meta.string.makefile string.quoted.double.makefile 154 - match: '"' 155 scope: punctuation.definition.string.end.makefile 156 pop: true 157 - include: escape-literals 158 - include: line-continuation 159 - include: variable-substitutions 160 - match: \( 161 scope: punctuation.section.group.begin.makefile 162 push: 163 - match: \) 164 scope: punctuation.section.group.end.makefile 165 pop: true 166 - include: variable-substitutions 167 - match: \, 168 scope: punctuation.separator.makefile 169 - match: \) 170 scope: invalid.illegal.stray.paren.makefile 171 - include: continuation-or-pop-on-line-end 172 173 control-flow: 174 - match: ^\s*(vpath)\s 175 captures: 176 1: keyword.control.vpath.makefile 177 push: 178 - include: highlight-wildcard-sign 179 - match: \s 180 set: 181 - meta_content_scope: meta.string.makefile string.unquoted.makefile 182 - include: pop-on-line-end 183 - include: pop-on-line-end 184 - match: ^\s*(vpath)$ 185 captures: keyword.control.vpath.makefile 186 - match: ^\s*({{include}})\s+ 187 captures: 188 1: keyword.control.import.makefile 189 push: 190 - meta_content_scope: meta.string.makefile string.unquoted.makefile 191 - include: continuation-or-pop-on-line-end 192 - include: variable-substitutions 193 - include: comments 194 - match: \b{{startdirective}}\b 195 scope: keyword.control.conditional.makefile 196 push: inside-control-flow 197 - match: ^\s*(else)\b 198 captures: 199 1: keyword.control.conditional.makefile 200 push: 201 - include: control-flow 202 - include: comments 203 - include: pop-on-line-end 204 - match: ^\s*(endif)\b 205 captures: 206 1: keyword.control.conditional.makefile 207 push: 208 - include: comments 209 - include: pop-on-line-end 210 211 highlight-percentage-sign: 212 - match: \% 213 scope: variable.language.makefile 214 215 highlight-wildcard-sign: 216 - match: \* 217 scope: variable.language.wildcard.makefile 218 219 expect-rule: 220 # Anything before the colon is part of the rule's name. 221 - meta_scope: meta.function.makefile entity.name.function.makefile 222 - include: line-continuation 223 - include: variable-substitutions 224 - include: highlight-percentage-sign 225 - match: (?= *::?[^=]+[!:?]?=) 226 set: 227 - match: ::? 228 scope: keyword.operator.assignment.makefile 229 set: 230 - include: variable-definitions 231 - include: variable-substitutions 232 - include: continuation-or-pop-on-line-end 233 - match: (?= *::?) 234 set: 235 - match: (::?)\s* 236 captures: 237 1: keyword.operator.assignment.makefile 238 set: 239 - meta_content_scope: 240 meta.function.arguments.makefile 241 string.unquoted.makefile 242 - include: line-continuation 243 - include: variable-substitutions 244 - include: highlight-percentage-sign 245 - match: (?=#) 246 set: 247 - match: \# 248 scope: punctuation.definition.comment.makefile 249 set: 250 - meta_scope: comment.line.number-sign.makefile 251 - match: $ 252 set: recipe-junction-between-spaces-or-tabs 253 - match: $ 254 set: recipe-junction-between-spaces-or-tabs 255 - match: (?=\s*;) 256 set: 257 - match: ; 258 scope: punctuation.terminator.makefile 259 set: recipe-inline 260 261 recipe-junction-between-spaces-or-tabs: 262 - meta_content_scope: meta.function.body.makefile 263 - include: comments 264 - match: ^\s*({{startdirective}}) 265 captures: 266 1: keyword.control.conditional.makefile 267 push: 268 - include: inside-control-flow 269 - include: recipe-junction-between-spaces-or-tabs 270 - match: ^(?=[ ]+([-@]{1,2})?) 271 set: recipe-with-spaces 272 - match: ^(?=\t([-@]{1,2})?) 273 set: recipe-with-tabs 274 - match: ^ 275 pop: true 276 277 recipe-inline: 278 - meta_content_scope: meta.function.body.makefile source.shell.embedded.makefile 279 - include: recipe-junction-between-spaces-or-tabs 280 - include: control-flow 281 - match: $ 282 set: recipe-junction-between-spaces-or-tabs 283 - include: shell-content 284 285 recipe-with-spaces: 286 - meta_content_scope: meta.function.body.makefile 287 - match: ^([ ]+)([-@]{1,2})? 288 captures: 289 2: constant.language.makefile 290 push: shell-common 291 - match: ^(\t)([-@]{1,2})? 292 captures: 293 1: invalid.illegal.inconsistent.expected.spaces.makefile 294 2: constant.language.makefile 295 - include: recipe-common 296 - match: ^(?![ ]+) 297 pop: true 298 299 recipe-with-tabs: 300 - meta_content_scope: meta.function.body.makefile 301 - match: ^\t([-@]{1,2})? 302 captures: 303 1: constant.language.makefile 304 push: shell-common 305 - match: ^([ ]+)([-@]{1,2})? 306 captures: 307 1: invalid.illegal.inconsistent.expected.tab.makefile 308 2: constant.language.makefile 309 - include: recipe-common 310 - match: ^(?!\t) 311 pop: true 312 313 recipe-common: 314 - include: control-flow 315 - match: ^\n 316 317 shell-common: 318 - meta_content_scope: source.shell.embedded.makefile 319 - include: pop-on-line-end 320 - include: shell-content 321 322 shell-content: 323 - include: Packages/Makefile/Makefile Shell.sublime-syntax 324 apply_prototype: true 325 326 line-continuation: 327 - match: (\\)([ ]*)$\n? 328 captures: 329 1: punctuation.separator.continuation.line.makefile 330 # make sure to resume parsing at next line 331 push: 332 - match: (?=\S|^\s*$) 333 pop: true 334 335 pop-on-line-end: 336 - match: $ 337 pop: true 338 339 continuation-or-pop-on-line-end: 340 - include: line-continuation 341 - include: pop-on-line-end 342 343 quoted-string: 344 - match: "'" 345 scope: punctuation.definition.string.begin.makefile 346 push: 347 - meta_include_prototype: false 348 - meta_scope: meta.string.makefile string.quoted.single.makefile 349 - match: "'" 350 scope: punctuation.definition.string.end.makefile 351 pop: true 352 - include: escape-literals 353 - include: line-continuation 354 - include: variable-substitutions 355 - match: '"' 356 scope: punctuation.definition.string.begin.makefile 357 push: 358 - meta_include_prototype: false 359 - meta_scope: meta.string.makefile string.quoted.double.makefile 360 - match: '"' 361 scope: punctuation.definition.string.end.makefile 362 pop: true 363 - include: escape-literals 364 - include: line-continuation 365 - include: variable-substitutions 366 367 escape-literals: 368 - match: \\. 369 scope: constant.character.escape.makefile 370 371 comments-pop-on-line-end: 372 - include: line-continuation 373 - match: $\n? 374 pop: true 375 376 comments: 377 # This hack is here in order to circumvent false-positives for the big 378 # rule lookahead. For example, if this match is not present, then things 379 # like 380 # 381 # # A comment with a : colon 382 # 383 # will match the rule-lookahead. 384 - match: (?=^\s*#) 385 push: 386 - match: \# 387 scope: punctuation.definition.comment.makefile 388 set: 389 - meta_scope: comment.line.number-sign.makefile 390 - include: comments-pop-on-line-end 391 # This is the "normal" comment parsing logic, but not sufficient in every 392 # case (see above). 393 - match: \# 394 scope: punctuation.definition.comment.makefile 395 push: 396 - meta_scope: comment.line.number-sign.makefile 397 - include: comments-pop-on-line-end 398 399 inside-function-call: 400 - meta_content_scope: meta.function-call.arguments.makefile 401 - match: \) 402 scope: keyword.other.block.end.makefile 403 pop: true 404 - match: \( 405 push: textual-parenthesis-balancer 406 - match: \, 407 scope: punctuation.separator.makefile 408 # eat escaped or unbalanced quotation marks in front of the `,` separator 409 # to highlight them as ordinary part of the surrounding unquoted string 410 - match: '\\[''""]|[''""](?=\s*,)' 411 - include: variable-substitutions 412 - include: quoted-string 413 414 function-invocations: 415 - match: ({{function_call_token_begin}})(call)\s 416 captures: 417 0: meta.function-call.makefile 418 1: keyword.other.block.begin.makefile 419 2: constant.language.call.makefile 420 push: 421 - meta_content_scope: 422 meta.function-call.makefile 423 variable.function.makefile 424 - match: (?=\)) 425 set: inside-function-call 426 - match: (?=,) 427 set: 428 - meta_content_scope: meta.function-call.makefile 429 - match: \, 430 scope: punctuation.separator.makefile 431 set: inside-function-call 432 - include: variable-substitutions 433 - match: ({{function_call_token_begin}})(patsubst|filter)\s 434 captures: 435 0: meta.function-call.makefile 436 1: keyword.other.block.begin.makefile 437 2: support.function.builtin.makefile 438 push: 439 - meta_content_scope: meta.function-call.arguments.makefile 440 - include: highlight-percentage-sign 441 - include: inside-function-call 442 - match: ({{function_call_token_begin}})(wildcard)\s 443 captures: 444 0: meta.function-call.makefile 445 1: keyword.other.block.begin.makefile 446 2: support.function.builtin.makefile 447 push: 448 - meta_content_scope: meta.function-call.arguments.makefile 449 - include: inside-function-call 450 - include: highlight-wildcard-sign 451 - match: ({{function_call_token_begin}})(info|warning|error)\s 452 captures: 453 0: meta.function-call.makefile 454 1: keyword.other.block.begin.makefile 455 2: support.function.builtin.makefile 456 push: 457 - meta_content_scope: meta.function-call.arguments.makefile 458 - match: \) 459 scope: keyword.other.block.end.makefile 460 pop: true 461 - match: \( 462 push: textual-parenthesis-balancer 463 - match: \, 464 scope: punctuation.separator.makefile 465 - include: variable-substitutions 466 - match: | # multiline string 467 (?x) # ignore whitespace 468 ({{function_call_token_begin}}) 469 ( 470 subst| 471 strip| 472 findstring| 473 filter-out| 474 sort| 475 word| 476 wordlist| 477 words| 478 firstword| 479 lastword| 480 dir| 481 notdir| 482 suffix| 483 basename| 484 addsuffix| 485 addprefix| 486 join| 487 realpath| 488 abspath| 489 if| 490 or| 491 and| 492 foreach| 493 file| 494 value| 495 eval| 496 origin| 497 flavor| 498 guile 499 ) 500 \s 501 captures: 502 0: meta.function-call.makefile 503 1: keyword.other.block.begin.makefile 504 2: support.function.builtin.makefile 505 push: inside-function-call 506 - match: ({{function_call_token_begin}})(shell)\s 507 captures: 508 1: keyword.other.block.begin.makefile 509 2: support.function.builtin.makefile 510 push: 511 - meta_content_scope: source.shell.embedded.makefile 512 - match: \) 513 scope: keyword.other.block.end.makefile 514 pop: true 515 - include: shell-content 516 517 variable-definitions: 518 - match: \s*(override)\b 519 captures: 520 1: keyword.control.makefile 521 set: 522 - match: \bdefine\b 523 scope: keyword.control.makefile 524 push: inside-define-directive-context 525 - include: variable-definitions 526 - include: continuation-or-pop-on-line-end 527 - match: \s*(define)\b 528 captures: 529 1: keyword.control.makefile 530 push: inside-define-directive-context 531 - match: ^\s*(export)\b 532 captures: 533 1: keyword.control.makefile 534 push: 535 - meta_content_scope: variable.other.makefile 536 - include: continuation-or-pop-on-line-end 537 - include: variable-substitutions 538 - match: (\?|\+|::?)?= 539 scope: keyword.operator.assignment.makefile 540 set: [value-to-be-defined, eat-whitespace-then-pop] 541 - match: (?={{var_lookahead}}|{{first_assign_then_colon}}) 542 push: 543 - meta_content_scope: variable.other.makefile 544 - match: (?=\s*!=) 545 set: 546 - match: '!=' 547 scope: keyword.operator.assignment.makefile 548 set: shell-common 549 - match: (?=\s*(!|\?|\+|::?)?=) 550 set: 551 - match: (!|\?|\+|::?)?= 552 scope: keyword.operator.assignment.makefile 553 set: [value-maybe-shellscript, eat-whitespace-then-pop] 554 - include: variable-substitutions 555 - include: continuation-or-pop-on-line-end 556 - include: variable-substitutions 557 558 textual-parenthesis-balancer: 559 - match: \) 560 pop: true 561 - include: variable-substitutions 562 563 eat-whitespace-then-pop: 564 - clear_scopes: 1 565 - match: \s* 566 pop: true 567 568 value-maybe-shellscript: 569 - match: ((?:bash|sh|zsh)\s+-c\s+)(['"`]) 570 captures: 571 1: meta.string.makefile string.unquoted.makefile 572 2: meta.string.makefile meta.interpolation.makefile punctuation.section.interpolation.begin.makefile 573 embed: shell-content 574 embed_scope: meta.string.makefile meta.interpolation.makefile source.shell.embedded.makefile 575 escape: (?!<\\)\2 576 escape_captures: 577 0: meta.string.makefile meta.interpolation.makefile punctuation.section.interpolation.end.makefile 578 - match: '' 579 set: value-to-be-defined 580 581 value-to-be-defined: 582 - meta_content_scope: meta.string.makefile string.unquoted.makefile 583 - include: escape-literals 584 - match: (?=#) 585 set: 586 - match: \# 587 scope: punctuation.definition.comment.makefile 588 set: 589 - meta_scope: comment.line.number-sign.makefile 590 - include: comments-pop-on-line-end 591 - include: variable-substitutions 592 - include: continuation-or-pop-on-line-end 593 594 inside-define-directive-context: 595 - meta_content_scope: variable.other.makefile 596 - match: (?=(!|\?|\+|::?)?=\s*\n) 597 set: 598 - match: ((!|\?|\+|::?)?=)\s*\n 599 captures: 600 1: keyword.operator.assignment.makefile 601 set: inside-define-directive-value 602 603 # Need to eat the actual newline character in order to start the 604 # string.unquoted scope on the next line. 605 - match: \n 606 set: inside-define-directive-value 607 - include: variable-substitutions 608 609 inside-define-directive-value: 610 - meta_content_scope: meta.string.makefile string.unquoted.makefile 611 - match: ^\s*(endef)\b 612 captures: 613 1: keyword.control.makefile 614 pop: true 615 # keep in balance with nested define statements 616 # see: https://github.com/sublimehq/Packages/issues/1998 617 - match: ^\s*define\b 618 push: 619 - match: ^\s*endef\b 620 pop: true 621 622 variable-sub-common: 623 - match: ':' 624 scope: punctuation.definition.substitution.makefile 625 - match: = 626 scope: punctuation.definition.assignment.makefile 627 - include: highlight-percentage-sign 628 - include: variable-substitutions 629 630 variable-substitutions: 631 - include: function-invocations 632 - match: \$\$?\( 633 scope: keyword.other.block.begin.makefile 634 push: 635 - meta_scope: variable.parameter.makefile 636 - match: \) 637 scope: keyword.other.block.end.makefile 638 pop: true 639 - include: variable-sub-common 640 - match: \$\$?{ 641 scope: keyword.other.block.begin.makefile 642 push: 643 - meta_scope: variable.parameter.makefile 644 - match: \} 645 scope: keyword.other.block.end.makefile 646 pop: true 647 - include: variable-sub-common 648 - match: \$\$?[@%<?^+|*] 649 scope: variable.language.automatic.makefile 650 - match: \$\$ 651 scope: constant.character.escape.makefile 652 - match: (\$)[[:alpha:]] 653 captures: 654 0: variable.parameter.makefile 655 1: keyword.other.single-character-variable.makefile