├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── grammars └── batchfile.cson ├── package-lock.json ├── package.json ├── settings └── language-batchfile.cson ├── snippets └── language-batchfile.cson └── spec ├── fixtures ├── comments.bat ├── constants.bat ├── controls.bat ├── issues │ ├── issue_023.bat │ ├── issue_024.bat │ ├── issue_025.bat │ ├── issue_026.bat │ ├── issue_028.bat │ ├── issue_029.bat │ ├── issue_034.bat │ └── issue_035.bat ├── keywords.bat ├── operators.bat ├── strings.bat └── variables.bat └── grammar-spec.coffee /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = false 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{bat,cmd}] 15 | end_of_line = crlf 16 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.7.7 - Grammar Fixes 2 | * Fix inline comments with labels. Fixes #35. (Thanks CPterion) 3 | * Fix arithmetic assignments with quotations. Fixes #34. (Thanks CPterion) 4 | * Fix incorrect scoping of batch parameters. Fixes #29. (Thanks msftrncs) 5 | 6 | ## 0.7.6 - Grammar Fixes 7 | * Add OpenSSH keywords. Fixes #31. 8 | * Add wmic and wsl keywords. (Thanks mataha) 9 | 10 | ## 0.7.5 - Grammar Fixes 11 | * Fix string assignments with SET /A. Fixes #28. 12 | 13 | ## 0.7.4 - Grammar Fixes 14 | * Fix issues with echo statements. Fixes #26. 15 | * Fix string assignments with SET /P. Fixes #26. 16 | * Fix issue with goto statements and labels. Fixes #26. 17 | * Add CLS command and recognize SETLOCAL arguments. Fixes #26. 18 | * Identify escaped characters in SET string assignments. Fixes #26. 19 | 20 | ## 0.7.3 - Grammar Fixes 21 | * Fix quoted variable assignment. Fixes #23. 22 | 23 | ## 0.7.2 - Grammar Fixes 24 | * Escape double parentheses in quoted strings. Fixes #24. 25 | 26 | ## 0.7.1 - Grammar Fixes 27 | * Ensure all capture groups have a `name` key. Pull request #21. 28 | 29 | ## 0.7.0 - Spec Testing 30 | * Add Atom Grammar Test suite and tests. 31 | * Better recognition of word boundaries for keywords. Fixes #19. 32 | * Snippets keywords changed to upper case for consistency. 33 | 34 | ## 0.6.3 - Syntax Fixes 35 | * Don't search for escaped characters in strings. Fixes #17. 36 | * Revert back to special-method scope for labels. Fixes #15. 37 | * Avoid using the ambiguous \h shorthand character. Fixes #16 . 38 | 39 | ## 0.6.2 - Syntax Fixes 40 | * Clean up command keyword recognition. 41 | * Fix variable substring issue with Github highlighter. 42 | * Improve variable replacement end of line recognition. 43 | 44 | ## 0.6.1 - Package Specification 45 | * Update package description for atom.io listing. 46 | 47 | ## 0.6.0 - Major Grammar Rewrite 48 | * Better organization of matching patterns. 49 | * Improved support for set command. 50 | * Improved support for variables including substring and substitution expansions. 51 | * Improved command keyword recognition. 52 | * Unclosed string highlighting does not cross new lines. Fixes #11. 53 | * Escaped characters in delayed expansion variables works properly. Fixes #11. 54 | * Properly scope arithmetic operators. Fixes #10. 55 | * Support for inline comments using &:: syntax. Fixes #9. 56 | 57 | ## 0.5.3 - Syntax Fixes 58 | * Fixed issue with new lines at the end of label highlights. Fixes #12. 59 | 60 | ## 0.5.2 - Package Specification 61 | * Add keywords to package Specification. 62 | 63 | ## 0.5.1 - Syntax Fixes 64 | * Fixed improper highlighting of environment variable substitution. Fixes #8. 65 | 66 | ## 0.5.0 - Syntax Fixes 67 | * Fixed command line argument variable highlighting. Fixes #7. 68 | * Fixed improper string highlighting for `echo` strings. Fixes #5. 69 | 70 | ## 0.4.0 - Update to 1.0 APIs 71 | * Renamed scoped-properties/ to settings/ 72 | 73 | ## 0.3.0 - Syntax and Snippets Update 74 | * Syntax highlighting for nul constant added 75 | * Initial snippets support for if, else, and for added 76 | 77 | ## 0.2.0 - Syntax Update 78 | * Syntax highlighting for variable substrings and replacement added 79 | * Syntax highlighting for wildcard argument 80 | 81 | ## 0.1.1 - Syntax Fix 82 | * Syntax highlighting for delayed expansion variables added 83 | 84 | ## 0.1.0 - First Release 85 | * Syntax highlighting added 86 | * Indent pattern and comment start added 87 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Michael Mims 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Windows batch file language support in Atom 2 | 3 | Adds syntax highlighting and snippets for batch files in Atom. 4 | 5 | ![language-batchfile](https://cloud.githubusercontent.com/assets/534908/26175651/550d981a-3b21-11e7-8eb0-d19b3d8c60be.png) 6 | 7 | _One Light with Chester Atom theme_ 8 | -------------------------------------------------------------------------------- /grammars/batchfile.cson: -------------------------------------------------------------------------------- 1 | 'scopeName': 'source.batchfile' 2 | 'name': 'Batch File' 3 | 'fileTypes': [ 4 | 'bat' 5 | 'cmd' 6 | ] 7 | 'injections': 8 | 'L:meta.block.repeat.batchfile': 9 | 'patterns': [ 10 | { 11 | 'include': '#repeatParameter' 12 | } 13 | ] 14 | 'patterns': [ 15 | { 16 | 'include': '#commands' 17 | } 18 | { 19 | 'include': '#comments' 20 | } 21 | { 22 | 'include': '#constants' 23 | } 24 | { 25 | 'include': '#controls' 26 | } 27 | { 28 | 'include': '#escaped_characters' 29 | } 30 | { 31 | 'include': '#labels' 32 | } 33 | { 34 | 'include': '#numbers' 35 | } 36 | { 37 | 'include': '#operators' 38 | } 39 | { 40 | 'include': '#parens' 41 | } 42 | { 43 | 'include': '#strings' 44 | } 45 | { 46 | 'include': '#variables' 47 | } 48 | ] 49 | 'repository': 50 | 'commands': 51 | 'patterns': [ 52 | { 53 | 'match': '(?<=^|[\\s@])(?i:adprep|append|arp|assoc|at|atmadm|attrib|auditpol|autochk|autoconv|autofmt|bcdboot|bcdedit|bdehdcfg|bitsadmin|bootcfg|brea|cacls|cd|certreq|certutil|change|chcp|chdir|chglogon|chgport|chgusr|chkdsk|chkntfs|choice|cipher|clip|cls|clscluadmin|cluster|cmd|cmdkey|cmstp|color|comp|compact|convert|copy|cprofile|cscript|csvde|date|dcdiag|dcgpofix|dcpromo|defra|del|dfscmd|dfsdiag|dfsrmig|diantz|dir|dirquota|diskcomp|diskcopy|diskpart|diskperf|diskraid|diskshadow|dispdiag|doin|dnscmd|doskey|driverquery|dsacls|dsadd|dsamain|dsdbutil|dsget|dsmgmt|dsmod|dsmove|dsquery|dsrm|edit|endlocal|eraseesentutl|eventcreate|eventquery|eventtriggers|evntcmd|expand|extract|fc|filescrn|find|findstr|finger|flattemp|fonde|forfiles|format|freedisk|fsutil|ftp|ftype|fveupdate|getmac|gettype|gpfixup|gpresult|gpupdate|graftabl|hashgen|hep|helpctr|hostname|icacls|iisreset|inuse|ipconfig|ipxroute|irftp|ismserv|jetpack|klist|ksetup|ktmutil|ktpass|label|ldifd|ldp|lodctr|logman|logoff|lpq|lpr|macfile|makecab|manage-bde|mapadmin|md|mkdir|mklink|mmc|mode|more|mount|mountvol|move|mqbup|mqsvc|mqtgsvc|msdt|msg|msiexec|msinfo32|mstsc|nbtstat|net computer|net group|net localgroup|net print|net session|net share|net start|net stop|net use|net user|net view|net|netcfg|netdiag|netdom|netsh|netstat|nfsadmin|nfsshare|nfsstat|nlb|nlbmgr|nltest|nslookup|ntackup|ntcmdprompt|ntdsutil|ntfrsutl|openfiles|pagefileconfig|path|pathping|pause|pbadmin|pentnt|perfmon|ping|pnpunatten|pnputil|popd|powercfg|powershell|powershell_ise|print|prncnfg|prndrvr|prnjobs|prnmngr|prnport|prnqctl|prompt|pubprn|pushd|pushprinterconnections|pwlauncher|qappsrv|qprocess|query|quser|qwinsta|rasdial|rcp|rd|rdpsign|regentc|recover|redircmp|redirusr|reg|regini|regsvr32|relog|ren|rename|rendom|repadmin|repair-bde|replace|reset session|rxec|risetup|rmdir|robocopy|route|rpcinfo|rpcping|rsh|runas|rundll32|rwinsta|sc|schtasks|scp|scwcmd|secedit|serverceipoptin|servrmanagercmd|serverweroptin|setspn|setx|sfc|sftp|shadow|shift|showmount|shutdown|sort|ssh|ssh-add|ssh-agent|ssh-keygen|ssh-keyscan|start|storrept|subst|sxstrace|ysocmgr|systeminfo|takeown|tapicfg|taskkill|tasklist|tcmsetup|telnet|tftp|time|timeout|title|tlntadmn|tpmvscmgr|tpmvscmgr|tacerpt|tracert|tree|tscon|tsdiscon|tsecimp|tskill|tsprof|type|typeperf|tzutil|uddiconfig|umount|unlodctr|ver|verifier|verif|vol|vssadmin|w32tm|waitfor|wbadmin|wdsutil|wecutil|wevtutil|where|whoami|winnt|winnt32|winpop|winrm|winrs|winsat|wlbs|wmic|wscript|wsl|xcopy)(?=$|\\s)' 54 | 'name': 'keyword.command.batchfile' 55 | } 56 | { 57 | 'begin': '(?i)(?<=^|[\\s@])(echo)(?:(?=$|\\.|:)|\\s+(?:(on|off)(?=\\s*$))?)' 58 | 'beginCaptures': 59 | '1': 60 | 'name': 'keyword.command.batchfile' 61 | '2': 62 | 'name': 'keyword.other.special-method.batchfile' 63 | 'end': '(?=$\\n|[&|><)])' 64 | 'patterns': [ 65 | { 66 | 'include': '#escaped_characters' 67 | } 68 | { 69 | 'include': '#variables' 70 | } 71 | { 72 | 'include': '#numbers' 73 | } 74 | { 75 | 'include': '#strings' 76 | } 77 | ] 78 | } 79 | { 80 | 'match': '(?i)(?<=^|[\\s@])(setlocal)(?:\\s*$|\\s+(EnableExtensions|DisableExtensions|EnableDelayedExpansion|DisableDelayedExpansion)(?=\\s*$))' 81 | 'captures': 82 | '1': 83 | 'name': 'keyword.command.batchfile' 84 | '2': 85 | 'name': 'keyword.other.special-method.batchfile' 86 | } 87 | { 88 | 'include': '#command_set' 89 | } 90 | ] 91 | 'command_set': 92 | 'patterns': [ 93 | { 94 | 'begin': '(?<=^|[\\s@])(?i:SET)(?=$|\\s)' 95 | 'beginCaptures': 96 | '0': 97 | 'name': 'keyword.command.batchfile' 98 | 'end': '(?=$\\n|[&|><)])' 99 | 'patterns': [ 100 | { 101 | 'include': '#command_set_inside' 102 | } 103 | ] 104 | } 105 | ] 106 | 'command_set_inside': 107 | 'patterns': [ 108 | { 109 | 'include': '#escaped_characters' 110 | } 111 | { 112 | 'include': '#variables' 113 | } 114 | { 115 | 'include': '#numbers' 116 | } 117 | { 118 | 'include': '#parens' 119 | } 120 | { 121 | 'include': '#command_set_strings' 122 | } 123 | { 124 | 'include': '#strings' 125 | } 126 | { 127 | 'begin': '([^ ][^=]*)(=)' 128 | 'beginCaptures': 129 | '1': 130 | 'name': 'variable.other.readwrite.batchfile' 131 | '2': 132 | 'name': 'keyword.operator.assignment.batchfile' 133 | 'end': '(?=$\\n|[&|><)])' 134 | 'patterns': [ 135 | { 136 | 'include': '#escaped_characters' 137 | } 138 | { 139 | 'include': '#variables' 140 | } 141 | { 142 | 'include': '#numbers' 143 | } 144 | { 145 | 'include': '#parens' 146 | } 147 | { 148 | 'include': '#strings' 149 | } 150 | ] 151 | } 152 | { 153 | 'begin': '\\s+/[aA]\\s+' 154 | 'end': '(?=$\\n|[&|><)])' 155 | 'name': 'meta.expression.set.batchfile' 156 | 'patterns': [ 157 | { 158 | 'begin': '"' 159 | 'beginCaptures': 160 | '0': 161 | 'name': 'punctuation.definition.string.begin.batchfile' 162 | 'end': '"' 163 | 'endCaptures': 164 | '0': 165 | 'name': 'punctuation.definition.string.end.batchfile' 166 | 'name': 'string.quoted.double.batchfile' 167 | 'patterns': [ 168 | { 169 | 'include': '#command_set_inside_arithmetic' 170 | } 171 | { 172 | 'include': '#command_set_group' 173 | } 174 | { 175 | 'include': '#variables' 176 | } 177 | ] 178 | } 179 | { 180 | 'include': '#command_set_inside_arithmetic' 181 | } 182 | { 183 | 'include': '#command_set_group' 184 | } 185 | ] 186 | } 187 | { 188 | 'begin': '\\s+/[pP]\\s+' 189 | 'end': '(?=$\\n|[&|><)])' 190 | 'patterns': [ 191 | { 192 | 'include': '#command_set_strings' 193 | } 194 | { 195 | 'begin': '([^ ][^=]*)(=)' 196 | 'beginCaptures': 197 | '1': 198 | 'name': 'variable.other.readwrite.batchfile' 199 | '2': 200 | 'name': 'keyword.operator.assignment.batchfile' 201 | 'end': '(?=$\\n|[&|><)])' 202 | 'name': 'meta.prompt.set.batchfile' 203 | 'patterns': [ 204 | { 205 | 'include': '#strings' 206 | } 207 | ] 208 | } 209 | ] 210 | } 211 | ] 212 | 'command_set_group': 213 | 'patterns': [ 214 | { 215 | 'begin': '\\(' 216 | 'beginCaptures': 217 | '0': 218 | 'name': 'punctuation.section.group.begin.batchfile' 219 | 'end': '\\)' 220 | 'endCaptures': 221 | '0': 222 | 'name': 'punctuation.section.group.end.batchfile' 223 | 'patterns': [ 224 | { 225 | 'include': '#command_set_inside_arithmetic' 226 | } 227 | ] 228 | } 229 | ] 230 | 'command_set_inside_arithmetic': 231 | 'patterns': [ 232 | { 233 | 'include': '#command_set_operators' 234 | } 235 | { 236 | 'include': '#numbers' 237 | } 238 | { 239 | 'match': ',' 240 | 'name': 'punctuation.separator.batchfile' 241 | } 242 | ] 243 | 'command_set_operators': 244 | 'patterns': [ 245 | { 246 | 'match': '([^ ]*)(\\+\\=|\\-\\=|\\*\\=|\\/\\=|%%\\=|&\\=|\\|\\=|\\^\\=|<<\\=|>>\\=)' 247 | 'captures': 248 | '1': 249 | 'name': 'variable.other.readwrite.batchfile' 250 | '2': 251 | 'name': 'keyword.operator.assignment.augmented.batchfile' 252 | } 253 | { 254 | 'match': '\\+|\\-|/|\\*|%%|\\||&|\\^|<<|>>|~' 255 | 'name': 'keyword.operator.arithmetic.batchfile' 256 | } 257 | { 258 | 'match': '!' 259 | 'name': 'keyword.operator.logical.batchfile' 260 | } 261 | { 262 | 'match': '([^ =]*)(=)' 263 | 'captures': 264 | '1': 265 | 'name': 'variable.other.readwrite.batchfile' 266 | '2': 267 | 'name': 'keyword.operator.assignment.batchfile' 268 | } 269 | ] 270 | 'command_set_strings': 271 | 'patterns': [ 272 | { 273 | 'begin': '(")\\s*([^ ][^=]*)(=)' 274 | 'beginCaptures': 275 | '1': 276 | 'name': 'punctuation.definition.string.begin.batchfile' 277 | '2': 278 | 'name': 'variable.other.readwrite.batchfile' 279 | '3': 280 | 'name': 'keyword.operator.assignment.batchfile' 281 | 'end': '"' 282 | 'endCaptures': 283 | '0': 284 | 'name': 'punctuation.definition.string.end.batchfile' 285 | 'name': 'string.quoted.double.batchfile' 286 | 'patterns': [ 287 | { 288 | 'include': '#variables' 289 | } 290 | { 291 | 'include': '#numbers' 292 | } 293 | { 294 | 'include': '#escaped_characters' 295 | } 296 | ] 297 | } 298 | ] 299 | 'comments': 300 | 'patterns': [ 301 | { 302 | 'begin': '(?:^|(&))\\s*(?=((?::[+=,;: ])))' 303 | 'beginCaptures': 304 | '1': 305 | 'name': 'keyword.operator.conditional.batchfile' 306 | 'end': '\\n' 307 | 'patterns': [ 308 | { 309 | 'begin': '((?::[+=,;: ]))' 310 | 'beginCaptures': 311 | '1': 312 | 'name': 'punctuation.definition.comment.batchfile' 313 | 'end': '(?=\\n)' 314 | 'name': 'comment.line.colon.batchfile' 315 | } 316 | ] 317 | } 318 | { 319 | 'begin': '(?<=^|[\\s@])(?i)(REM)(\\.)' 320 | 'beginCaptures': 321 | '1': 322 | 'name': 'keyword.command.rem.batchfile' 323 | '2': 324 | 'name': 'punctuation.separator.batchfile' 325 | 'end': '(?=$\\n|[&|><)])' 326 | 'name': 'comment.line.rem.batchfile' 327 | } 328 | { 329 | # https://technet.microsoft.com/en-us/library/cc753384(v=ws.11).aspx 330 | 'begin': '(?<=^|[\\s@])(?i:rem)\\b' 331 | 'beginCaptures': 332 | '0': 333 | 'name': 'keyword.command.rem.batchfile' 334 | 'end': '\\n' 335 | 'name': 'comment.line.rem.batchfile' 336 | 'patterns': [ 337 | { 338 | 'match': '[><|]' 339 | 'name': 'invalid.illegal.unexpected-character.batchfile' 340 | } 341 | ] 342 | } 343 | ] 344 | 'constants': 345 | 'patterns': [ 346 | { 347 | 'match': '\\b(?i:NUL)\\b' 348 | 'name': 'constant.language.batchfile' 349 | } 350 | ] 351 | 'controls': 352 | 'patterns': [ 353 | { 354 | 'match': '(?i)(?<=^|\\s)(?:call|exit(?=$|\\s)|goto(?=$|\\s|:))' 355 | 'name': 'keyword.control.statement.batchfile' 356 | } 357 | { 358 | 'match': '(?<=^|\\s)(?i)(if)\\s+(?:(not)\\s+)?(exist|defined|errorlevel|cmdextversion)(?=\\s)' 359 | 'captures': 360 | '1': 361 | 'name': 'keyword.control.conditional.batchfile' 362 | '2': 363 | 'name': 'keyword.operator.logical.batchfile' 364 | '3': 365 | 'name': 'keyword.other.special-method.batchfile' 366 | } 367 | { 368 | 'match': '(?<=^|\\s)(?i)(?:if|else)(?=$|\\s)' 369 | 'name': 'keyword.control.conditional.batchfile' 370 | } 371 | { 372 | 'begin': '(?<=^|[\\s(&^])(?i)for(?=\\s)' 373 | 'beginCaptures': 374 | '0': 375 | 'name': 'keyword.control.repeat.batchfile' 376 | 'name': 'meta.block.repeat.batchfile' 377 | 'end': '\\n' 378 | 'patterns':[ 379 | { 380 | 'begin': '(?<=[\\s^])(?i)in(?=\\s)' 381 | 'beginCaptures': 382 | '0': 383 | 'name': 'keyword.control.repeat.in.batchfile' 384 | 'end': '(?<=[\\s)^])(?i)do(?=\\s)|\\n', 385 | 'endCaptures': 386 | '0': 387 | 'name': 'keyword.control.repeat.do.batchfile' 388 | 'patterns':[ 389 | { 390 | 'include': '$self' 391 | } 392 | ] 393 | } 394 | { 395 | 'include': '$self' 396 | } 397 | ] 398 | } 399 | ] 400 | 'escaped_characters': 401 | 'patterns': [ 402 | { 403 | 'match': '%%|\\^\\^!|\\^(?=.)|\\^\\n' 404 | 'name': 'constant.character.escape.batchfile' 405 | } 406 | ] 407 | 'labels': 408 | 'patterns': [ 409 | { 410 | 'match': '(?i)(?:^\\s*|(?<=call|goto)\\s*)(:)([^+=,;:\\s]\\S*)' 411 | 'captures': 412 | '1': 413 | 'name': 'punctuation.separator.batchfile' 414 | '2': 415 | 'name': 'keyword.other.special-method.batchfile' 416 | } 417 | ] 418 | 'numbers': 419 | 'patterns': [ 420 | { 421 | 'match': '(?<=^|\\s|=)(0[xX][0-9A-Fa-f]*|[+-]?\\d+)(?=$|\\s|<|>)' 422 | 'name': 'constant.numeric.batchfile' 423 | } 424 | ] 425 | 'operators': 426 | 'patterns': [ 427 | { 428 | 'match': '@(?=\\S)' 429 | 'name': 'keyword.operator.at.batchfile' 430 | } 431 | { 432 | 'match': '(?<=\\s)(?i:EQU|NEQ|LSS|LEQ|GTR|GEQ)(?=\\s)|==' 433 | 'name': 'keyword.operator.comparison.batchfile' 434 | } 435 | { 436 | 'match': '(?<=\\s)(?i)(NOT)(?=\\s)' 437 | 'name': 'keyword.operator.logical.batchfile' 438 | } 439 | { 440 | 'match': '(?[&>]?' 449 | 'name': 'keyword.operator.redirection.batchfile' 450 | } 451 | ] 452 | 'parens': 453 | 'patterns': [ 454 | { 455 | 'begin': '\\(' 456 | 'beginCaptures': 457 | '0': 'name': 'punctuation.section.group.begin.batchfile' 458 | 'end': '\\)' 459 | 'endCaptures': 460 | '0': 'name': 'punctuation.section.group.end.batchfile' 461 | 'name': 'meta.group.batchfile' 462 | 'patterns': [ 463 | { 464 | 'match': ',|;' 465 | 'name': 'punctuation.separator.batchfile' 466 | } 467 | { 468 | 'include': '$self' 469 | } 470 | ] 471 | } 472 | ] 473 | 'repeatParameter': 474 | 'patterns': [ 475 | { 476 | 'match': '(%%)(?:(?i:~[fdpnxsatz]*(?:\\$PATH:)?)?[a-zA-Z])' 477 | 'captures': 478 | '1': 479 | 'name': 'punctuation.definition.variable.batchfile' 480 | 'name': 'variable.parameter.repeat.batchfile' 481 | } 482 | ] 483 | 'strings': 484 | 'patterns': [ 485 | { 486 | 'begin': '"' 487 | 'beginCaptures': 488 | '0': 489 | 'name': 'punctuation.definition.string.begin.batchfile' 490 | 'end': '(")|(\\n)' 491 | 'endCaptures': 492 | '1': 493 | 'name': 'punctuation.definition.string.end.batchfile' 494 | '2': 495 | 'name': 'invalid.illegal.newline.batchfile' 496 | 'name': 'string.quoted.double.batchfile' 497 | 'patterns': [ 498 | { 499 | 'match': '%%' 500 | 'name': 'constant.character.escape.batchfile' 501 | } 502 | { 503 | 'include': '#variables' 504 | } 505 | ] 506 | } 507 | ] 508 | 'variables': 509 | 'patterns': [ 510 | { 511 | 'match': '(%)(?:(?i:~[fdpnxsatz]*(?:\\$PATH:)?)?\\d|\\*)' 512 | 'captures': 513 | '1': 514 | 'name': 'punctuation.definition.variable.batchfile' 515 | 'name': 'variable.parameter.batchfile' 516 | } 517 | { 518 | 'include': '#variable' 519 | } 520 | { 521 | 'include': '#variable_delayed_expansion' 522 | } 523 | ] 524 | 'variable': 525 | 'patterns': [ 526 | { 527 | 'begin': '%(?=[^%]+%)' 528 | 'beginCaptures': 529 | '0': 530 | 'name': 'punctuation.definition.variable.begin.batchfile' 531 | 'end': '(%)|\\n' 532 | 'endCaptures': 533 | '1': 534 | 'name': 'punctuation.definition.variable.end.batchfile' 535 | 'name': 'variable.other.readwrite.batchfile' 536 | 'patterns': [ 537 | { 538 | 'begin': ':~' 539 | 'beginCaptures': 540 | '0': 541 | 'name': 'punctuation.separator.batchfile' 542 | 'end': '(?=%|\\n)' 543 | 'name': 'meta.variable.substring.batchfile' 544 | 'patterns': [ 545 | { 546 | 'include': '#variable_substring' 547 | } 548 | ] 549 | } 550 | { 551 | 'begin': ':' 552 | 'beginCaptures': 553 | '0': 554 | 'name': 'punctuation.separator.batchfile' 555 | 'end': '(?=%|\\n)' 556 | 'name': 'meta.variable.substitution.batchfile' 557 | 'patterns': [ 558 | { 559 | 'include': '#variable_replace' 560 | } 561 | { 562 | 'begin': '=' 563 | 'beginCaptures': 564 | '0': 565 | 'name': 'punctuation.separator.batchfile' 566 | 'end': '(?=%|\\n)' 567 | 'patterns': [ 568 | { 569 | 'include': '#variable_delayed_expansion' 570 | } 571 | { 572 | 'match': '[^%]+' 573 | 'name': 'string.unquoted.batchfile' 574 | } 575 | ] 576 | } 577 | ] 578 | } 579 | ] 580 | } 581 | ] 582 | 'variable_delayed_expansion': 583 | 'patterns': [ 584 | { 585 | 'begin': '!(?=[^!]+!)' 586 | 'beginCaptures': 587 | '0': 588 | 'name': 'punctuation.definition.variable.begin.batchfile' 589 | 'end': '(!)|\\n' 590 | 'endCaptures': 591 | '1': 592 | 'name': 'punctuation.definition.variable.end.batchfile' 593 | 'name': 'variable.other.readwrite.batchfile' 594 | 'patterns': [ 595 | { 596 | 'begin': ':~' 597 | 'beginCaptures': 598 | '0': 599 | 'name': 'punctuation.separator.batchfile' 600 | 'end': '(?=!|\\n)' 601 | 'name': 'meta.variable.substring.batchfile' 602 | 'patterns': [ 603 | { 604 | 'include': '#variable_substring' 605 | } 606 | ] 607 | } 608 | { 609 | 'begin': ':' 610 | 'beginCaptures': 611 | '0': 612 | 'name': 'punctuation.separator.batchfile' 613 | 'end': '(?=!|\\n)' 614 | 'name': 'meta.variable.substitution.batchfile' 615 | 'patterns': [ 616 | { 617 | 'include': '#escaped_characters' 618 | } 619 | { 620 | 'include': '#variable_replace' 621 | } 622 | { 623 | 'include': '#variable' 624 | } 625 | { 626 | 'begin': '=' 627 | 'beginCaptures': 628 | '0': 629 | 'name': 'punctuation.separator.batchfile' 630 | 'end': '(?=!|\\n)' 631 | 'patterns': [ 632 | { 633 | 'include': '#variable' 634 | } 635 | { 636 | 'match': '[^!]+' 637 | 'name': 'string.unquoted.batchfile' 638 | } 639 | ] 640 | } 641 | ] 642 | } 643 | ] 644 | } 645 | ] 646 | 'variable_replace': 647 | 'patterns': [ 648 | { 649 | 'match': '[^=%!\\n]+' 650 | 'name': 'string.unquoted.batchfile' 651 | } 652 | ] 653 | 'variable_substring': 654 | 'patterns': [ 655 | { 656 | 'match': '([+-]?\\d+)(?:(,)([+-]?\\d+))?' 657 | 'captures': 658 | '1': 659 | 'name': 'constant.numeric.batchfile' 660 | '2': 661 | 'name': 'punctuation.separator.batchfile' 662 | '3': 663 | 'name': 'constant.numeric.batchfile' 664 | } 665 | ] 666 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "language-batchfile", 3 | "version": "0.7.7", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "atom-grammar-test": { 8 | "version": "0.6.4", 9 | "resolved": "https://registry.npmjs.org/atom-grammar-test/-/atom-grammar-test-0.6.4.tgz", 10 | "integrity": "sha1-2KU1A9H+k5mX9Ji3SirDEARKfU4=", 11 | "dev": true, 12 | "requires": { 13 | "chevrotain": "^0.18.0", 14 | "escape-string-regexp": "^1.0.5" 15 | } 16 | }, 17 | "chevrotain": { 18 | "version": "0.18.0", 19 | "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-0.18.0.tgz", 20 | "integrity": "sha1-sodxTjFZC64sXR4vYRZz7+xHnYA=", 21 | "dev": true 22 | }, 23 | "escape-string-regexp": { 24 | "version": "1.0.5", 25 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 26 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 27 | "dev": true 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "language-batchfile", 3 | "version": "0.7.7", 4 | "description": "Actively maintained Windows batch file language support in Atom.", 5 | "repository": "https://github.com/mmims/language-batchfile", 6 | "license": "MIT", 7 | "keywords": [ 8 | "windows", 9 | "batch", 10 | "bat", 11 | "cmd" 12 | ], 13 | "engines": { 14 | "atom": ">0.50.0" 15 | }, 16 | "devDependencies": { 17 | "atom-grammar-test": "^0.6.4" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /settings/language-batchfile.cson: -------------------------------------------------------------------------------- 1 | '.source.batchfile': 2 | 'editor': 3 | 'commentStart': 'REM ' 4 | 'increaseIndentPattern': '^.*(\\([^\\)]*)$' 5 | 'decreaseIndentPattern': '^\\s*\\)\\s*$' 6 | -------------------------------------------------------------------------------- /snippets/language-batchfile.cson: -------------------------------------------------------------------------------- 1 | '.source.batchfile': 2 | 'if': 3 | 'prefix': 'if' 4 | 'body': 'IF ${1:condition} (\n\t${0:REM statement}\n)' 5 | 'else': 6 | 'prefix': 'el' 7 | 'body': 'ELSE (\n\t${0:REM statement}\n)' 8 | 'for': 9 | 'prefix': 'for' 10 | 'body': 'FOR /${1:F} %%${2:a} IN (${3:set}) DO ${0:command}' 11 | -------------------------------------------------------------------------------- /spec/fixtures/comments.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | REM This is a comment 4 | REM^^^ keyword.command.rem.batchfile comment.line.rem.batchfile 5 | REM^^^^^^^^^^^^^^^^^^^^^ comment.line.rem.batchfile 6 | 7 | REM Illegal characters < | > added 8 | REM^^^ keyword.command.rem.batchfile comment.line.rem.batchfile 9 | REM^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.rem.batchfile 10 | REM ^ ^ ^ invalid.illegal.unexpected-character.batchfile 11 | 12 | REM Don't join a command inline & DIR 13 | REM^^^ keyword.command.rem.batchfile comment.line.rem.batchfile 14 | REM^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.rem.batchfile 15 | 16 | REM. Join a command inline & DIR 17 | REM^^^ keyword.command.rem.batchfile comment.line.rem.batchfile 18 | REM ^ punctuation.separator.batchfile 19 | REM^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.rem.batchfile 20 | REM ^ keyword.operator.conditional.batchfile 21 | REM ^^^ keyword.command.batchfile 22 | 23 | DIR /a /s somedir & REM Inline comment 24 | REM <- keyword.command.batchfile 25 | REM ^ keyword.operator.conditional.batchfile 26 | REM ^^^ keyword.command.rem.batchfile 27 | REM ^^^^^^^^^^^^^^^^^^ comment.line.rem.batchfile 28 | 29 | :: This is a comment 30 | REM <- punctuation.definition.comment.batchfile comment.line.colon.batchfile 31 | REM^^^^^^^^^^^^^^^^^ comment.line.colon.batchfile 32 | 33 | :: Don't join a command inline & DIR 34 | REM <- punctuation.definition.comment.batchfile comment.line.colon.batchfile 35 | REM^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.colon.batchfile 36 | 37 | DIR /A /S somedir &:: Inline comment 38 | REM <- keyword.command.batchfile 39 | REM ^ keyword.operator.conditional.batchfile 40 | REM ^^ punctuation.definition.comment.batchfile 41 | REM ^^^^^^^^^^^^^^^^^ comment.line.colon.batchfile -------------------------------------------------------------------------------- /spec/fixtures/constants.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | ECHO Redirect to 2>NUL 4 | REM^^^^ keyword.command.batchfile 5 | REM ^ constant.numeric.batchfile 6 | REM ^ keyword.operator.redirection.batchfile 7 | REM ^^^ constant.language.batchfile 8 | 9 | ECHO Escaped characters %%, ^^!, ^(, ^&, etc. 10 | REM^^^^ keyword.command.batchfile 11 | REM ^^ ^^^ ^ ^ constant.character.escape.batchfile 12 | REM ^^ ^^ ^^^ ^^^^^^^ source.batchfile 13 | 14 | ECHO Decimal number -8675 +8765 8945 15 | REM ^^^^^ ^^^^^ ^^^^ constant.numeric.batchfile 16 | 17 | ECHO Hexadecimal number 0x0123456789abcdefABCDEF 18 | REM ^^^^^^^^^^^^^^^^^^^^^^^^ constant.numeric.batchfile 19 | 20 | ECHO Numbers 08pre-string 21 | REM ^^ !constant.numeric.batchfile 22 | 23 | ECHO Numbers post-string14 24 | REM ^^ !constant.numeric.batchfile 25 | 26 | ECHO Numbers mid-08-string 27 | REM ^^ !constant.numeric.batchfile 28 | 29 | ECHO Numbers after equals=08 30 | REM ^^ constant.numeric.batchfile -------------------------------------------------------------------------------- /spec/fixtures/controls.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | IF EXIST "file.bat" ( 4 | REM <- keyword.control.conditional.batchfile 5 | REM^^^^^ keyword.other.special-method.batchfile 6 | REM ^^^^^^^^^^ string.quoted.double.batchfile 7 | REM ^ meta.group.batchfile 8 | 9 | GOTO :DOWORK 10 | REM ^^^^ keyword.control.statement.batchfile 11 | 12 | ) ELSE ( 13 | REM <- meta.group.batchfile 14 | REM <- keyword.control.conditional.batchfile 15 | REM ^ meta.group.batchfile 16 | 17 | EXIT 18 | REM <- keyword.control.statement.batchfile 19 | 20 | ) 21 | REM <- meta.group.batchfile 22 | 23 | IF NOT EXIST "file.bat" CALL :GOHOME 24 | REM <- keyword.control.conditional.batchfile 25 | REM^^^ keyword.operator.logical.batchfile 26 | REM ^^^^^ keyword.other.special-method.batchfile 27 | REM ^^^^^^^^^^ string.quoted.double.batchfile 28 | REM ^^^^ keyword.control.statement.batchfile 29 | 30 | IF DEFINED %myvar% GOTO :EOF 31 | REM <- keyword.control.conditional.batchfile 32 | REM^^^^^^^ keyword.other.special-method.batchfile 33 | REM ^^^^^^^ variable.other.readwrite.batchfile 34 | REM ^^^^ keyword.control.statement.batchfile 35 | 36 | IF ERRORLEVEL 1 GOTO :EOF 37 | REM <- keyword.control.conditional.batchfile 38 | REM^^^^^^^^^^ keyword.other.special-method.batchfile 39 | REM ^ constant.numeric.batchfile 40 | REM ^^^^ keyword.control.statement.batchfile 41 | 42 | IF CMDEXTVERSION 2 GOTO :EOF 43 | REM <- keyword.control.conditional.batchfile 44 | REM^^^^^^^^^^^^^ keyword.other.special-method.batchfile 45 | REM ^ constant.numeric.batchfile 46 | REM ^^^^ keyword.control.statement.batchfile 47 | 48 | FOR /F "tokens=1,3 delims=," %%G IN (weather.txt) DO @echo %%G %%H 49 | REM <- keyword.control.repeat.batchfile -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_023.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | @echo off 4 | setlocal 5 | set "flag=" 6 | REM ^^^^^^^ string.quoted.double.batchfile 7 | REM ^^^^ variable.other.readwrite.batchfile 8 | REM ^ keyword.operator.assignment.batchfile 9 | endlocal 10 | 11 | exit /b 0 -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_024.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | copy "50%% done.txt" %K% 4 | REM ^^ constant.character.escape.batchfile 5 | REM ^^^ variable.other.readwrite.batchfile -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_025.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | @echo off 4 | 5 | mkdir bin\DesktopGL\shaders 6 | for /R %%f in (.\shaders\*.fx) do ( 7 | REM ^^ punctuation.definition.variable.batchfile 8 | REM ^^^ variable.parameter.repeat.batchfile 9 | echo %%f 10 | REM ^^ punctuation.definition.variable.batchfile 11 | REM ^^^ variable.parameter.repeat.batchfile 12 | fxc /T fx_2_0 /Fo "bin\DesktopGL\shaders\%%~nf.xnb" "%%f" 13 | REM ^^ ^^ punctuation.definition.variable.batchfile 14 | REM ^^^^^ ^^^ variable.parameter.repeat.batchfile 15 | ) 16 | -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_026.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | REM PART 1 AND 2 4 | 5 | ECHO:Off with his head 6 | REM <- keyword.command.batchfile 7 | REM ^^^^^^^^^^^^^^^^^^ source.batchfile 8 | 9 | @echo:On point 10 | REM <- keyword.operator.at.batchfile 11 | REM <- keyword.command.batchfile 12 | REM ^^^^^^^^^ source.batchfile 13 | 14 | @echo OFF 15 | echo on 16 | REM <- keyword.command.batchfile 17 | REM ^^ keyword.other.special-method.batchfile 18 | 19 | echo hello there 20 | REM <- keyword.command.batchfile 21 | REM ^^^^^^^^^^^ source.batchfile 22 | 23 | REM PART 3 24 | 25 | SET /P "$=Enter choice: " 26 | REM <- keyword.command.batchfile 27 | REM ^^^^^^^^^^^^^^^^^^ string.quoted.double.batchfile 28 | REM ^ variable.other.readwrite.batchfile 29 | REM ^ keyword.operator.assignment.batchfile 30 | 31 | REM PART 4 32 | 33 | IF EXIST myfile.txt GOTO:my_label 34 | REM ^^^^ keyword.control.statement.batchfile 35 | REM ^ punctuation.separator.batchfile 36 | REM ^^^^^^^^ keyword.other.special-method.batchfile 37 | 38 | IF EXIST myfile.txt GOTO :my_label 39 | REM ^^^^ keyword.control.statement.batchfile 40 | REM ^ punctuation.separator.batchfile 41 | REM ^^^^^^^^ keyword.other.special-method.batchfile 42 | 43 | :my_label 44 | REM <- punctuation.separator.batchfile 45 | REM <- keyword.other.special-method.batchfile 46 | 47 | REM PART 5 48 | 49 | cls 50 | REM <- keyword.command.batchfile 51 | 52 | REM PART 10 53 | 54 | setlocal 55 | REM <- keyword.command.batchfile 56 | 57 | SETLOCAL EnableExtensions 58 | REM <- keyword.command.batchfile 59 | REM ^^^^^^^^^^^^^^^^ keyword.other.special-method.batchfile 60 | 61 | SETLOCAL DisableExtensions 62 | REM <- keyword.command.batchfile 63 | REM ^^^^^^^^^^^^^^^^^ keyword.other.special-method.batchfile 64 | 65 | SETLOCAL EnableDelayedExpansion 66 | REM <- keyword.command.batchfile 67 | REM ^^^^^^^^^^^^^^^^^^^^^^ keyword.other.special-method.batchfile 68 | 69 | SETLOCAL DisableDelayedExpansion 70 | REM <- keyword.command.batchfile 71 | REM ^^^^^^^^^^^^^^^^^^^^^^^ keyword.other.special-method.batchfile 72 | 73 | REM PART 11 74 | 75 | SET "PORT_TITLE=Chocolate Doom ^(Setup^)" 76 | REM <- keyword.command.batchfile 77 | REM ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.batchfile 78 | REM ^^^^^^^^^^ variable.other.readwrite.batchfile 79 | REM ^ keyword.operator.assignment.batchfile 80 | REM ^ ^ constant.character.escape.batchfile -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_028.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | SET "i=1" 4 | REM <- keyword.command.batchfile 5 | REM ^^^^^ string.quoted.double.batchfile 6 | REM ^ variable.other.readwrite.batchfile 7 | REM ^ keyword.operator.assignment.batchfile 8 | 9 | SET /a "i=1" 10 | REM <- keyword.command.batchfile 11 | REM ^^^^^^^^ meta.expression.set.batchfile 12 | REM ^ variable.other.readwrite.batchfile 13 | REM ^ keyword.operator.assignment.batchfile 14 | 15 | SET /A "i+=1" 16 | REM <- keyword.command.batchfile 17 | REM ^^^^^^^^ meta.expression.set.batchfile 18 | REM ^ variable.other.readwrite.batchfile 19 | REM ^^ keyword.operator.assignment.augmented.batchfile -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_029.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | IF "%1"=="MONTHLY" GOTO MONTHLY 4 | REM ^^ variable.parameter.batchfile 5 | REM ^ punctuation.definition.variable.batchfile 6 | 7 | net use "%~1" %2 /USER:%3 8 | REM ^^ ^^ ^^ variable.parameter.batchfile 9 | REM ^ ^ ^ punctuation.definition.variable.batchfile 10 | IF NOT EXIST "%~1\%~4" GOTO NOSOURCE 11 | REM ^^^ ^^^ variable.parameter.batchfile 12 | REM ^ ^ punctuation.definition.variable.batchfile 13 | -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_034.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | :: This will work... 4 | set var=val & set var=val 5 | :: This as well... 6 | set "var=val" & set var=val 7 | :: This... will, I guess? 8 | set /a var=val & set var=val 9 | REM ^^^ ^^^ keyword.command.batchfile 10 | REM ^^^^^^^^^^ meta.expression.set.batchfile 11 | REM ^^^ ^^^ variable.other.readwrite.batchfile 12 | REM ^ ^ keyword.operator.assignment.batchfile 13 | REM ^ keyword.operator.conditional.batchfile 14 | :: This won't. 15 | set /a "var=val" & set var=val 16 | :: Aaaand everything's screwed. 17 | set sadness=true 18 | title it's over 19 | echo weep woop 20 | exit /b -42 21 | -------------------------------------------------------------------------------- /spec/fixtures/issues/issue_035.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | :: Inline comment below 4 | :somewhere &:: we're here 5 | REM ^ punctuation.separator.batchfile 6 | REM ^^^^^^^^^ keyword.other.special-method.batchfile 7 | REM ^ keyword.operator.conditional.batchfile 8 | REM ^^^^^^^^^^^^^ comment.line.colon.batchfile 9 | REM ^^ punctuation.definition.comment.batchfile 10 | 11 | :: Another inline comment below 12 | goto :somewhere &:: and close the door when leaving 13 | REM ^^^^ keyword.control.statement.batchfile 14 | REM ^ punctuation.separator.batchfile 15 | REM ^^^^^^^^^ keyword.other.special-method.batchfile 16 | REM ^ keyword.operator.conditional.batchfile 17 | REM ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.colon.batchfile 18 | REM ^^ punctuation.definition.comment.batchfile 19 | 20 | call :somewhere &:: This seems to work correctly, though 21 | REM ^^^^ keyword.control.statement.batchfile 22 | REM ^ punctuation.separator.batchfile 23 | REM ^^^^^^^^^ keyword.other.special-method.batchfile 24 | REM ^ keyword.operator.conditional.batchfile 25 | REM ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.colon.batchfile 26 | REM ^^ punctuation.definition.comment.batchfile 27 | -------------------------------------------------------------------------------- /spec/fixtures/keywords.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | example-copy should not highlight copy 4 | REM ^^^^ !keyword.command.batchfile 5 | 6 | example-echo should not highlight echo 7 | REM ^^^^ !keyword.command.batchfile 8 | 9 | example-set should not highlight set 10 | REM ^^^ !keyword.command.batchfile 11 | 12 | example-rem should not highlight rem 13 | REM ^^^ !keyword.command.rem.batchfile 14 | 15 | example-rem. should not highlight rem 16 | REM ^^^ !keyword.command.rem.batchfile 17 | 18 | @copy should hightlight copy 19 | REM <- keyword.command.batchfile 20 | 21 | @echo should hightlight echo 22 | REM <- keyword.command.batchfile 23 | 24 | @set should highlight set 25 | REM <- keyword.command.batchfile 26 | 27 | @rem should hightlight rem 28 | REM <- keyword.command.rem.batchfile 29 | 30 | @rem.should hightlight rem 31 | REM <- keyword.command.rem.batchfile -------------------------------------------------------------------------------- /spec/fixtures/operators.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | @ECHO off 4 | REM^ keyword.operator.at.batchfile 5 | 6 | EQU NEQ LSS LEQ GTR GEQ == 7 | REM^^^ ^^^ ^^^ ^^^ ^^^ ^^^ ^^ keyword.operator.comparison.batchfile 8 | 9 | NOT 10 | REM^^^ keyword.operator.logical.batchfile 11 | 12 | & && || 13 | REM^ ^^ ^^ keyword.operator.conditional.batchfile 14 | 15 | | 16 | REM^ keyword.operator.pipe.batchfile 17 | 18 | < <& > >& >> 19 | REM^ ^^ ^ ^^ ^^ keyword.operator.redirection.batchfile -------------------------------------------------------------------------------- /spec/fixtures/strings.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | SETLOCAL EnableDelayedExpansion 4 | SET var=value 5 | 6 | ECHO "So these carets ^ should stand for itself and not escape anything:" 7 | ECHO " ^( ^) ^%% ^. ^# Double caret: ^^ ^" 8 | REM ^ punctuation.definition.string.begin.batchfile 9 | REM ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ string.quoted.double.batchfile 10 | REM ^ punctuation.definition.string.end.batchfile 11 | 12 | ECHO "But with exclamation marks, carets within quoted strings escape:" 13 | ECHO "!var! ^^( ^^) ^^%% ^^. ^^# Double caret: ^^^^ ^^" 14 | 15 | ECHO "Even with just escaped exclamation marks:" 16 | ECHO "^^! ^^( ^^) ^^%% ^^. ^^# Double caret: ^^^^ ^^" 17 | 18 | ECHO If unquoted, to produce string similar to above would require this: 19 | ECHO ^"^^! ^^^^( ^^^^) ^^^^%% ^^^^. ^^^^# Double caret: ^^^^^^^^ ^^^^^" 20 | ECHO ^"^^( ^^) ^^%% ^^. ^^# Double caret: ^^^^ ^^^" 21 | 22 | SETLOCAL DisableDelayedExpansion 23 | 24 | ECHO "! ^( ^) ^%% ^. ^# Double caret: ^^ ^" 25 | ECHO ^"! ^^( ^^) ^^%% ^^. ^^# Double caret: ^^^^ ^^^" 26 | ECHO "^^! ^^( ^^) ^^%% ^^. ^^# Double caret: ^^^^ ^^" -------------------------------------------------------------------------------- /spec/fixtures/variables.bat: -------------------------------------------------------------------------------- 1 | REM SYNTAX TEST "source.batchfile" 2 | 3 | %foo% 4 | REM ^^^^^ variable.other.readwrite.batchfile 5 | REM ^ punctuation.definition.variable.begin.batchfile 6 | REM ^ punctuation.definition.variable.end.batchfile 7 | 8 | !foo! 9 | REM ^^^^^ variable.other.readwrite.batchfile 10 | REM ^ punctuation.definition.variable.begin.batchfile 11 | REM ^ punctuation.definition.variable.end.batchfile 12 | 13 | %foo:^"= % 14 | REM ^^^^^^^^^ variable.other.readwrite.batchfile 15 | REM ^ punctuation.definition.variable.begin.batchfile 16 | REM ^^^^ meta.variable.substitution.batchfile 17 | REM ^ ^ punctuation.separator.batchfile 18 | REM ^^ ^ string.unquoted.batchfile 19 | REM ^ punctuation.definition.variable.end.batchfile 20 | 21 | !foo:^"= ! 22 | REM ^^^^^^^^^ variable.other.readwrite.batchfile 23 | REM ^ punctuation.definition.variable.begin.batchfile 24 | REM ^^^^ meta.variable.substitution.batchfile 25 | REM ^ ^ punctuation.separator.batchfile 26 | REM ^ constant.character.escape.batchfile 27 | REM ^ ^ string.unquoted.batchfile 28 | REM ^ punctuation.definition.variable.end.batchfile 29 | 30 | %PATH:~10,5% 31 | REM ^^^^^^^^^^^^ variable.other.readwrite.batchfile 32 | REM ^ punctuation.definition.variable.begin.batchfile 33 | REM ^^^^^^ meta.variable.substring.batchfile 34 | REM ^^ punctuation.separator.batchfile 35 | REM ^^ ^ constant.numeric.batchfile 36 | REM ^ punctuation.definition.variable.end.batchfile 37 | 38 | !PATH:~10,5! 39 | REM ^^^^^^^^^^^^ variable.other.readwrite.batchfile 40 | REM ^ punctuation.definition.variable.begin.batchfile 41 | REM ^^^^^^ meta.variable.substring.batchfile 42 | REM ^^ punctuation.separator.batchfile 43 | REM ^^ ^ constant.numeric.batchfile 44 | REM ^ punctuation.definition.variable.end.batchfile 45 | 46 | %PATH:~-5% 47 | REM ^^^^^^^^^^ variable.other.readwrite.batchfile 48 | REM ^ punctuation.definition.variable.begin.batchfile 49 | REM ^^^^ meta.variable.substring.batchfile 50 | REM ^^ punctuation.separator.batchfile 51 | REM ^^ constant.numeric.batchfile 52 | REM ^ punctuation.definition.variable.end.batchfile 53 | 54 | !PATH:~-5! 55 | REM ^^^^^^^^^^ variable.other.readwrite.batchfile 56 | REM ^ punctuation.definition.variable.begin.batchfile 57 | REM ^^^^ meta.variable.substring.batchfile 58 | REM ^^ punctuation.separator.batchfile 59 | REM ^^ constant.numeric.batchfile 60 | REM ^ punctuation.definition.variable.end.batchfile -------------------------------------------------------------------------------- /spec/grammar-spec.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | grammarTest = require 'atom-grammar-test' 3 | 4 | describe "Grammar", -> 5 | beforeEach -> 6 | waitsForPromise -> 7 | atom.packages.activatePackage 'language-batchfile' 8 | 9 | # Key scopes 10 | grammarTest path.join(__dirname, 'fixtures/comments.bat') 11 | grammarTest path.join(__dirname, 'fixtures/constants.bat') 12 | grammarTest path.join(__dirname, 'fixtures/controls.bat') 13 | grammarTest path.join(__dirname, 'fixtures/keywords.bat') 14 | grammarTest path.join(__dirname, 'fixtures/operators.bat') 15 | grammarTest path.join(__dirname, 'fixtures/strings.bat') 16 | grammarTest path.join(__dirname, 'fixtures/variables.bat') 17 | 18 | # Regression tests 19 | grammarTest path.join(__dirname, 'fixtures/issues/issue_023.bat') 20 | grammarTest path.join(__dirname, 'fixtures/issues/issue_024.bat') 21 | grammarTest path.join(__dirname, 'fixtures/issues/issue_025.bat') 22 | grammarTest path.join(__dirname, 'fixtures/issues/issue_026.bat') 23 | grammarTest path.join(__dirname, 'fixtures/issues/issue_028.bat') 24 | grammarTest path.join(__dirname, 'fixtures/issues/issue_029.bat') 25 | grammarTest path.join(__dirname, 'fixtures/issues/issue_034.bat') 26 | grammarTest path.join(__dirname, 'fixtures/issues/issue_035.bat') 27 | --------------------------------------------------------------------------------