├── icon.png
├── .gitignore
├── imgs
└── preview.png
├── tests
├── comprehensive
│ ├── no_newline.mcfunction
│ ├── uuid.mcfunction
│ ├── parsers
│ │ ├── message
│ │ │ ├── invalid.mcfunction
│ │ │ └── valid.mcfunction
│ │ ├── entity_anchor
│ │ │ ├── valid.mcfunction
│ │ │ └── invalid.mcfunction
│ │ ├── swizzle
│ │ │ ├── invalid.mcfunction
│ │ │ └── valid.mcfunction
│ │ ├── block_position.mcfunction
│ │ ├── dimension
│ │ │ ├── invalid.mcfunction
│ │ │ └── valid.mcfunction
│ │ ├── int_range
│ │ │ ├── invalid.mcfunction
│ │ │ └── valid.mcfunction
│ │ ├── rotation
│ │ │ ├── invalid.mcfunction
│ │ │ └── valid.mcfunction
│ │ ├── block_position
│ │ │ ├── valid.mcfunction
│ │ │ └── invalid.mcfunction
│ │ └── position
│ │ │ ├── invalid.mcfunction
│ │ │ └── valid.mcfunction
│ ├── root_redirect.mcfunction
│ ├── README.md
│ ├── json.mcfunction
│ ├── nbt_list.mcfunction
│ ├── greedy_commands.mcfunction
│ ├── fakeplayer.mcfunction
│ ├── misc.mcfunction
│ ├── number.mcfunction
│ ├── operation.mcfunction
│ ├── commands.mcfunction
│ ├── block_predicate.mcfunction
│ ├── strings.mcfunction
│ ├── nbt_compound.mcfunction
│ ├── resource_location.mcfunction
│ ├── nbt_path
│ │ ├── valid.mcfunction
│ │ └── invalid.mcfunction
│ ├── range.mcfunction
│ ├── showcase.mcfunction
│ ├── comments.mcfunction
│ ├── commands
│ │ └── effect.mcfunction
│ ├── target_selectors
│ │ ├── invalid.mcfunction
│ │ └── valid.mcfunction
│ ├── text_components
│ │ ├── invalid.mcfunction
│ │ └── valid.mcfunction
│ ├── everything.mcfunction
│ └── selector.mcfunction
├── jmc.mcfunction
├── macros.mcfunction
├── mcbuild.mcfunction
├── demo.mcfunction
├── vanilla.mcfunction
└── bolt.mcfunction
├── .vscode
└── launch.json
├── mcfunction.tmPreferences
├── language-configuration.json
├── LICENSE
├── package.json
├── .github
├── ISSUE_TEMPLATE
│ ├── feature-request.yaml
│ └── bug-report.yaml
└── workflows
│ └── publish.yml
├── CHANGELOG.md
├── README.md
├── mcfunction.tmLanguage.yaml
├── mcfunction.tmLanguage.json
└── mcfunction.tmLanguage
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinecraftCommands/syntax-mcfunction/HEAD/icon.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | node_modules/
4 | *.vsix
5 |
6 | .vscode/*
7 | !.vscode/launch.json
8 |
--------------------------------------------------------------------------------
/imgs/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MinecraftCommands/syntax-mcfunction/HEAD/imgs/preview.png
--------------------------------------------------------------------------------
/tests/comprehensive/no_newline.mcfunction:
--------------------------------------------------------------------------------
1 | # no newline at the end of this file
2 | function my.pack:my/folder/hello_world
--------------------------------------------------------------------------------
/tests/comprehensive/uuid.mcfunction:
--------------------------------------------------------------------------------
1 | execute as f7a39418-72ca-4bf2-bc7e-ba9df67a4707 run
2 | execute as 0-0-0-0-0 run
3 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/message/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | say hello@e[world
2 | say hello@e[sort]world
3 | say hello@e[sort=]world
4 |
--------------------------------------------------------------------------------
/tests/comprehensive/root_redirect.mcfunction:
--------------------------------------------------------------------------------
1 | execute as @a run
2 | execute as @a run say hello
3 | execute as running_player say hello
4 |
--------------------------------------------------------------------------------
/tests/comprehensive/README.md:
--------------------------------------------------------------------------------
1 | # Comprehensive Test Suite
2 | > *Originally from [language-mcfunction](https://github.com/Arcensoth/language-mcfunction/tree/main/tests)
3 |
--------------------------------------------------------------------------------
/tests/comprehensive/json.mcfunction:
--------------------------------------------------------------------------------
1 | tellraw @a {"text": "hello world", "color": "blue"}
2 | tellraw @a [{"text": "hello", "color": "blue"}, {"text": "world", "color": "blue"}]
3 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/message/valid.mcfunction:
--------------------------------------------------------------------------------
1 | say hello
2 | say hello world
3 | say hello @e world
4 | say hello@eworld
5 | say hello@e[tag=foo]world
6 | say @@e[tag=x,tag=!x]e
7 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/entity_anchor/valid.mcfunction:
--------------------------------------------------------------------------------
1 | execute anchored eyes run say hello
2 | execute anchored feet run say hello
3 |
4 | execute anchored eyes anchored feet run say hello
5 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/swizzle/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # non-executable
2 | execute align y
3 | execute align xz
4 | execute align xyz
5 |
6 | # not real axes
7 | execute align a run say hello
8 | execute align abc run say hello
9 |
--------------------------------------------------------------------------------
/tests/comprehensive/nbt_list.mcfunction:
--------------------------------------------------------------------------------
1 | # test array types
2 | give @s minecraft:stone{foo: [B; 123b, 123b]}
3 | give @s minecraft:stone{foo: [I; 123, 456]}
4 | give @s minecraft:stone{foo: [L; 123L, 456L]}
5 | give @s minecraft:stone{foo: [foo; 123L, 456L]}
6 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/entity_anchor/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # non-executable
2 | execute anchored eyes
3 | execute anchored feet
4 |
5 | # not real anchors
6 | execute anchored foo run say hello
7 | execute anchored bar run say hello
8 | execute anchored eyes anchored nose run say hello
9 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/swizzle/valid.mcfunction:
--------------------------------------------------------------------------------
1 | execute align x run say hello
2 | execute align y run say hello
3 | execute align z run say hello
4 | execute align xy run say hello
5 | execute align xz run say hello
6 | execute align yz run say hello
7 | execute align xyz run say hello
8 |
9 | execute align x align y align z run say hello
10 |
--------------------------------------------------------------------------------
/tests/comprehensive/greedy_commands.mcfunction:
--------------------------------------------------------------------------------
1 | say hello [world] how are.you @s today?
2 | execute as @a run say hello [world] how are.you @s today?
3 | execute as uh_oh_say at @s run say hello [world] how are.you @s today?
4 | execute as say_uh_oh at @s run say hello [world] how are.you @s today?
5 | say hi hello whats up my friend \
6 | this is still apart of the say command
7 | # but not this
8 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/block_position.mcfunction:
--------------------------------------------------------------------------------
1 | execute if blocks 0 0 0 1 2 3 -1 -2 -3 all run say hi
2 | execute if blocks ~1 ~2 ~3 ~-1 ~-2 ~-3 ~0 ~0 ~0 all run say hi
3 | execute if blocks ^1 ^2 ^3 ^-1 ^-2 ^-3 ^0 ^0 ^0 all run say hi
4 |
5 | # invalid, mixed coords
6 | execute if blocks 1 ^2 ^3 ^-1 ^-2 ^-3 ^0 ^0 ^0 all run say hi
7 | execute if blocks ~1 ^2 ^3 ^-1 ^-2 ^-3 ^0 ^0 ^0 all run say hi
8 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/dimension/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # non-executable
2 | execute in minecraft:overworld
3 | execute in minecraft:the_nether
4 | execute in minecraft:the_end
5 |
6 | # bad resource location
7 | execute in :overworld run say hello
8 | execute in minecraft: run say hello
9 | execute in : run say hello
10 |
11 | # no slashes
12 | execute in over/world run say hello
13 | execute in minecraft:over/world run say hello
14 |
--------------------------------------------------------------------------------
/tests/comprehensive/fakeplayer.mcfunction:
--------------------------------------------------------------------------------
1 | scoreboard notfake
2 | scoreboard not_fake
3 | scoreboard unquoted.string
4 | scoreboard #fakeplayer
5 | scoreboard #fake.player
6 | scoreboard #fake_player
7 | scoreboard $fakeplayer
8 | scoreboard %fakeplayer
9 | scoreboard .fakeplayer
10 | scoreboard "quoted string"
11 |
12 | # cursed blame SnaveSutit
13 | scoreboard #fakeplayer-1y-1z-
14 | scoreboard #-200
15 | scoreboard %fakeplayer-1.20%%
16 | scoreboard .-30
17 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/int_range/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # just ellipsis
2 | execute if score @s foo matches .. run say hello
3 |
4 | # decimals
5 | execute if score @s foo matches 0.5 run say hello
6 | execute if score @s foo matches 0.5.. run say hello
7 | execute if score @s foo matches ..0.5 run say hello
8 | execute if score @s foo matches -0.5..0.5 run say hello
9 |
10 | # technically invalid, but hard to detect with regex
11 | execute if score @s foo matches 1..-1 run say hello
12 |
--------------------------------------------------------------------------------
/tests/comprehensive/misc.mcfunction:
--------------------------------------------------------------------------------
1 | # root redirect
2 | execute as @a at @s run
3 | execute as @a at @s run
4 | execute as @a at @s run say
5 | execute as @a at @s run say hello
6 |
7 | # booleans
8 | effect give @s minecraft:night_vision 999999 1 true
9 | effect give @s minecraft:night_vision 999999 1 false
10 |
11 | # crazy whitespace
12 | execute
13 | execute
14 | execute
15 | execute
16 | execute
17 | execute
18 |
19 | # non-literal characters
20 | execute.
21 | execute_
22 | execute-
23 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/dimension/valid.mcfunction:
--------------------------------------------------------------------------------
1 | # without namespace
2 | execute in overworld run say hello
3 | execute in the_nether run say hello
4 | execute in the_end run say hello
5 |
6 | # with namespace
7 | execute in minecraft:overworld run say hello
8 | execute in minecraft:the_nether run say hello
9 | execute in minecraft:the_end run say hello
10 |
11 | # nested
12 | execute in minecraft:overworld in minecraft:the_nether run say hello
13 |
14 | # custom dimension
15 | execute in minecraft:the_aether run say hello
16 |
--------------------------------------------------------------------------------
/tests/jmc.mcfunction:
--------------------------------------------------------------------------------
1 | class folder_one.folder_two
2 | {
3 | function folder_three.function_name() {
4 | say "Code example 1";
5 | say "Code example 2";
6 | }
7 | new file_type(folder_name.json_file_name) { // See JSON Files page for this feature
8 | JSON_CONTENT
9 | }
10 | }
11 |
12 | folder_one.folder_two.folder_three.function_name();
13 |
14 | if ($deathCount>5 ) {
15 | say "More than 5 death!";
16 | } else if ($deathCount matches 2..3 ) {
17 | say "Between 2 to 3 death!";
18 | } else if ($deathCount) {
19 | say "At least 1 death";
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that launches the extension inside a new window
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | {
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "name": "Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "args": [
13 | "--extensionDevelopmentPath=${workspaceFolder}"
14 | ]
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/int_range/valid.mcfunction:
--------------------------------------------------------------------------------
1 | # exact numbers
2 | execute if score @s foo matches -1 run say hello
3 | execute if score @s foo matches 0 run say hello
4 | execute if score @s foo matches 1 run say hello
5 |
6 | # minimum
7 | execute if score @s foo matches 1.. run say hello
8 | execute if score @s foo matches 0.. run say hello
9 | execute if score @s foo matches -1.. run say hello
10 |
11 | # maximum
12 | execute if score @s foo matches ..1 run say hello
13 | execute if score @s foo matches ..0 run say hello
14 | execute if score @s foo matches ..-1 run say hello
15 |
16 | # min and max
17 | execute if score @s foo matches -1..1 run say hello
18 |
--------------------------------------------------------------------------------
/mcfunction.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | mcfunction
7 | scope
8 | source.mcfunction
9 | settings
10 |
11 | shellVariables
12 |
13 |
14 | name
15 | TM_COMMENT_START
16 | value
17 | #
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/comprehensive/number.mcfunction:
--------------------------------------------------------------------------------
1 | # test valid number
2 | execute if score @a temp matches 1 run
3 | say 123
4 | say 1.0
5 | say 0.1
6 | say 123.456
7 | say .1
8 | say .789
9 |
10 | # test valid number in selectors
11 | execute as @a[distance=1] run
12 | execute as @a[distance=123] run
13 | execute as @a[distance=1.0] run
14 | execute as @a[distance=0.1] run
15 | execute as @a[distance=123.456] run
16 | execute as @a[distance=.1] run
17 | execute as @a[distance=.789] run
18 |
19 | # test valid negative numbers
20 | execute if score @a temp matches -1 run
21 |
22 | # test invalid number
23 | say .
24 | say 1.
25 |
26 | # test invalid number in selectors
27 | execute as @a[distance=.] run
28 | execute as @a[distance=1.] run
29 |
--------------------------------------------------------------------------------
/tests/comprehensive/operation.mcfunction:
--------------------------------------------------------------------------------
1 | # test scoreboard players operation
2 | scoreboard players operation @s foo %= @s bar
3 | scoreboard players operation @s foo *= @s bar
4 | scoreboard players operation @s foo += @s bar
5 | scoreboard players operation @s foo -= @s bar
6 | scoreboard players operation @s foo /= @s bar
7 | scoreboard players operation @s foo < @s bar
8 | scoreboard players operation @s foo = @s bar
9 | scoreboard players operation @s foo > @s bar
10 | scoreboard players operation @s foo >< @s bar
11 |
12 | # test execute if score
13 | execute if score @s foo < @s bar run
14 | execute if score @s foo <= @s bar run
15 | execute if score @s foo = @s bar run
16 | execute if score @s foo > @s bar run
17 | execute if score @s foo >= @s bar run
18 |
--------------------------------------------------------------------------------
/language-configuration.json:
--------------------------------------------------------------------------------
1 | {
2 | "comments": {
3 | // symbol used for single line comment. Remove this entry if your language does not support line comments
4 | "lineComment": "#",
5 | },
6 | // symbols used as brackets
7 | "brackets": [
8 | ["{", "}"],
9 | ["[", "]"],
10 | ["(", ")"]
11 | ],
12 | // symbols that are auto closed when typing
13 | "autoClosingPairs": [
14 | ["{", "}"],
15 | ["[", "]"],
16 | ["(", ")"],
17 | ["\"", "\""],
18 | ["'", "'"]
19 | ],
20 | // symbols that can be used to surround a selection
21 | "surroundingPairs": [
22 | ["{", "}"],
23 | ["[", "]"],
24 | ["(", ")"],
25 | ["\"", "\""],
26 | ["'", "'"]
27 | ]
28 | }
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/rotation/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # bad decimals with absolutes
2 | execute rotated 10 . run say hello
3 | execute rotated 10 5. run say hello
4 | execute rotated 10 - run say hello
5 | execute rotated 10 -. run say hello
6 | execute rotated 10 -5. run say hello
7 |
8 | # bad decimals with relatives
9 | execute rotated ~10 ~. run say hello
10 | execute rotated ~10 ~5. run say hello
11 | execute rotated ~10 ~- run say hello
12 | execute rotated ~10 ~-. run say hello
13 | execute rotated ~10 ~-5. run say hello
14 |
15 | # can't use locals with rotation
16 | execute rotated ^10 ^ run say hello
17 | execute rotated ^10 ^10 run say hello
18 | execute rotated ^10 ^0.5 run say hello
19 | execute rotated ^10 ^.5 run say hello
20 | execute rotated ^10 ^-10 run say hello
21 | execute rotated ^10 ^-0.5 run say hello
22 | execute rotated ^10 ^-.5 run say hello
23 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/block_position/valid.mcfunction:
--------------------------------------------------------------------------------
1 | # all absolutes
2 | execute if block 10 0 -10 minecraft:stone run say hello
3 | execute if block 10 10 -10 minecraft:stone run say hello
4 | execute if block 10 -10 -10 minecraft:stone run say hello
5 |
6 | # absolutes mixed with relatives
7 | execute if block 10 ~ -10 minecraft:stone run say hello
8 | execute if block 10 ~10 -10 minecraft:stone run say hello
9 | execute if block 10 ~-10 -10 minecraft:stone run say hello
10 |
11 | # all relatives
12 | execute if block ~10 ~ ~-10 minecraft:stone run say hello
13 | execute if block ~10 ~10 ~-10 minecraft:stone run say hello
14 | execute if block ~10 ~-10 ~-10 minecraft:stone run say hello
15 |
16 | # all locals (can't be mixed)
17 | execute if block ^10 ^ ^-10 minecraft:stone run say hello
18 | execute if block ^10 ^10 ^-10 minecraft:stone run say hello
19 | execute if block ^10 ^-10 ^-10 minecraft:stone run say hello
20 |
--------------------------------------------------------------------------------
/tests/macros.mcfunction:
--------------------------------------------------------------------------------
1 | #> Borrowed from slicedlime
2 | # src: https://github.com/slicedlime/examples/
3 |
4 | scoreboard players operation @a result \
5 | += @e[type=marker,limit=1,tag=source] value
6 |
7 | # Run the command in $(command) (eval)
8 | $$(command)
9 |
10 | # Concatenate $(string1) and $(string2), save that to $(path) in storage $(id)
11 | $data modify storage $(id) $(path) set value "with random $(string1) stuff $(string2)"
12 |
13 | # Set the time to $(time)
14 | $time set $(time)
15 |
16 | # this doesn't look perfect, but i can't really fix it
17 | $data modify \
18 | storage $(id) $(path) set \
19 | value "$(string1)$(string2)"
20 |
21 | $data modify
22 | storage $(id) $(path) set
23 | value "$(string1)$(string2)"
24 |
25 | random value 2..45
26 |
27 | scoreboard players set #me not_comment 3 # hello world
28 | give @a #all_diamonds
29 |
30 | execute summon marker run mud:register {command: "function a:target", setup: ""}
31 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/rotation/valid.mcfunction:
--------------------------------------------------------------------------------
1 | # all absolutes
2 | execute rotated 10 0 run say hello
3 | execute rotated 10 10 run say hello
4 | execute rotated 10 0.5 run say hello
5 | execute rotated 10 .5 run say hello
6 | execute rotated 10 -10 run say hello
7 | execute rotated 10 -0.5 run say hello
8 | execute rotated 10 -.5 run say hello
9 |
10 | # absolutes mixed with relatives
11 | execute rotated 10 ~ run say hello
12 | execute rotated 10 ~10 run say hello
13 | execute rotated 10 ~0.5 run say hello
14 | execute rotated 10 ~.5 run say hello
15 | execute rotated 10 ~-10 run say hello
16 | execute rotated 10 ~-0.5 run say hello
17 | execute rotated 10 ~-.5 run say hello
18 |
19 | # all relatives
20 | execute rotated ~10 ~ run say hello
21 | execute rotated ~10 ~10 run say hello
22 | execute rotated ~10 ~0.5 run say hello
23 | execute rotated ~10 ~.5 run say hello
24 | execute rotated ~10 ~-10 run say hello
25 | execute rotated ~10 ~-0.5 run say hello
26 | execute rotated ~10 ~-.5 run say hello
27 |
--------------------------------------------------------------------------------
/tests/mcbuild.mcfunction:
--------------------------------------------------------------------------------
1 | dir a {
2 | function test {
3 |
4 | }
5 |
6 | function target {
7 | scoreboard players set #x v 1
8 | }
9 |
10 | function setup {
11 | data merge storage a:test {}
12 | LOOP(1000,i){
13 | execute summon marker run mud:register {command:"function tests:a/target",setup:""}
14 | summon marker 0 0 0 {Tags:["a.i"]}
15 | }
16 | }
17 |
18 | function cleanup {
19 | data remove storage a:test {}
20 | kill @e[type=marker]
21 | }
22 | }
23 |
24 | dir b {
25 |
26 | function test {
27 | execute @e[tag=b.test] run function tests:b/target
28 | }
29 |
30 | function target {
31 | scoreboard players set #x v 1
32 | }
33 |
34 | function setup {
35 | LOOP(1000,i) {
36 | summon marker 0 0 0 {Tags:["b.test"]}
37 | summon marker 0 0 0 {Tags:["b.i"]}
38 | }
39 | }
40 |
41 | function cleanup {
42 | data remove storage b:test {}
43 | kill @e[type=marker]
44 | }
45 | }
--------------------------------------------------------------------------------
/tests/comprehensive/commands.mcfunction:
--------------------------------------------------------------------------------
1 | execute
2 | execute foo
3 | execute as
4 | execute as foo
5 | execute as @s
6 | execute as @s foo
7 | execute as @s execute
8 | execute as @s execute as
9 | execute as @s execute as @s
10 | execute as @s as
11 | execute as @s as foo
12 | execute as @s as @s
13 | execute run
14 | execute run foo
15 | execute run execute
16 | execute run execute foo
17 | execute run execute run
18 | execute as @s run
19 | execute as @s run foo
20 | execute as @s run as
21 | execute as @s run as @s
22 | execute as @s run execute
23 | execute as @s run execute foo
24 | execute as @s run execute as @s run
25 |
26 | advancement
27 | advancement foo
28 | advancement grant
29 | advancement grant foo
30 | advancement grant targets
31 | advancement grant targets foo
32 | advancement grant targets everything
33 |
34 | execute as targets
35 | execute as targets
36 | execute as targets run
37 | execute as targets run
38 | execute as targets run execute
39 | execute as targets run execute
40 | execute as targets run execute as
41 | execute as targets run execute as
42 | execute as targets run execute as targets
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023-2023 MinecraftCommands
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "syntax-mcfunction",
3 | "publisher": "MinecraftCommands",
4 | "displayName": "syntax-mcfunction",
5 | "description": "Syntax highlighting for mcfunction files (Last Updated: 1.21)",
6 | "icon": "icon.png",
7 | "author": "MinecraftCommands",
8 | "version": "1.0.1",
9 | "license": "MIT",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/MinecraftCommands/syntax-mcfunction"
13 | },
14 | "engines": {
15 | "vscode": "^1.81.0"
16 | },
17 | "categories": [
18 | "Programming Languages"
19 | ],
20 | "contributes": {
21 | "languages": [
22 | {
23 | "id": "mcfunction",
24 | "aliases": [
25 | "mcfunction",
26 | "mcf",
27 | "MCF"
28 | ],
29 | "extensions": [
30 | ".mcfunction"
31 | ],
32 | "configuration": "./language-configuration.json"
33 | }
34 | ],
35 | "grammars": [
36 | {
37 | "language": "mcfunction",
38 | "scopeName": "source.mcfunction",
39 | "path": "./mcfunction.tmLanguage.json"
40 | }
41 | ]
42 | },
43 | "devDependencies": {
44 | "js-yaml": "^4.1.0"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/position/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # bad decimals with absolutes
2 | execute positioned 10 . -10 run say hello
3 | execute positioned 10 5. -10 run say hello
4 | execute positioned 10 - -10 run say hello
5 | execute positioned 10 -. -10 run say hello
6 | execute positioned 10 -5. -10 run say hello
7 |
8 | # bad decimals with relatives
9 | execute positioned ~10 ~. ~-10 run say hello
10 | execute positioned ~10 ~5. ~-10 run say hello
11 | execute positioned ~10 ~- ~-10 run say hello
12 | execute positioned ~10 ~-. ~-10 run say hello
13 | execute positioned ~10 ~-5. ~-10 run say hello
14 |
15 | # bad decimals with locals
16 | execute positioned ^10 ^. ^-10 run say hello
17 | execute positioned ^10 ^5. ^-10 run say hello
18 | execute positioned ^10 ^- ^-10 run say hello
19 | execute positioned ^10 ^-. ^-10 run say hello
20 | execute positioned ^10 ^-5. ^-10 run say hello
21 |
22 | # bad mixed locals
23 | execute positioned 1 2 ^3 run say hello
24 | execute positioned 1 ^2 3 run say hello
25 | execute positioned ^1 2 3 run say hello
26 | execute positioned ~1 ~2 ^3 run say hello
27 | execute positioned ~1 ^2 ~3 run say hello
28 | execute positioned ^1 ~2 ~3 run say hello
29 |
30 | # not a real operator
31 | execute positioned %1 %2 %3 run say hello
32 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/block_position/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # bad decimals with absolutes
2 | execute if block 10 0.5 -10 minecraft:stone run say hello
3 | execute if block 10 .5 -10 minecraft:stone run say hello
4 | execute if block 10 -0.5 -10 minecraft:stone run say hello
5 | execute if block 10 -.5 -10 minecraft:stone run say hello
6 |
7 | # bad decimals with relatives
8 | execute if block ~10 ~0.5 ~-10 minecraft:stone run say hello
9 | execute if block ~10 ~.5 ~-10 minecraft:stone run say hello
10 | execute if block ~10 ~-0.5 ~-10 minecraft:stone run say hello
11 | execute if block ~10 ~-.5 ~-10 minecraft:stone run say hello
12 |
13 | # bad decimals with locals
14 | execute if block ^10 ^0.5 ^-10 minecraft:stone run say hello
15 | execute if block ^10 ^.5 ^-10 minecraft:stone run say hello
16 | execute if block ^10 ^-0.5 ^-10 minecraft:stone run say hello
17 | execute if block ^10 ^-.5 ^-10 minecraft:stone run say hello
18 |
19 | # bad mixed locals
20 | execute if block 1 2 ^3 minecraft:stone run say hello
21 | execute if block 1 ^2 3 minecraft:stone run say hello
22 | execute if block ^1 2 3 minecraft:stone run say hello
23 | execute if block ~1 ~2 ^3 minecraft:stone run say hello
24 | execute if block ~1 ^2 ~3 minecraft:stone run say hello
25 | execute if block ^1 ~2 ~3 minecraft:stone run say hello
26 |
27 | # not a real operator
28 | execute if block %1 %2 %3 minecraft:stone run say hello
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yaml:
--------------------------------------------------------------------------------
1 | name: "💡 Feature Request"
2 | description: Create a ticket for a new feature request
3 | title: "Request: "
4 | labels: ["feature-request"]
5 |
6 | body:
7 | - type: textarea
8 | id: summary
9 | attributes:
10 | label: "Summary"
11 | description: Provide a brief explanation of your feature request
12 | placeholder: Describe in a few lines your feature request
13 | validations:
14 | required: true
15 |
16 | - type: textarea
17 | id: basic_example
18 | attributes:
19 | label: "Basic Example"
20 | description: Indicate here some basic examples of your feature.
21 | placeholder: A few specific words about your feature request.
22 | validations:
23 | required: true
24 |
25 | - type: dropdown
26 | id: platform
27 | attributes:
28 | label: Is this specific to a text editor?
29 | multiple: true
30 | options:
31 | - VSCode
32 | - Sublime Text
33 | - Other (please specify above)
34 | validations:
35 | required: false
36 |
37 | - type: textarea
38 | id: other-info
39 | attributes:
40 | label: "Other Info"
41 | description: Any drawbacks or other details of your feature request?
42 | placeholder: Other thoughts you think might be **Important**
43 | render: bash
44 | validations:
45 | required: false
46 |
--------------------------------------------------------------------------------
/tests/comprehensive/block_predicate.mcfunction:
--------------------------------------------------------------------------------
1 | # test argument types
2 | execute if block ~ ~ ~ minecraft:oak_log[axis=x] run
3 | execute if block ~ ~ ~ minecraft:oak_leaves[distance=5] run
4 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent=true] run
5 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent=false] run
6 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent = false] run
7 |
8 | # test multiple arguments
9 | execute if block ~ ~ ~ minecraft:oak_leaves[distance=5,persistent=true] run
10 |
11 | # test tagged variant
12 | execute if block ~ ~ ~ #minecraft:leaves[distance=5] run
13 | execute if block ~ ~ ~ #minecraft:leaves[distance=5,persistent=true] run
14 | execute if block ~ ~ ~ #minecraft:leaves[distance=5, persistent=true] run
15 |
16 | # test with nbt
17 | setblock ~ ~ ~ mypack:foo{foo:bar} destroy
18 | setblock ~ ~ ~ mypack:foo{foo: bar} destroy
19 | setblock ~ ~ ~ mypack:foo[facing=up]{foo: bar} destroy
20 | setblock ~ ~ ~ mypack:foo[facing = up]{foo: bar} destroy
21 |
22 | # test without namespace
23 | setblock ~ ~ ~ foo{foo:bar} destroy
24 | setblock ~ ~ ~ foo[facing=up]{foo: bar} destroy
25 | setblock ~ ~ ~ foo[facing=up] destroy
26 | setblock ~ ~ ~ foo[ facing = up ]{foo: bar} destroy
27 | setblock ~ ~ ~ foo[ facing = up ]{foo: bar} destroy
28 |
29 | # invalid
30 | setblock ~ ~ ~ mypack:foo[facing = up]foo destroy
31 | setblock ~ ~ ~ mypack:foo[facing = up]{foo: bar}foo destroy
32 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v0.6.0
4 |
5 | - Added `##` as a valid block starter
6 | - Fixed comments ordering so that both inline AND commented commands work
7 |
8 | ## v0.5.0
9 |
10 | - Literals with suffixes (b, B, l, L) now highlight properly
11 | - Literals inside properties (specifically `true`/`false`) highlight better
12 | - Resource Names within properties highlight better
13 | - This causes false-positives via `minecraft:block{key:value}` to highlight incorrectly
14 | - Added `-`, `.` as a valid special fakeplayer character
15 | - These characters will only highlight within valid fakeplayer starting characters (`#%$.`)
16 | - Adjusted some scope names to match `language-mcfunction` better
17 | - Fixed sublime support (hopefully)
18 | - Improved some testing
19 |
20 | ## v0.4.x
21 |
22 | - Fiddling around w/ VSCode Publishing
23 |
24 | ## v0.3.1
25 |
26 | - Update name to `syntax-mcfunction`
27 | - Move to `MinecraftCommands` organization
28 |
29 | ## v0.3.0
30 |
31 | - Added support for Sublime Text
32 | - Reverted commenting changes from last release
33 | - This caused issues when you commented out normal code
34 | - Slightly restructured GA + some naming
35 |
36 | ## v0.2.0
37 |
38 | Refactor and additions to qualify for a `mcfunction` language
39 |
40 | - Added explicit macro support
41 | - Loosened restrictions on special commenting
42 | - Fixed various bugs
43 |
44 | ## v0.1.0
45 |
46 | Initial release for the `bolt` community with major support for multiline commands
47 |
--------------------------------------------------------------------------------
/tests/comprehensive/strings.mcfunction:
--------------------------------------------------------------------------------
1 | # literal
2 | # without contenxt, there is no way to differentiate
3 | # literal arguments from literal subcommands
4 | tag @s add mytag
5 |
6 | # literal
7 | tag @s add my_tag
8 |
9 | # literal
10 | say hello
11 |
12 | # literals
13 | say hello world
14 |
15 | # unquoted string
16 | # could be confused with an nbt path
17 | # but nbt paths typically have at least one capital letter
18 | tag @s add my.tag
19 |
20 | # unquoted string
21 | tag @s add my-tag
22 |
23 | # maybe nbt path
24 | data get entity @s My.Tag
25 |
26 | # definitely nbt path
27 | data get entity @s My.Tag[0]
28 |
29 | # quoted string
30 | say "hello world"
31 | say "hello ' world"
32 | say 'hello world'
33 | say 'hello " world'
34 |
35 | # quoted string escaped
36 | say "hello \" world"
37 | say 'hello \' world'
38 |
39 | # player names
40 | scoreboard players reset $mypack:some.fakeplayer
41 | scoreboard players reset $mypack.core:another.fakeplayer
42 |
43 | # quoted string with trailing characters
44 | say "oh oh"bad
45 | say 'oh oh'bad
46 |
47 | # quoted string with terminal backslash
48 | say "uh oh\
49 | say 'uh oh\
50 |
51 | # quoted string unbounded
52 | say "uh oh
53 | # this should be a comment, otherwise
54 | # the quoted string is probably leaking
55 |
56 | say 'uh oh
57 | # same here
58 |
59 | tellraw @s ["test test test\
60 | test test test test test test\
61 | test test", "test test"]
62 |
63 | tellraw @s ['test test test\
64 | test test test test test test\
65 | test test', 'test test']
66 |
--------------------------------------------------------------------------------
/tests/demo.mcfunction:
--------------------------------------------------------------------------------
1 | #> Block Comment Header
2 | # Normal comment - Example of some commands
3 | # @returns $my.variable at #resource:location
4 |
5 | # However, we don't get @returns highlighting here
6 |
7 | setblock ~ ~ ~ minecraft:dispenser[facing=up]{Items: [{id: "minecraft:diamond", Count: 1}]}
8 | $data modify storage $(id) $(path) set value "with random $(string1) stuff $(string2)"
9 | tellraw @a [{"text": "hello", "color": "blue"}, {"text": "world", "color": "blue"}]
10 | random roll 2..45 # neat command they added
11 | give @a #minecraft:log # plenty of wood to capture
12 |
13 | # multiline
14 | execute \
15 | as @a \
16 | at @s \
17 | if entity @s[distance=..0.6] \
18 | say bar
19 |
20 | # bolt
21 | infinite_invisibility = {
22 | Id: 14,
23 | Duration: 999999,
24 | Amplifier: 1,
25 | ShowParticles: false,
26 | }
27 |
28 | def summon_chicken_army(n):
29 | for i in range(n):
30 | summon chicken ~i ~ ~ {
31 | Tags: [f"quack{i}"],
32 | IsChickenJockey: true,
33 | Passengers: [{
34 | id: zombie,
35 | IsBaby: true,
36 | ActiveEffects: [infinite_invisibility]
37 | }]
38 | }
39 |
40 | say Go forth, my minions!
41 | summon_chicken_army(16)
42 |
43 | # mcbuild
44 | LOOP(1000,i){
45 | execute summon marker run mud:register {command:"function tests:a/target",setup:""}
46 | summon marker 0 0 0 {Tags:["a.i"]}
47 | }
48 |
--------------------------------------------------------------------------------
/tests/comprehensive/parsers/position/valid.mcfunction:
--------------------------------------------------------------------------------
1 | # all absolutes
2 | execute positioned 10 0 -10 run say hello
3 | execute positioned 10 10 -10 run say hello
4 | execute positioned 10 0.5 -10 run say hello
5 | execute positioned 10 .5 -10 run say hello
6 | execute positioned 10 -10 -10 run say hello
7 | execute positioned 10 -0.5 -10 run say hello
8 | execute positioned 10 -.5 -10 run say hello
9 |
10 | # absolutes mixed with relatives
11 | execute positioned 10 ~ -10 run say hello
12 | execute positioned 10 ~10 -10 run say hello
13 | execute positioned 10 ~0.5 -10 run say hello
14 | execute positioned 10 ~.5 -10 run say hello
15 | execute positioned 10 ~-10 -10 run say hello
16 | execute positioned 10 ~-0.5 -10 run say hello
17 | execute positioned 10 ~-.5 -10 run say hello
18 |
19 | # all relatives
20 | execute positioned ~10 ~ ~-10 run say hello
21 | execute positioned ~10 ~10 ~-10 run say hello
22 | execute positioned ~10 ~0.5 ~-10 run say hello
23 | execute positioned ~10 ~.5 ~-10 run say hello
24 | execute positioned ~10 ~-10 ~-10 run say hello
25 | execute positioned ~10 ~-0.5 ~-10 run say hello
26 | execute positioned ~10 ~-.5 ~-10 run say hello
27 |
28 | # all locals (can't be mixed)
29 | execute positioned ^10 ^ ^-10 run say hello
30 | execute positioned ^10 ^10 ^-10 run say hello
31 | execute positioned ^10 ^0.5 ^-10 run say hello
32 | execute positioned ^10 ^.5 ^-10 run say hello
33 | execute positioned ^10 ^-10 ^-10 run say hello
34 | execute positioned ^10 ^-0.5 ^-10 run say hello
35 | execute positioned ^10 ^-.5 ^-10 run say hello
36 |
--------------------------------------------------------------------------------
/tests/comprehensive/nbt_compound.mcfunction:
--------------------------------------------------------------------------------
1 | # test compounds
2 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: true }
3 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: true, bar: 1234, baz: "hello world" }
4 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: { bar: true } }
5 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: { bar: true, baz: 1234 } }
6 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: { bar: true, baz: 1234, fiz: "hello world" } }
7 |
8 | # test lists
9 | data modify block ~ ~ ~ RecordItem.tag.custom set value [ 1 ]
10 | data modify block ~ ~ ~ RecordItem.tag.custom set value [ 1, 2, 3 ]
11 | data modify block ~ ~ ~ RecordItem.tag.custom set value [ a, "hello world", b ]
12 | data modify block ~ ~ ~ RecordItem.tag.custom set value [ [1], [2.1, 2.5, 2.9], [3] ]
13 |
14 | # test combos
15 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: [ 1 ] }
16 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: [ 1, 2, 3 ] }
17 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: [ a, "hello world", b ] }
18 | data modify block ~ ~ ~ RecordItem.tag.custom set value { foo: [ { foo: true }, { bar: 1234 }, { baz: "hello world" } ] }
19 | data modify block ~ ~ ~ RecordItem.tag.custom set value [ { foo: true }, { bar: 1234 }, { baz: "hello world" } ]
20 |
21 | # edge case keys
22 | execute unless data block 0 0 0 this.block.is.something{foo_bar: true}
23 | execute unless data block 0 0 0 this.block.is.something{Foo.Bar: true}
24 | execute unless data block 0 0 0 this.block.is.something{foo-bar: true}
25 | execute unless data block 0 0 0 this.block.is.something[{foo.bar: true}]
26 |
--------------------------------------------------------------------------------
/tests/comprehensive/resource_location.mcfunction:
--------------------------------------------------------------------------------
1 | # valid, with namespace
2 | function mypack:foo
3 | function mypack:foo/bar
4 | function mypack:foo/bar/baz
5 | function #mypack:foo
6 | function #mypack:foo/bar
7 | function #mypack:foo/bar/baz
8 |
9 | # valid, without namespace
10 | function foo
11 | function foo/bar
12 | function foo/bar/baz
13 | function #foo
14 | function #foo/bar
15 | function #foo/bar/baz
16 |
17 | # valid, with trailing command
18 | execute if block ~ ~ ~ mypack:foo run say hi
19 | execute if block ~ ~ ~ mypack:foo/bar run say hi
20 | execute if block ~ ~ ~ mypack:foo/bar/baz run say hi
21 | execute if block ~ ~ ~ #mypack:foo run say hi
22 | execute if block ~ ~ ~ #mypack:foo/bar run say hi
23 | execute if block ~ ~ ~ #mypack:foo/bar/baz run say hi
24 |
25 | # invalid
26 | function mypack:
27 | function :foo
28 | function #mypack:
29 | function #:foo
30 | function mypack:/
31 | function mypack:foo/
32 | function mypack:/foo
33 | function #mypack:/
34 | function #mypack:foo/
35 | function #mypack:/foo
36 |
37 | # invalid, with trailing command
38 | execute if block ~ ~ ~ mypack: run say hi
39 | execute if block ~ ~ ~ :foo run say hi
40 | execute if block ~ ~ ~ mypack:/ run say hi
41 | execute if block ~ ~ ~ mypack:foo/ run say hi
42 | execute if block ~ ~ ~ mypack:/foo run say hi
43 | execute if block ~ ~ ~ mypack:/ run say hi
44 | execute if block ~ ~ ~ mypack:foo/ run say hi
45 | execute if block ~ ~ ~ mypack:/foo run say hi
46 | execute if block ~ ~ ~ #mypack:/ run say hi
47 | execute if block ~ ~ ~ #mypack:foo/ run say hi
48 | execute if block ~ ~ ~ #mypack:/foo run say hi
49 |
50 | function gm4_boots_of_ostara:flippers_merge
51 | function gm4_boots_of_ostara:flippers/merge
52 | function gm_boots_of_ostara:flippers_merge
53 |
--------------------------------------------------------------------------------
/tests/comprehensive/nbt_path/valid.mcfunction:
--------------------------------------------------------------------------------
1 | # basic property access
2 | data modify entity @s SelectedItem set value true
3 | data modify entity @s SelectedItem. set value true
4 | data modify entity @s SelectedItem.tag set value true
5 | data modify entity @s SelectedItem.tag. set value true
6 | data modify entity @s SelectedItem.tag.display set value true
7 |
8 | # list access
9 | data modify entity @s Inventory[] set value true
10 | data modify entity @s Inventory[0] set value true
11 | data modify entity @s Inventory[-1] set value true
12 | data modify entity @s Inventory[].tag set value true
13 |
14 | # list access with compound
15 | data modify entity @s Inventory[{}] set value true
16 | data modify entity @s Inventory[{Count: 64}] set value true
17 | data modify entity @s Inventory[{id: "minecraft:diamond"}] set value true
18 |
19 | # adjacent list access
20 | data modify entity @s Item.tag.foo[][] set value true
21 | data modify entity @s Item.tag.foo[0][] set value true
22 | data modify entity @s Item.tag.foo[][0] set value true
23 | data modify entity @s Item.tag.foo[0][0] set value true
24 | data modify entity @s Item.tag.foo[][][] set value true
25 | data modify entity @s Item.tag.foo[][0][] set value true
26 | data modify entity @s Item.tag.foo[][{}][] set value true
27 |
28 | # compound access
29 | data get entity @s Inventory[].tag{custom: true}.display.Name
30 |
31 | # quoted keys
32 | data modify entity @s Item.tag."my_quoted_key"
33 | data modify entity @s Item.tag."my_quoted_key"
34 | data modify entity @s Item.tag."my_quoted_key" set value true
35 | data modify entity @s Item.tag."my_quoted_key".foo set value true
36 | data modify entity @s Item.tag."my quoted key"
37 | data modify entity @s Item.tag."my quoted key".foo
38 | data modify entity @s Item.tag."my quoted key" set value true
39 | data modify entity @s Item.tag."my quoted key".foo set value true
40 |
--------------------------------------------------------------------------------
/tests/comprehensive/range.mcfunction:
--------------------------------------------------------------------------------
1 | # test valid range with integers
2 | execute if score @a temp matches 10.. run
3 | execute if score @a temp matches ..20 run
4 | execute if score @a temp matches 10..20 run
5 |
6 | # test valid range with integers in selectors
7 | execute as @a[distance=10..] run
8 | execute as @a[distance=..20] run
9 | execute as @a[distance=11..19] run
10 |
11 | # test valid range with negative integers
12 | execute if score @a temp matches -1.. run
13 | execute if score @a temp matches ..-1 run
14 | execute if score @a temp matches -2..-1 run
15 | execute if score @a temp matches -1..1 run
16 |
17 | # test valid range with negative integers in selectors
18 | execute as @a[x_rotation=-1..] run
19 | execute as @a[x_rotation=..-1] run
20 | execute as @a[x_rotation=-2..-1] run
21 | execute as @a[x_rotation=-1..1] run
22 |
23 | # test valid range with decimals in selectors
24 | execute as @a[distance=0.1..] run
25 | execute as @a[distance=0.2..0.8] run
26 | execute as @a[distance=..0.9] run
27 | execute as @a[distance=.1..] run
28 | execute as @a[distance=.2..0.8] run
29 | execute as @a[distance=0.2...8] run
30 | execute as @a[distance=.2...8] run
31 | execute as @a[distance=...9] run
32 |
33 | # test valid range with negative decimals in selectors
34 | execute as @a[x_rotation=-0.1..] run
35 | execute as @a[x_rotation=-.1..] run
36 | execute as @a[x_rotation=..-0.1] run
37 | execute as @a[x_rotation=..-.1] run
38 | execute as @a[x_rotation=-0.2..-0.1] run
39 | execute as @a[x_rotation=-.2..-.1] run
40 | execute as @a[x_rotation=-0.1..0.1] run
41 | execute as @a[x_rotation=-.1...1] run
42 |
43 | # test valid mixed range in selectors
44 | execute as @a[x_rotation=0..0.2] run
45 | execute as @a[x_rotation=0...2] run
46 | execute as @a[distance=0.2..1] run
47 | execute as @a[distance=.2..1] run
48 |
49 | # test invalid range
50 | execute if score @a temp matches .. run
51 |
52 | # test invalid range in selectors
53 | execute as @a[distance=..] run
54 |
--------------------------------------------------------------------------------
/tests/comprehensive/nbt_path/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | # multi dots
2 | data modify entity @s SelectedItem..tag set value true
3 | data modify entity @s SelectedItem...tag set value true
4 | data modify entity @s SelectedItem....tag set value true
5 | data modify entity @s SelectedItem..tag.custom set value true
6 | data modify entity @s SelectedItem..tag..custom set value true
7 |
8 | # list access
9 | data modify entity @s Inventory[ 0] set value true
10 | data modify entity @s Inventory[0 ] set value true
11 | data modify entity @s Inventory[ 0 ] set value true
12 | data modify entity @s Inventory[0.5] set value true
13 | data modify entity @s Inventory[true] set value true
14 | data modify entity @s Inventory[1, 2] set value true
15 |
16 | # trailing bracket data
17 | data modify entity @s Inventory[0]tag set value true
18 | data modify entity @s Inventory[{}]tag set value true
19 | data modify entity @s Inventory{}tag set value true
20 |
21 | # list access with compound
22 | data modify entity @s Inventory[ {} ] set value true
23 | data modify entity @s Inventory[x{}] set value true
24 | data modify entity @s Inventory[{}x] set value true
25 | data modify entity @s Inventory[x{}x] set value true
26 | data modify entity @s Inventory[ {Count: 64} ] set value true
27 |
28 | # test list access leak
29 | data get entity @s Inventory[
30 | data get entity @s Inventory[set value true
31 | data get entity @s Inventory[ set value true
32 | say hello
33 |
34 | # test compound access leak
35 | data get entity @s Inventory[].tag{custom: true
36 | data get entity @s Inventory[].tag{set value true
37 | data get entity @s Inventory[].tag{ set value true
38 | say hello
39 |
40 | # test inner list leak
41 | data get entity @s Inventory[[
42 | say hello
43 |
44 | # test inner compound leak
45 | data get entity @s Inventory[{
46 | say hello
47 |
48 | # test trailing text after quoted nbt path key
49 | data modify entity @s Item.tag."my_quoted_key"foo
50 | data modify entity @s Item.tag."my_quoted_key"foo set value true
51 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yaml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug Report
2 | description: File a bug report related to syntax highlighting
3 | title: "Bug: "
4 | labels: ["bug"]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thank you for taking the time to fill out a bug report.
11 |
12 | > **Important**
13 | > Remember to check that you are on the latest version of the extension (or indicate pre-release if applicable).
14 |
15 | - type: dropdown
16 | id: type-of-issue
17 | attributes:
18 | label: |
19 | What type of issues are you dealing with?
20 | description: |
21 | > **Note**
22 | > Coloring inconsistencies w/ `language-mcfunction` are not always considered bugs and may not be fixed
23 | multiple: true
24 | options:
25 | - Incorrect highlighting
26 | - Scope leak (breaking highlighting later in the file)
27 | - Coloring or scope inconsistency
28 | - Alternate syntax related (likely "Won't Fix")
29 | - Other (please specify)
30 |
31 | - type: textarea
32 | id: what-happened
33 | attributes:
34 | label: What happened?
35 | description: |
36 | What did you expect to happen? What happened instead?
37 | Include screenshots to explain your problem visually.
38 | placeholder: Tell us what you see!
39 | validations:
40 | required: true
41 |
42 | - type: dropdown
43 | id: platform
44 | attributes:
45 | label: Which text editors are you seeing the problem on?
46 | multiple: true
47 | options:
48 | - VSCode
49 | - Sublime Text
50 | - Other (please specify above)
51 | validations:
52 | required: true
53 |
54 | - type: textarea
55 | id: code-snippets
56 | attributes:
57 | label: Include a code snippet
58 | description: Put the exact code snippet used to produce the bug
59 | placeholder: |
60 | say my buggy command
61 | value: |
62 | execute as @a run say buggy command executed
63 | render: mcfunction
64 | validations:
65 | required: false
66 |
--------------------------------------------------------------------------------
/tests/comprehensive/showcase.mcfunction:
--------------------------------------------------------------------------------
1 | #> Raycasting
2 | # Casts a ray from starting position up to 128 blocks away.
3 |
4 | function mypack:raycast/loop
5 | function #mypack:hooks/raycast/begin
6 | effect give @s minecraft:night_vision 999999 1 true
7 | execute if score @a temp matches 10..20
8 | execute positioned 10 ~10 -10
9 | execute positioned 10 ^0.5 -10
10 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent=true]
11 | execute if block ~ ~ ~ #minecraft:leaves[distance=5,persistent=false]
12 | setblock ~ ~ ~ minecraft:dispenser[facing=up]{Items: [{id: "minecraft:diamond", Count: 1}]}
13 | tag @s add my.tag
14 | datapack enable "hello world"
15 | datapack enable "escape \" me"
16 | datapack enable 'single quotes'
17 | give @s minecraft:diamond_sword{display: {Name: '"My Custom Sword"'}}
18 | execute as f7a39418-72ca-4bf2-bc7e-ba9df67a4707 run say hello
19 | execute as 0-0-0-0-0 run say goodbye
20 | execute as @a[sort=nearest]
21 | execute as @a[gamemode=!creative]
22 | execute as @a[tag=foo,tag=bar,tag=!baz]
23 | execute as @a[distance=100]
24 | execute as @a[distance=1..19]
25 | execute as @a[distance=...001]
26 | execute as @a[type=minecraft:bat]
27 | execute as @a[type=!#minecraft:skeletons,type=!minecraft:zombie]
28 | execute as @a[name="Custom Name"] as @s
29 | execute as @e[nbt={ PortalCooldown: 0 }]
30 | execute as @e[nbt={ Item: {id: "minecraft:diamond", Count: 64 } }]
31 | execute if score @s foo < @s bar
32 | scoreboard players operation @s foo %= @s bar
33 | data get entity @s SelectedItem.tag.display.Name
34 | data get entity @s Inventory[0]
35 | data get entity @s Inventory[{id: "minecraft:diamond"}].Count
36 | data get entity @s Inventory[].tag{custom: true}.display.Name
37 | data merge entity @s { foo: true, bar: 1234 }
38 | data modify block ~ ~ ~ RecordItem.tag set value { messages: [hi, bye] }
39 | data modify block ~ ~ ~ RecordItem.tag.messages append value [ { message: "hello world" } ]
40 | tellraw @a {"text": "hello world", "color": "blue"}
41 | tellraw @a [{"text": "hello", "color": "blue"}, {"text": "world", "color": "blue"}]
42 | execute as @a[scores={myscore=1..}]
43 | execute as @a[scores={foo=10, bar=1..5, baz=..0}]
44 | execute as @a[advancements={mypack:some/advancement=true}]
45 | execute as @a[advancements={mypack:another/advancement={foo=true, bar=false}}]
46 |
47 |
--------------------------------------------------------------------------------
/tests/comprehensive/comments.mcfunction:
--------------------------------------------------------------------------------
1 | #> Raycasting
2 | #
3 | # Casts a ray from starting position along a configurable number
4 | # of blocks with a confugrable accuracy, counting the number of
5 | # entities hit by the ray along the way.
6 | #
7 | # @params
8 | # $mypack.raycast.distance param
9 | # The number of blocks to cast forward.
10 | # $mypack.raycast.precision param
11 | # The ratio of block precision to a full block.
12 | #
13 | # @returns
14 | # $mypack.raycast.result return
15 | # The number of entities hit by the ray.
16 |
17 | # @test no longer part of the block comment
18 | execute as @s run say this should not be a comment
19 |
20 | execute as @s run say this should also not be a comment
21 |
22 | # Non-highlighted block
23 | # @hello this block is not highlighted
24 | # because the first line doesn't have a prefix
25 |
26 | #! Another block
27 | # @hello this is another block
28 | # and this is the end
29 |
30 | ## Another block
31 | # @hello this is another block
32 | # and this is the end
33 |
34 | execute as @s run say this should be a command
35 |
36 | #> One block
37 | #> Two block
38 |
39 | # @hello world
40 | #> Red block
41 | # @hello world
42 | #> Blue block
43 | # @hello world
44 |
45 | #> An indented block
46 | # @hello does this still work?
47 | # hopefully it does
48 | execute as @s run say goodbye world
49 |
50 | #> Yet another block
51 | # @except this time
52 | # we have very strange indents
53 | execute as @s run say goodbye world
54 | execute as @s run say goodbye world
55 | execute as @s run say goodbye world
56 |
57 | #> Yet another block
58 | # @yeah another one
59 | # blah blah blah
60 | execute as @s run say this should also be a command
61 | execute as @s run say this should also also be a command
62 |
63 | execute as @s run say this should also also also be a command
64 |
65 | ## An alternate block comment prefix
66 | # a
67 | # b
68 | # c
69 |
70 | ### With multiple characters
71 |
72 | ########## Really long one
73 |
74 | #~ Another alternate prefix
75 |
76 | #! And another one
77 |
78 | #@ And another one
79 |
80 | #$ And another one
81 |
82 | #% And another one
83 |
84 | #^ And another one
85 |
86 | #* And another one
87 |
88 | ## This should be a block comment
89 |
90 | #execute as @a run say hi
91 | # execute as @a run say hi
92 | #> execute as @a run say hi
93 |
94 | execute as @a run say hi # tacossss
95 | execute if block #minecraft:stone
96 |
97 |
--------------------------------------------------------------------------------
/tests/comprehensive/commands/effect.mcfunction:
--------------------------------------------------------------------------------
1 | effect
2 | effect clear
3 | effect clear targets
4 | effect clear targets effect
5 | effect give
6 | effect give targets
7 | effect give targets effect
8 | effect give targets effect seconds
9 | effect give targets effect seconds amplifier
10 | effect give targets effect seconds amplifier hideParticles
11 |
12 | # effect
13 | effect
14 | effect
15 | effect foo
16 |
17 | # effect clear
18 | effect clear
19 | effect clear s
20 | effect clear @
21 | effect clear @s
22 | effect clear @s
23 | effect clear @s foo
24 | effect clear @s minecraft:foo
25 | effect clear @s strength
26 | effect clear @s minecraft:strength
27 | effect clear @s minecraft:strength
28 | effect give @e[tag=foo] minecraft:strength
29 | effect give Arcensoth minecraft:strength
30 | effect give f7a39418-72ca-4bf2-bc7e-ba9df67a4707 minecraft:strength
31 | effect give @s minecraft:strength/foo
32 |
33 | # effect give
34 | effect give
35 | effect give
36 | effect give s
37 | effect give @
38 | effect give @s
39 | effect give @s
40 | effect give @s foo
41 | effect give @s minecraft:foo
42 | effect give @s strength
43 | effect give @s minecraft:strength
44 | effect give @e[tag=foo] minecraft:strength
45 | effect give Arcensoth minecraft:strength
46 | effect give f7a39418-72ca-4bf2-bc7e-ba9df67a4707 minecraft:strength
47 | effect give @s minecraft:strength/foo
48 | effect give @s minecraft:strength
49 | effect give @s minecraft:strength 1
50 | effect give @s minecraft:strength foo
51 | effect give @s minecraft:strength 0
52 | effect give @s minecraft:strength -1
53 | effect give @s minecraft:strength 1
54 | effect give @s minecraft:strength 999999
55 | effect give @s minecraft:strength 999999
56 | effect give @s minecraft:strength 999999 foo
57 | effect give @s minecraft:strength 999999 0
58 | effect give @s minecraft:strength 999999 -1
59 | effect give @s minecraft:strength 999999 1
60 | effect give @s minecraft:strength 999999 127
61 | effect give @s minecraft:strength 999999 127
62 | effect give @s minecraft:strength 999999 127 t
63 | effect give @s minecraft:strength 999999 127 true
64 | effect give @s minecraft:strength 999999 127 false
65 | effect give @s minecraft:strength 999999 127 true
66 | effect give @s minecraft:strength 999999 127 true
67 | effect give @s minecraft:strength 999999 127 true uhoh
68 |
69 | effect give @s minecraft:strength
70 | effect give @s minecraft:strength
71 | effect give @s minecraft:strength
72 | effect give @s minecraft:strength
73 | effect give @s minecraft:strength
74 | effect give @s minecraft:strength
75 | effect give @s minecraft:strength 999999
76 |
--------------------------------------------------------------------------------
/tests/comprehensive/target_selectors/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | execute as @s[
2 | execute as @s[
3 | execute as @s[sort=nearest,
4 | execute as @s[sort=nearest,
5 | execute as @s[ run say hello
6 | execute as @s[]run execute as @s run say hello
7 | execute as @s[ ]run execute as @s run say hello
8 | execute as @s [] run execute as @s run say hello
9 | execute as @s [ ] run execute as @s run say hello
10 | execute as @s[nearest] run execute as @s run say hello
11 | execute as @s[nearest ] run execute as @s run say hello
12 | execute as @s[ nearest] run execute as @s run say hello
13 | execute as @s[ nearest ] run execute as @s run say hello
14 | execute as @s[,] run execute as @s run say hello
15 | execute as @s[ ,] run execute as @s run say hello
16 | execute as @s[, ] run execute as @s run say hello
17 | execute as @s[ , ] run execute as @s run say hello
18 | execute as @s[,sort=nearest] run execute as @s run say hello
19 | execute as @s[ ,sort=nearest] run execute as @s run say hello
20 | execute as @s[ ,sort=nearest] run execute as @s run say hello
21 | execute as @s[sort,sort=nearest] run execute as @s run say hello
22 | execute as @s[sort ,sort=nearest] run execute as @s run say hello
23 | execute as @s[sort=,sort=nearest] run execute as @s run say hello
24 | execute as @s[sort=nearest,] run execute as @s run say hello
25 | execute as @s[sort=nearest, ] run execute as @s run say hello
26 | execute as @s[sort=nearest ,, sort=bar] run execute as @s run say hello
27 | execute as @s[sort=nearest , , sort=bar] run execute as @s run say hello
28 | execute as @s[sort=nearest,sort] run execute as @s run say hello
29 | execute as @s[sort=nearest,sort=] run execute as @s run say hello
30 | execute as @s[sort=nearest,sort,sort=bar] run execute as @s run say hello
31 | execute as @s[sort=nearest,sort=,sort=bar] run execute as @s run say hello
32 |
33 | execute as @e[sort] run
34 | execute as @e[sort=] run
35 | execute as @e[sort=foo] run
36 | execute as @e[sort=nearestfoo] run
37 | execute as @e[sort=foonearest] run
38 | execute as @e[sort=!nearest] run
39 |
40 | execute as @e[limit] run
41 | execute as @e[limit=] run
42 | execute as @e[limit=foo] run
43 | execute as @e[limit=nearest] run
44 | execute as @e[limit=0.1] run
45 | execute as @e[limit=-1] run
46 | execute as @e[limit=!1] run
47 |
48 | execute as @e["quoted_key=foo] run say hi
49 | execute as @e[quoted_key"=foo] run say hi
50 | execute as @e["quoted_key""=foo] run say hi
51 | execute as @e["quoted_key"bar=foo] run say hi
52 | execute as @e[bar"quoted_key"=foo] run say hi
53 |
54 | execute as @e['quoted_key=foo] run say hi
55 | execute as @e[quoted_key'=foo] run say hi
56 | execute as @e['quoted_key''=foo] run say hi
57 | execute as @e['quoted_key'bar=foo] run say hi
58 | execute as @e[bar'quoted_key'=foo] run say hi
59 |
--------------------------------------------------------------------------------
/tests/comprehensive/text_components/invalid.mcfunction:
--------------------------------------------------------------------------------
1 | tellraw @s xtrue
2 | tellraw @s xtrue,
3 | tellraw @s true,
4 | tellraw @s [true,]
5 | tellraw @s [xtrue,]
6 | tellraw @s truex
7 | tellraw @s xtruex
8 |
9 | tellraw @s {"bold": foo}
10 | tellraw @s {"bold": "true"}
11 |
12 | tellraw @s {"color": "foo"}
13 |
14 | tellraw @s {"keybind": "foo"}
15 |
16 | tellraw @s { "extra" : foo }
17 | tellraw @s { "extra" : foo, "text": "hello" }
18 | tellraw @s { "extra" : "{}" }
19 | tellraw @s { "extra" : "{ a : [ { b : c} ] }" }
20 | tellraw @s { "extra" : "{ a : " " }
21 | tellraw @s { "extra" : "{ a : \" " }
22 | tellraw @s { "extra" : "[]" }
23 | tellraw @s { "extra" : "[ { a : b } ] " }
24 | tellraw @s { "extra" : "[ { a : \" } ] " }
25 | tellraw @s { "extra" : "[ { a : " } ] " }
26 |
27 | tellraw @s { "text": "hello", "extra" : "{}" }
28 | tellraw @s { "extra" : "{}", "text": "hello" }
29 | tellraw @s [{ "extra" : "{}" }, { "extra" : "{}" }]
30 |
31 | tellraw @s { "unknown" : "{}" }
32 | tellraw @s { "unknown" : "[]" }
33 | tellraw @s { "extra" : [ { "unknown" : "foo" } ] }
34 | tellraw @s { "extra" : [ { "unknown" : "{}" } ] }
35 | tellraw @s { "extra" : [ { "unknown" : "[]" } ] }
36 | tellraw @s { "foo" : { "bar" : "{}" } }
37 | tellraw @s { "foo" : { "bar" : "[]" } }
38 | tellraw @s { "foo" : [ { "bar" : "{}" } ] }
39 | tellraw @s { "foo" : [ { "bar" : "[]" } ] }
40 |
41 | tellraw @s {"text"}
42 | tellraw @s {"text
43 | tellraw @s {"text"
44 | tellraw @s {"text":
45 | tellraw @s {"text":}
46 | tellraw @s {"text":}
47 | tellraw @s {"text": }
48 | tellraw @s {"text": }
49 | tellraw @s {"text": }
50 | tellraw @s {"text":foo}
51 | tellraw @s {"text": foo}
52 | tellraw @s {"text": foo}
53 | tellraw @s {"text": foo}
54 | tellraw @s {"text": foo }
55 | tellraw @s {"text" foo}
56 | tellraw @s {"text" foo }
57 | tellraw @s {"text": 0}
58 | tellraw @s {"text": true}
59 | tellraw @s {"text": hello world}
60 | tellraw @s {"translate": true}
61 | tellraw @s {"translate": hello world}
62 | tellraw @s {"translate": true, "text"}
63 | tellraw @s {"translate": true, "text":}
64 | tellraw @s {"translate": true, "text": true}
65 | tellraw @s {"translate": true, "text": "hello"}
66 | tellraw @s {"translate": two words, "text": "hello"}
67 | tellraw @s {"translate": "two words", "text": uh oh}
68 | tellraw @s {"translate": true, "text": hello world}
69 | tellraw @s {"translate": true, "unknown": true}
70 |
71 | tellraw @s {"unknown": "unknown text component key"}
72 | tellraw @s {"selector": "not a target"}
73 | tellraw @s {"selector": " @e"}
74 | tellraw @s {"selector": "@e "}
75 | tellraw @s {"selector": " @e "}
76 | tellraw @s {"selector": "@e["}
77 | tellraw @s {"selector": "@e]"}
78 | tellraw @s {"selector": "@e[sort"}
79 | tellraw @s {"selector": "@e[sort]"}
80 | tellraw @s {"selector": "@e[sort="}
81 | tellraw @s {"selector": "@e[sort=foo"}
82 | tellraw @s {"selector": "@e[sort=foo]"}
83 | tellraw @s {"selector": "@e[sort=nearest"}
84 | tellraw @s {"selector": " @e[sort=nearest]"}
85 | tellraw @s {"selector": "@e[sort=nearest] "}
86 | tellraw @s {"selector": " @e[sort=nearest] "}
87 | tellraw @s {"selector": "@e[sort=nearest,"}
88 | tellraw @s {"selector": "@e[sort=nearest,]"}
89 | tellraw @s [{"extra": "x"}]
90 | tellraw @s [{"extra": {"foo": [0, [1, 2], 3]}}]
91 |
92 | tellraw @s {"block": "", "nbt": "RecordItem"}
93 | tellraw @s {"block": "no", "nbt": "RecordItem"}
94 | tellraw @s {"block": true, "nbt": "RecordItem"}
95 | tellraw @s {"block": 0, "nbt": "RecordItem"}
96 | tellraw @s {"block": 1 2 3, "nbt": "RecordItem"}
97 | tellraw @s {"block": "10 20", "nbt": "RecordItem"}
98 | tellraw @s {"block": "^10 20 30", "nbt": "RecordItem"}
99 | tellraw @s {"block": "10 ^20 30", "nbt": "RecordItem"}
100 | tellraw @s {"block": "10 20 ^30", "nbt": "RecordItem"}
101 |
102 | tellraw @s {"text": 3.14x}
103 |
104 | tellraw @s {"text": "hello", "nby": "RecordItem.tag.foo", "text": "world"}
105 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | pull_request:
5 | branches: [main]
6 | paths:
7 | - "mcfunction.*"
8 | push:
9 | tags: ["v*.*.*"]
10 |
11 | jobs:
12 | ci:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | # ---------------------------------------------
17 | # ---- gather repo -----
18 | # ---------------------------------------------
19 | - uses: actions/checkout@v3
20 | with:
21 | fetch-depth: 0
22 |
23 | # Fetch all branches and tags
24 | - name: Fetch all branches and tags
25 | run: git fetch --all
26 |
27 | - name: Checkout main branch
28 | run: git checkout main
29 |
30 | # ---------------------------------------------
31 | # ---- setup deps -----
32 | # ---------------------------------------------
33 | - name: Use Node.js ${{ matrix.node-version }}
34 | uses: actions/setup-node@v3
35 | with:
36 | node-version: 20.x
37 | cache: npm
38 |
39 | - name: Install npm stuff
40 | run: |
41 | npm install -g @vscode/vsce
42 | npm install -g js-yaml
43 | npm install -g ovsx
44 | npm install -g plist2
45 |
46 | - name: "Setup jq"
47 | uses: dcarbone/install-jq-action@v2
48 | with:
49 | version: 1.7
50 | force: true
51 |
52 | # ---------------------------------------------
53 | # ---- generate files -----
54 | # ---------------------------------------------
55 | - name: Export YAML -> JSON -> PLIST
56 | run: |
57 | js-yaml mcfunction.tmLanguage.yaml > mcfunction.tmLanguage.json
58 | plist2 mcfunction.tmLanguage.json mcfunction.tmLanguage
59 |
60 | - id: version
61 | name: Version
62 | run: |
63 | VERSION=$(echo ${{ github.ref_name }} | sed 's/^v//')
64 | echo "v=$VERSION" >> "$GITHUB_OUTPUT"
65 | echo "ext=syntax-mcfunction-$VERSION.vsix" >> "$GITHUB_OUTPUT"
66 |
67 | # ---------------------------------------------
68 | # ---- push files -----
69 | # ---------------------------------------------
70 | - name: Push JSON to repo for sublime (if not matched)
71 | if: github.ref == 'refs/heads/main'
72 | run: |
73 | git config --global user.name "github-actions"
74 | git config --global user.email "action@github.com"
75 | git add mcfunction.tmLanguage.json mcfunction.tmLanguage
76 | git commit -m "🤖 Generate JSON/PLIST"
77 | git push origin main
78 | continue-on-error: true
79 |
80 | - name: Push version number to repo
81 | if: startsWith(github.ref, 'refs/tags/')
82 | run: |
83 | jq '.version = "${{ steps.version.outputs.v }}"' package.json > package.json.tmp
84 | mv package.json.tmp package.json
85 | git config --global user.name "github-actions"
86 | git config --global user.email "action@github.com"
87 | git add package.json
88 | git commit -m "🎉 Release ${{ steps.version.outputs.v }}"
89 | git push origin main
90 |
91 | # ---------------------------------------------
92 | # ---- release -----
93 | # ---------------------------------------------
94 | - id: package
95 | name: Package VSCode Ext
96 | run: vsce package
97 |
98 | - name: Archive production artifacts
99 | uses: actions/upload-artifact@v3
100 | if: "!startsWith(github.ref, 'refs/tags/')"
101 | with:
102 | name: dist-without-markdown
103 | path: |
104 | *.vsix
105 | mcfunction.tmLanguage.yaml
106 | mcfunction.tmLanguage.json
107 |
108 | - name: Release
109 | uses: softprops/action-gh-release@v1
110 | if: startsWith(github.ref, 'refs/tags/')
111 | with:
112 | files: |
113 | *.vsix
114 | mcfunction.tmLanguage.yaml
115 | mcfunction.tmLanguage.json
116 |
117 | - name: Release to vsce
118 | if: startsWith(github.ref, 'refs/tags/')
119 | run: vsce publish
120 | env:
121 | VSCE_PAT: ${{ secrets.VSCE_PAT }}
122 |
123 | - name: Release to openvsix
124 | if: startsWith(github.ref, 'refs/tags/')
125 | run: npx ovsx publish ${{ steps.version.outputs.ext }} -p ${{ secrets.OVSX }}
126 |
--------------------------------------------------------------------------------
/tests/comprehensive/target_selectors/valid.mcfunction:
--------------------------------------------------------------------------------
1 | execute as @s run execute as @s run say hello
2 | execute as 0-0-0-0-0 run execute as @s run say hello
3 | execute as f7a39418-72ca-4bf2-bc7e-ba9df67a4707 run execute as @s run say hello
4 | execute as Arcensoth run execute as @s run say hello
5 | execute as some_guy run execute as @s run say hello
6 | execute as @s[] run execute as @s run say hello
7 | execute as @s[ ] run execute as @s run say hello
8 | execute as @s[tag=foo] run execute as @s run say hello
9 | execute as @s[tag=!foo] run execute as @s run say hello
10 | execute as @s[ tag = foo ] run execute as @s run say hello
11 | execute as @s[ tag = !foo ] run execute as @s run say hello
12 | execute as @s[ tag = ! foo ] run execute as @s run say hello
13 | execute as @s[tag=foo,tag=bar] run execute as @s run say hello
14 | execute as @s[ tag=foo,tag=bar] run execute as @s run say hello
15 | execute as @s[tag=foo,tag=bar ] run execute as @s run say hello
16 | execute as @s[tag=foo ,tag=bar] run execute as @s run say hello
17 | execute as @s[tag=foo, tag=bar] run execute as @s run say hello
18 | execute as @s[tag=foo , tag=bar] run execute as @s run say hello
19 | execute as @s[ tag = foo , tag = bar ] run execute as @s run say hello
20 | execute as @s[tag = foo ,tag = bar ] run execute as @s run say hello
21 | execute as @s[tag = foo , tag = bar ] run execute as @s run say hello
22 | execute as @s[ tag = foo ,tag = bar ] run execute as @s run say hello
23 | execute as @s[ tag = foo , tag = bar ] run execute as @s run say hello
24 | execute as @s[tag = foo ,tag = bar ] run execute as @s run say hello
25 | execute as @s[tag = foo,tag = bar ] run execute as @s run say hello
26 | execute as @s[tag = foo, tag = bar ] run execute as @s run say hello
27 | execute as @s[ tag = foo , tag = bar ] run execute as @s run say hello
28 | execute as @s[tag = foo , tag = bar] run execute as @s run say hello
29 | execute as @s[ tag = foo , tag = bar , tag = baz ] run execute as @s run say hello
30 | execute as @s[nbt={custom: true}] as @s run say hello
31 | execute as @s[nbt={foo: {bar: []}}] as @s run say hello
32 | execute as @s[nbt={foo: {bar: [{baz: {}}]}}] as @s run say hello
33 | execute as @s[nbt=!{custom: true}] as @s run say hello
34 | execute as @e[tag=foo, sort=nearest, nbt={custom: true}] run execute as @s run execute as @s run say hello
35 |
36 | execute as @e[sort=nearest] run say hello
37 | execute as @e[ sort = nearest ] run say hello
38 | execute as @e[ sort = nearest ] run say hello
39 |
40 | execute as @e[limit=1] run say hello
41 | execute as @e[limit=01] run say hello
42 | execute as @e[ limit = 1 ] run say hello
43 | execute as @e[ limit = 1 ] run say hello
44 |
45 | execute as @e[team=] run say hi
46 | execute as @e[team=!] run say hi
47 | execute as @e[team=foo] run say hi
48 | execute as @e[team=!foo] run say hi
49 | execute as @e[team=foo.bar] run say hi
50 | execute as @e[team=!foo.bar] run say hi
51 |
52 | execute as @e[tag=] run say hi
53 | execute as @e[tag=!] run say hi
54 | execute as @e[tag=foo] run say hi
55 | execute as @e[tag=!foo] run say hi
56 | execute as @e[tag=foo.bar] run say hi
57 | execute as @e[tag=!foo.bar] run say hi
58 |
59 | execute as @e[name=] run say hi
60 | execute as @e[name=!] run say hi
61 | execute as @e[name=foo] run say hi
62 | execute as @e[name=!foo] run say hi
63 | execute as @e[name=""] run say hi
64 | execute as @e[name="foo bar"] run say hi
65 | execute as @e[name=!"foo bar"] run say hi
66 | execute as @e[name="foo \" bar"] run say hi
67 | execute as @e[name="foo ' bar"] run say hi
68 | execute as @e[name=''] run say hi
69 | execute as @e[name='foo bar'] run say hi
70 | execute as @e[name=!'foo bar'] run say hi
71 | execute as @e[name='foo \' bar'] run say hi
72 | execute as @e[name='foo " bar'] run say hi
73 |
74 | # double quoted keys
75 | execute as @e["quoted_key"=foo] run say hi
76 | execute as @e["quoted key"=foo] run say hi
77 | execute as @e[foo=bar,"quoted key"=foo] run say hi
78 | execute as @e["quoted key"=foo,foo=bar] run say hi
79 | execute as @e[foo=bar,"quoted key"=foo,foo=bar] run say hi
80 | execute as @e[foo=bar, "quoted key"=foo, foo=bar] run say hi
81 | execute as @e["quoted key"=foo, "another quoted key"=foo] run say hi
82 | execute as @e["quoted 'x key"=foo] run say hi
83 | execute as @e["quoted 'x' key"=foo] run say hi
84 |
85 | # single quoted keys
86 | execute as @e['quoted_key'=foo] run say hi
87 | execute as @e['quoted key'=foo] run say hi
88 | execute as @e[foo=bar,'quoted key'=foo] run say hi
89 | execute as @e['quoted key'=foo,foo=bar] run say hi
90 | execute as @e[foo=bar,'quoted key'=foo,foo=bar] run say hi
91 | execute as @e[foo=bar, 'quoted key'=foo, foo=bar] run say hi
92 | execute as @e['quoted key'=foo, 'another quoted key'=foo] run say hi
93 | execute as @e['quoted "x key'=foo] run say hi
94 | execute as @e['quoted "x" key'=foo] run say hi
95 |
--------------------------------------------------------------------------------
/tests/comprehensive/everything.mcfunction:
--------------------------------------------------------------------------------
1 | #> Raycasting
2 | #
3 | # Casts a ray from starting position along a configurable number
4 | # of blocks with a confugrable accuracy, counting the number of
5 | # entities hit by the ray along the way.
6 | #
7 | # @params
8 | # $mypack.raycast.distance param
9 | # The number of blocks to cast forward.
10 | # $mypack.raycast.precision param
11 | # The ratio of block precision to a full block.
12 | #
13 | # @returns
14 | # $mypack.raycast.result return
15 | # The number of entities hit by the ray.
16 |
17 | function #mypack:hooks/raycast/begin
18 |
19 | function mypack:raycast/loop
20 |
21 | function #mypack:hooks/raycast/end
22 |
23 | # this is a comment
24 | say hello world
25 |
26 | # indented comment
27 | say hello indent
28 |
29 | effect give @s minecraft:night_vision 999999 1 true
30 | effect give @s minecraft:night_vision 999999 1 false
31 |
32 | teleport 1 2 3
33 | teleport 100.5 80 -100.5
34 |
35 | execute if score @a temp matches 10.. run
36 | execute if score @a temp matches ..20 run
37 | execute if score @a temp matches 10..20 run
38 |
39 | execute positioned 10 ~ -10 run
40 | execute positioned 10 ~10 -10 run
41 | execute positioned 10 ~0.5 -10 run
42 | execute positioned 10 ~.5 -10 run
43 | execute positioned 10 ~-10 -10 run
44 | execute positioned 10 ~-0.5 -10 run
45 | execute positioned 10 ~-.5 -10 run
46 |
47 | execute positioned 10 ^ -10 run
48 | execute positioned 10 ^10 -10 run
49 | execute positioned 10 ^0.5 -10 run
50 | execute positioned 10 ^.5 -10 run
51 | execute positioned 10 ^-10 -10 run
52 | execute positioned 10 ^-0.5 -10 run
53 | execute positioned 10 ^-.5 -10 run
54 |
55 | function mypack:foo
56 | function mypack:foo/bar
57 | function mypack:foo/bar/baz
58 | function #mypack:foo
59 | function #mypack:foo/bar
60 | function #mypack:foo/bar/baz
61 |
62 | execute if block ~ ~ ~ minecraft:oak_log[axis=x] run
63 | execute if block ~ ~ ~ minecraft:oak_leaves[distance=5] run
64 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent=true] run
65 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent=false] run
66 | execute if block ~ ~ ~ minecraft:oak_leaves[distance=5,persistent=true] run
67 | execute if block ~ ~ ~ #minecraft:leaves[distance=5] run
68 | execute if block ~ ~ ~ #minecraft:leaves[distance=5,persistent=true] run
69 | setblock ~ ~ ~ mypack:foo{foo:bar} destroy
70 | setblock ~ ~ ~ mypack:foo{foo: bar} destroy
71 | setblock ~ ~ ~ mypack:foo[facing=up]{foo: bar} destroy
72 | setblock ~ ~ ~ mypack:foo[facing = up]{foo: bar} destroy
73 | setblock ~ ~ ~ minecraft:dispenser[facing=up]{Items: [{id: "minecraft:diamond", Count: 1}]}
74 |
75 | tag @s add my.tag
76 |
77 | datapack enable "hello world"
78 | datapack enable "escape \" me"
79 | datapack enable 'hello world'
80 | datapack enable 'escape \' me'
81 |
82 | execute as f7a39418-72ca-4bf2-bc7e-ba9df67a4707 run
83 | execute as 0-0-0-0-0 run
84 |
85 | execute store result score #fakeplayer
86 | execute store result score #fake.player
87 | execute store result score #fake_player
88 | execute store result score $fakeplayer
89 | execute store result score %fakeplayer
90 |
91 | execute as @b
92 | execute as @a
93 |
94 | execute as @a[tag=foo]
95 | execute as @a[tag=!foo]
96 |
97 | execute as @a[sort=nearest] run
98 | execute as @a[gamemode=survival] run
99 | execute as @a[gamemode=!creative] run
100 | execute as @a[tag=foo,tag=bar,tag=!baz] run
101 |
102 | execute as @a[distance=15]
103 | execute as @a[distance=1.5]
104 | execute as @a[distance=.5]
105 | execute as @a[distance=-.25]
106 |
107 | execute as @a[distance=100]
108 | execute as @a[distance=..10]
109 | execute as @a[distance=11..19]
110 | execute as @a[distance=20..]
111 | execute as @a[distance=0.5]
112 | execute as @a[distance=..0.1]
113 | execute as @a[distance=0.2..0.8]
114 | execute as @a[distance=0.9..]
115 |
116 | execute as @a[type=minecraft:bat] run
117 | execute as @a[type=!minecraft:cow,type=!minecraft:pig] run
118 | execute as @a[type=#minecraft:skeletons] run
119 | execute as @a[type=!#minecraft:skeletons,type=!minecraft:zombie] run
120 |
121 | execute as @a[tag=my.tag] run
122 |
123 | execute as @a[name="hello world"] as @s run
124 | execute as @a[name="escape \" me"] as @s run
125 | execute as @a[name="how, about, commas ?"] as @s run
126 | execute as @a[name="and [braces] ?"] as @s run
127 |
128 | execute as @e[nbt={ PortalCooldown: 0 }] run
129 | execute as @e[nbt={ Item: {id: "minecraft:diamond", Count: 64 } }] run
130 |
131 | execute if score @s foo < @s bar run
132 | execute if score @s foo <= @s bar run
133 | execute if score @s foo = @s bar run
134 | execute if score @s foo > @s bar run
135 | execute if score @s foo >= @s bar run
136 |
137 | data get entity @s SelectedItem.tag.display.Name
138 | data get entity @s Inventory[0]
139 | data get entity @s Inventory[{id: "minecraft:diamond"}].Count
140 | data get entity @s Inventory[].tag{custom: true}.display.Name
141 |
142 | data merge entity @s { foo: true, bar: 1234 }
143 | data modify block ~ ~ ~ RecordItem.tag set value { messages: [hi, bye] }
144 | data modify block ~ ~ ~ RecordItem.tag.messages append value [ { message: "hello world" } ]
145 |
146 | tellraw @a {"text": "hello world", "color": "blue"}
147 | tellraw @a [{"text": "hello", "color": "blue"}, {"text": "world", "color": "blue"}]
148 |
149 | execute as @a[scores={myscore=10}] run
150 | execute as @a[scores={myscore=10..12}] run
151 | execute as @a[scores={foo=10, bar=1..5, baz=..0}] run
152 |
153 | execute as @a[advancements={minecraft:story/form_obsidian=true}] run
154 | execute as @a[advancements={minecraft:story/obtain_armor={iron_helmet=true}}] run
155 | execute as @a[advancements={minecraft:story/obtain_armor={iron_helmet=true, gold_helmet=false}}] run
156 | execute as @a[advancements={minecraft:story/form_obsidian=true, minecraft:story/follow_ender_eye=true}] run
157 | execute as @a[advancements={minecraft:story/form_obsidian={foo=true, bar=false},minecraft:story/follow_ender_eye={foo=false, bar=true}}] run
158 |
159 | give @s diamond_sword{display: {Name: '"My Custom Sword"'}}
160 | give @s minecraft:diamond_sword{display: {Name: '"My Custom Sword"'}}
161 |
162 | execute if score @s foo < @s bar run say execute if score @s foo < @s bar run say
163 | execute if score @s foo < @s bar run say hello @e[tag=baz, sort=nearest, limit=1] how are you?
164 |
--------------------------------------------------------------------------------
/tests/comprehensive/text_components/valid.mcfunction:
--------------------------------------------------------------------------------
1 | # See: https://github.com/skylinerw/guides/blob/master/java/text%20component.md
2 |
3 | # "text" and escaping
4 | tellraw @s {"text": "hello world"}
5 | tellraw @s {"text": "hello \"escaped\" world"}
6 | tellraw @s {"text": "hello \" world"}
7 | tellraw @s {"text": "hello ' world"}
8 | tellraw @s {"text": "hello\nworld"}
9 | tellraw @s {"text": true}
10 | tellraw @s {"text": 123}
11 | tellraw @s {"text": -321}
12 | tellraw @s {"text": 3.14}
13 |
14 | # "bold", "italic", "underline", and "obfuscated"
15 | tellraw @s {"bold": false}
16 | tellraw @s {"text": "this is bold", "bold": true}
17 | tellraw @s {"italic": false}
18 | tellraw @s {"text": "this is italic", "italic": true}
19 | tellraw @s {"underlined": false}
20 | tellraw @s {"text": "this is underlined", "underlined": true}
21 | tellraw @s {"strikethrough": false}
22 | tellraw @s {"text": "this is strikethrough", "strikethrough": true}
23 | tellraw @s {"obfuscated": false}
24 | tellraw @s {"text": "this is obfuscated", "obfuscated": true}
25 |
26 | # "color"
27 | tellraw @s {"color": "black"}
28 | tellraw @s {"color": "dark_blue"}
29 | tellraw @s {"color": "dark_green"}
30 | tellraw @s {"color": "dark_aqua"}
31 | tellraw @s {"color": "dark_red"}
32 | tellraw @s {"color": "dark_purple"}
33 | tellraw @s {"color": "gold"}
34 | tellraw @s {"color": "gray"}
35 | tellraw @s {"color": "dark_gray"}
36 | tellraw @s {"color": "blue"}
37 | tellraw @s {"color": "green"}
38 | tellraw @s {"color": "aqua"}
39 | tellraw @s {"color": "red"}
40 | tellraw @s {"color": "light_purple"}
41 | tellraw @s {"color": "yellow"}
42 | tellraw @s {"color": "white"}
43 |
44 | # "extra"
45 | tellraw @s {"extra": []}
46 | tellraw @s {"extra": ["hello"]}
47 | tellraw @s {"extra": ["hello", "world"]}
48 | tellraw @s {"extra": [{"text": "hello world"}]}
49 | tellraw @s {"extra": [{"text": "hello \" world"}]}
50 | tellraw @s {"extra": [{"extra": ["nested"]}]}
51 | tellraw @s {"extra": [{"extra": [{"extra": ["nested again"]}]}]}
52 |
53 | # "translate" and "with"
54 | tellraw @s {"translate": "gui.toTitle"}
55 | tellraw @s {"translate": "Text inserted here"}
56 | tellraw @s {"translate": "commands.generic.entity.invalidType", "with": ["Creeper"]}
57 | tellraw @s {"translate": "Insert a %s here.", "with": ["STRING"]}
58 | tellraw @s {"translate": "custom.key", "with": ["STRING1", "STRING2"]}
59 | tellraw @s {"translate": "Nearest player: %s", "with": [{"selector": "@p"}]}
60 |
61 | # "keybind"
62 | tellraw @s {"keybind": "key.drop"}
63 |
64 | # "selector"
65 | tellraw @s {"selector": ""}
66 | tellraw @s {"selector": "Arcensoth"}
67 | tellraw @s {"selector": "f7a39418-72ca-4bf2-bc7e-ba9df67a4707"}
68 | tellraw @s {"selector": "@s"}
69 | tellraw @s {"selector": "@e[sort=nearest, limit=1]"}
70 |
71 | # "insertion"
72 | tellraw @s {"insertion": "hello world"}
73 | tellraw @s {"insertion": "/execute as @a run say hello @e[sort=nearest, limit=1]"}
74 |
75 | # "score"
76 | tellraw @s {"score": {"name": "@p", "objective": "TEST"}}
77 | tellraw @s {"score": {"name": "*", "objective": "TEST"}}
78 | tellraw @s {"score": {"name": "@p", "objective": "TEST", "value": 123}}
79 | tellraw @s {"score": {"name": "@p", "objective": "TEST", "value": -123}}
80 | tellraw @s {"score": {"name": "@p", "objective": "TEST", "value": 3.14}}
81 | tellraw @s {"score": {"name": "@p", "objective": "TEST", "value": true}}
82 | tellraw @s {"score": {"name": "@p", "objective": "TEST", "value": "hello world"}}
83 | tellraw @s {"score": {"name": "@e[sort=nearest, limit=1]", "objective": "TEST", "value": "hello"}}
84 | tellraw @s {"score": {"name": "#temp", "objective": "TEST"}}
85 | tellraw @s {"score": {"name": "$mypack.calc", "objective": "TEST"}}
86 |
87 | # "clickEvent"
88 | tellraw @s {"text": "Click", "clickEvent": {"action": "open_url", "value": "http://google.com"}}
89 | tellraw @s {"text": "Click", "clickEvent": {"action": "run_command", "value": "/say Must be OP'd to run this command"}}
90 | tellraw @s {"text": "Click", "clickEvent": {"action": "suggest_command", "value": "Text replaced"}}
91 |
92 | # "hoverEvent"
93 | tellraw @s {"text": "Hover", "hoverEvent": {"action": "show_text", "value": "Basic string"}}
94 | tellraw @s {"text": "Hover", "hoverEvent": {"action": "show_text", "value": ["", { "text": "Text\n", "color": "green", "underlined": true}, "component"]}}
95 | tellraw @s {"text": "Hover", "hoverEvent": {"action": "show_entity", "value": "{name: \"Skylinerw\", type: \"Creeper\", id: \"00000000-0000-0000-0000-000000000000\"}"}}
96 | tellraw @s {"text": "Hover", "hoverEvent": {"action": "show_entity", "value": "{name: \"Skylinerw\", id: \"Not a valid UUID\"}"}}
97 | tellraw @s {"text": "Hover", "hoverEvent": {"action": "show_item", "value": "{id: \"minecraft:stone\", Count: 1b, tag: {display: {Lore: [\"\\\"Lore line 1\\\"\", \"\\\"Lore line 2\\\"\"]}}}"}}
98 | tellraw @s {"text": "Hover", "hoverEvent": {"action": "show_item", "value": "{id: 'minecraft:stone', Count: 1b, tag: {display: {Lore: ['\"Lore line 1\"', '\"Lore line 2\"']}}}"}}
99 |
100 | # "nbt", "entity", "block", and "interpret"
101 | tellraw @s {"entity": "@s", "nbt": "SelectedItem"}
102 | tellraw @s {"entity": "@s", "nbt": "SelectedItem.tag"}
103 | tellraw @s {"entity": "@e[sort=nearest, limit=1]", "nbt": "SelectedItem.tag.display"}
104 | tellraw @s {"entity": "@s", "nbt": "SelectedItem.tag.display.Name", "interpret": true}
105 | tellraw @s {"block": "~ ~-1 ~", "nbt": "RecordItem"}
106 | tellraw @s {"block": "~ ~-1 ~", "nbt": "RecordItem.tag"}
107 | tellraw @s {"block": "~ ~-1 ~", "nbt": "RecordItem.tag.display"}
108 | tellraw @s {"block": "10 20 30", "nbt": "RecordItem"}
109 | tellraw @s {"block": "10 ~20 30", "nbt": "RecordItem"}
110 | tellraw @s {"block": "10 ~ 30", "nbt": "RecordItem"}
111 | tellraw @s {"block": "~10 20 ~30", "nbt": "RecordItem"}
112 | tellraw @s {"block": "~10 ~20 ~30", "nbt": "RecordItem"}
113 | tellraw @s {"block": "~ ~ ~", "nbt": "RecordItem"}
114 | tellraw @s {"block": "^10 ^20 ^30", "nbt": "RecordItem"}
115 | tellraw @s {"block": "^10 ^ ^30", "nbt": "RecordItem"}
116 |
117 | # nested lists
118 | tellraw @s ["Hello ", {"selector": "@e[sort=nearest, limit=1]"}, ", how are you?"]
119 | tellraw @s ["Hello ", {"selector": "@e[sort=nearest, limit=1]"}, ", how are you?"]
120 | tellraw @s ["a", ["b", {"text": "c"}, ["d"], "e"]]
121 | tellraw @s ["a", ["b", {"text": "c"}, ["d"], "e"], {"text":"f", "extra": [{"text": "g"}]}]
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # syntax-mcfunction
4 |
5 |
6 | A syntax definition for Minecraft Commands.
7 |
8 | Give this repo a ⭐ if you like it!
9 |
10 |
11 | 
12 |
13 | This project contains syntax definitions for Minecraft commands (`.mcfunction`) using the textmate grammer spec. It is a general, feature complete language spec built via generic syntatical components that describe the language (aka, mimimal hardcoded command support). This means it should support future game versions, many modded commands, and even custom language compilers such as [bolt](https://github.com/mcbeet/bolt) and [jmc](https://jmc.wingedseal.com/).
14 |
15 | > [!Warning]
16 | > This syntax does **not** contain any error highlighting meaning invalid commands will highlight correctly. If you are looking error validation and auto-complete for vanilla commands, we recommend the [Spyglass](https://spyglassmc.com/) project for a language-server that builds upon this simple grammar!
17 |
18 | ## Installing
19 |
20 | ### [VSCode Extension](https://marketplace.visualstudio.com/items?itemName=MinecraftCommands.syntax-mcfunction)
21 |
22 | Install the extension from the [marketplace](https://marketplace.visualstudio.com/items?itemName=MinecraftCommands.syntax-mcfunction) or by searching for `syntax-mcfunction` in the extensions tab.
23 |
24 | ### [open-vsix Extension](https://open-vsx.org/extension/MinecraftCommands/syntax-mcfunction)
25 |
26 | Follow these [instructions](https://github.com/eclipse/openvsx/wiki/Using-Open-VSX-in-VS-Code) if you are looking on using the open-vsix version of this project in VSCode or any of it's forks.
27 |
28 | ### Sublime Text
29 |
30 | It is recommended you use [Package Control](https://packagecontrol.io/) to manage the package:
31 |
32 | 1. [Install Package Control](https://packagecontrol.io/installation) if it is not already present.
33 | 2. Run the `Package Control: Add Repository` [command](https://packagecontrol.io/docs/usage) and enter `https://github.com/MinecraftCommands/syntax-mcfunction.git` to add the repository as a package.
34 | 3. Run the `Package Control: Install Package` and search for `syntax-mcfunction` to install it as you would a normal package.
35 |
36 | If you already had language-mcfunction
37 |
38 | > **Note**
39 | > You might want to remove Arc's language-mcfunction if you have it installed. You can do that via `Package Control: Remove Repository` and selecting https://github.com/Arcensoth/language-mcfunction then `Package Control: Remove Package` and selecting `language-mcfunction` from 2021.
40 |
41 |
42 |
43 | This will keep the package updated with the repository automatically.
44 |
45 | Otherwise you can clone the repository into user packages (e.g. `%appdata%\Sublime Text 3\Packages`) and update it manually.
46 |
47 | ## `language-mcfunction`
48 |
49 | While this grammar was created from scratch, much of it's work was adapted from the original [`language-mcfunction`](https://github.com/arcensoth/language-mcfunction) grammar. One of the original ideas for `language-mcfunction` was to develop a general, simpler version for `mcfunction`.
50 |
51 | > [!Note]
52 | > Actually, an earlier prototype of this grammar was going to be used as a base for a `language-mcfunction` rewrite.
53 |
54 | There are some key differences to note between this syntax and the original:
55 | - `language-mcfunction` is designed to operate on singular lines. If one line is broken, it does not affect lines after it and commands **cannot** span across multiple lines at all.
56 | - This was the core issue that caused me to develop `syntax-mcfunction` (even before Minecraft 1.20.2 introduced multi-line commands) as I needed a grammar that had multi-line support.
57 | - `language-mcfunction` contains specific commands validation and reports errors for invalid commands
58 | - `syntax-mcfunction` differs in philosophy here. Textmate grammars are not well-equipped to actually validate commands — that's more of a role for language servers.
59 | - This project also generally highlights commands as it allows for easier maintenance and is better for platforms such as Github where multiple command extensions / modded commands might reuse the `.mcfunction` extension.
60 |
61 | Due to these, coloring and highlighting will vary in a couple of places when comparing these grammars. While the goal is to match `language-mcfunction` as close as possible, there will never be a true 1:1 match in highlighting as the entire design of the grammar differs.
62 |
63 | ## Contributing
64 |
65 | We are happy to accept any PRs just make sure to make a cooresponding issue first to track it. When making a PR, make sure the branch of your fork is **not** `main` and also make sure maintainers are allowed to edit your PR. This is helpful for me making small edits to the PR before merging.
66 |
67 | We only require edits to the `yaml` file as the `json` and `plist` files are generated. You can use the npm package, `js-yaml`, to generate the `json` file after editting the `yaml` file.
68 |
69 | ```bash
70 | npx js-yaml mcfunction.tmLanguage.yaml > mcfunction.tmLanguage.json
71 | ```
72 |
73 | ### Making Releases
74 |
75 | Releases are semi-automated in this repo. Once your PR is merged into the `main` branch, the maintainer will create a new tag to trigger our Github CI to produce a new version.
76 |
77 | ```bash
78 | git tag -a v1.2.3
79 | git push --tags
80 | ```
81 |
82 | This will generate the json and plist variations of the grammar, create and push a `.vsix` extension to the VSCode and open-vsix marketplaces, and create a release in the [releases](https://github.com/MinecraftCommands/syntax-mcfunction/releases) tab.
83 |
84 | The maintainer will then need to manually fill in the body of the release to add in the changelog and links.
85 |
86 | ## Acknowledgements
87 |
88 | This repo is entirely dedicated to our beloved community member and friend, [Arcensoth](https://github.com/Arcensoth). His work on the original [language-mcfunction](https://github.com/Arcensoth/language-mcfunction) and overall contributions to the Minecraft Commands community was invaluable and he will be missed.
89 |
90 | > Rest in Peace, Arcensoth
91 |
--------------------------------------------------------------------------------
/tests/vanilla.mcfunction:
--------------------------------------------------------------------------------
1 | #> Example of base game commands
2 | #
3 | # Casts a ray from starting position along a configurable number
4 | # of blocks with a confugrable accuracy, counting the number of
5 | # entities hit by the ray along the way.
6 | #
7 | # @params
8 | # $mypack.raycast.distance param
9 | # The number of blocks to cast forward.
10 | # $mypack.raycast.precision param
11 | # The ratio of block precision to a full block.
12 | #
13 | # @returns
14 | # $mypack.raycast.result return
15 | # The number of entities hit by the ray.
16 | # Caching handled by storage:location/over/here
17 |
18 | function #mypack:hooks/raycast/begin
19 |
20 | function mypack:raycast/loop
21 |
22 | function #mypack:hooks/raycast/end
23 |
24 | # this is a comment
25 | say hello world
26 |
27 | # indented comment
28 | say hello indent
29 |
30 | effect give @s minecraft:night_vision 999999 1 true
31 | effect give @s minecraft:night_vision 999999 1 false
32 |
33 | teleport 1 2 3
34 | teleport 100.5 80 -100.5
35 |
36 | execute if score @a temp matches 10.. run
37 | execute if score @a temp matches ..20 run
38 | execute if score @a temp matches 10..20 run
39 |
40 | execute positioned 10 ~ -10 run
41 | execute positioned 10 ~10 -10 run
42 | execute positioned 10 ~0.5 -10 run
43 | execute positioned 10 ~.5 -10 run
44 | execute positioned 10 ~-10 -10 run
45 | execute positioned 10 ~-0.5 -10 run
46 | execute positioned 10 ~-.5 -10 run
47 |
48 | execute positioned 10 ^ -10 run
49 | execute positioned 10 ^10 -10 run
50 | execute positioned 10 ^0.5 -10 run
51 | execute positioned 10 ^.5 -10 run
52 | execute positioned 10 ^-10 -10 run
53 | execute positioned 10 ^-0.5 -10 run
54 | execute positioned 10 ^-.5 -10 run
55 |
56 | function mypack:foo
57 | function mypack:foo/bar
58 | function mypack:foo/bar/baz
59 | function #mypack:foo
60 | function #mypack:foo/bar
61 | function #mypack:foo/bar/baz
62 |
63 | execute if block ~ ~ ~ minecraft:oak_log[axis=x] run
64 | execute if block ~ ~ ~ minecraft:oak_leaves[distance=5] run
65 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent=true] run
66 | execute if block ~ ~ ~ minecraft:oak_leaves[persistent=false] run
67 | execute if block ~ ~ ~ minecraft:oak_leaves[distance=5,persistent=true] run
68 | execute if block ~ ~ ~ #minecraft:leaves[distance=5] run
69 | execute if block ~ ~ ~ #minecraft:leaves[distance=5,persistent=true] run
70 | setblock ~ ~ ~ mypack:foo{foo:bar} destroy
71 | setblock ~ ~ ~ mypack:foo{foo: bar} destroy
72 | setblock ~ ~ ~ mypack:foo[facing=up]{foo: bar} destroy
73 | setblock ~ ~ ~ mypack:foo[facing = up]{foo: bar} destroy
74 | setblock ~ ~ ~ minecraft:dispenser[facing=up]{Items: [{id: "minecraft:diamond", Count: 1}]}
75 |
76 | tag @s add my.tag
77 |
78 | datapack enable "hello world"
79 | datapack enable "escape \" me"
80 | datapack enable 'hello world'
81 | datapack enable 'escape \' me'
82 |
83 | execute as f7a39418-72ca-4bf2-bc7e-ba9df67a4707 run
84 | execute as 0-0-0-0-0 run
85 |
86 | execute store result score #fakeplayer
87 | execute store result score #fake.player
88 | execute store result score #fake_player
89 | execute store result score $fakeplayer
90 | execute store result score %fakeplayer
91 |
92 | execute as @b
93 | execute as @a
94 |
95 | execute as @a[tag=foo]
96 | execute as @a[tag=!foo]
97 |
98 | execute as @a[sort=nearest] run
99 | execute as @a[gamemode=survival] run
100 | execute as @a[gamemode=!creative] run
101 | execute as @a[tag=foo,tag=bar,tag=!baz] run
102 |
103 | execute as @a[distance=15]
104 | execute as @a[distance=1.5]
105 | execute as @a[distance=.5]
106 | execute as @a[distance=-.25]
107 |
108 | execute as @a[distance=100]
109 | execute as @a[distance=..10]
110 | execute as @a[distance=11..19]
111 | execute as @a[distance=20..]
112 | execute as @a[distance=0.5]
113 | execute as @a[distance=..0.1]
114 | execute as @a[distance=0.2..0.8]
115 | execute as @a[distance=0.9..]
116 |
117 | execute as @a[type=minecraft:bat] run
118 | execute as @a[type=!minecraft:cow,type=!minecraft:pig] run
119 | execute as @a[type=#minecraft:skeletons] run
120 | execute as @a[type=!#minecraft:skeletons,type=!minecraft:zombie] run
121 |
122 | execute as @a[tag=my.tag] run
123 |
124 | execute as @a[name="hello world"] as @s run
125 | execute as @a[name="escape \" me"] as @s run
126 | execute as @a[name="how, about, commas ?"] as @s run
127 | execute as @a[name="and [braces] ?"] as @s run
128 |
129 | execute as @e[nbt={ PortalCooldown: 0 }] run
130 | execute as @e[nbt={ Item: {id: "minecraft:diamond", Count: 64 } }] run
131 |
132 | execute if score @s foo < @s bar run
133 | execute if score @s foo <= @s bar run
134 | execute if score @s foo = @s bar run
135 | execute if score @s foo > @s bar run
136 | execute if score @s foo >= @s bar run
137 |
138 | data get entity @s SelectedItem.tag.display.Name
139 | data get entity @s Inventory[0]
140 | data get entity @s Inventory[{id: "minecraft:diamond"}].Count
141 | data get entity @s Inventory[].tag{custom: true}.display.Name
142 |
143 | data merge entity @s { foo: true, bar: 1234 }
144 | data modify block ~ ~ ~ RecordItem.tag set value { messages: [hi, bye] }
145 | data modify block ~ ~ ~ RecordItem.tag.messages append value [ { message: "hello world" } ]
146 |
147 | tellraw @a {"text": "hello world", "color": "blue"}
148 | tellraw @a [{"text": "hello", "color": "blue"}, {"text": "world", "color": "blue"}]
149 |
150 | execute as @a[scores={myscore=10}] run
151 | execute as @a[scores={myscore=10..12}] run
152 | execute as @a[scores={foo=10, bar=1..5, baz=..0}] run
153 |
154 | execute as @a[advancements={minecraft:story/form_obsidian=true}] run
155 | execute as @a[advancements={minecraft:story/obtain_armor={iron_helmet=true}}] run
156 | execute as @a[advancements={minecraft:story/obtain_armor={iron_helmet=true, gold_helmet=false}}] run
157 | execute as @a[advancements={minecraft:story/form_obsidian=true, minecraft:story/follow_ender_eye=true}] run
158 | execute as @a[advancements={minecraft:story/form_obsidian={foo=true, bar=false},minecraft:story/follow_ender_eye={foo=false, bar=true}}] run
159 |
160 | give @s diamond_sword{display: {Name: '"My Custom Sword"'}}
161 | give @s minecraft:diamond_sword{display: {Name: '"My Custom Sword"'}}
162 |
163 | execute if score @s foo < @s bar run say execute if score @s foo < @s bar run say
164 | execute if score @s foo < @s bar run say hello @e[tag=baz, sort=nearest, limit=1] how are you?
165 |
166 | scoreboard players operation @a result \
167 | += @e[type=marker,limit=1,tag=source] value
168 | $data modify storage $(id) $(path) set value "with random $(string1) stuff $(string2)"
169 |
170 | give @n armor_stand[entity_data={id:"minecraft:armor_stand", Tags:[taco_sauce]}]
171 |
172 | say -1L -1l -1S -1s -1 0 1 1b 1s 1S 1l 1L
173 |
174 | say "Something" Something
175 |
176 | give @s taco[minecraft:unbreaking]
177 |
--------------------------------------------------------------------------------
/tests/comprehensive/selector.mcfunction:
--------------------------------------------------------------------------------
1 | # test valid
2 | execute as @b
3 | execute as @a
4 | execute as @a[]
5 | execute as @a[tag=foo]
6 | execute as @a[tag=!foo]
7 |
8 | # test valid with trailing command
9 | execute as @a run
10 | execute as @a[] run
11 | execute as @a[tag=foo] run
12 | execute as @a[tag=!foo] run
13 |
14 | # test valid with mixed selectors
15 | execute as @a as @a run
16 | execute as @a as @a[sort=nearest] run
17 | execute as @a[sort=nearest] as @a run
18 | execute as @a[sort=nearest] as @a[sort=nearest] run
19 | teleport @a @s
20 |
21 | # test valid multiple arguments
22 | execute as @a[sort=nearest,limit=1] run
23 | execute as @a[sort=nearest,limit=1] run
24 | execute as @a[sort=nearest,limit=1,distance=0] run
25 | execute as @a[sort=nearest,tag=!foo,tag=bar] run
26 |
27 | # test valid whitespace around arguments
28 |
29 | execute as @a[sort=nearest] run
30 | execute as @a[ sort=nearest] run
31 | execute as @a[sort=nearest ] run
32 | execute as @a[ sort=nearest ] run
33 |
34 | execute as @a[sort=nearest,limit=1] run
35 | execute as @a[ sort=nearest,limit=1] run
36 | execute as @a[sort=nearest,limit=1 ] run
37 | execute as @a[ sort=nearest,limit=1 ] run
38 |
39 | execute as @a[sort=nearest, limit=1] run
40 | execute as @a[ sort=nearest, limit=1] run
41 | execute as @a[sort=nearest, limit=1 ] run
42 | execute as @a[ sort=nearest, limit=1 ] run
43 |
44 | execute as @a[sort=nearest ,limit=1] run
45 | execute as @a[ sort=nearest ,limit=1] run
46 | execute as @a[sort=nearest ,limit=1 ] run
47 | execute as @a[ sort=nearest ,limit=1 ] run
48 |
49 | execute as @a[sort=nearest , limit=1] run
50 | execute as @a[ sort=nearest , limit=1] run
51 | execute as @a[sort=nearest , limit=1 ] run
52 | execute as @a[ sort=nearest , limit=1 ] run
53 |
54 | execute as @a[ sort =nearest , limit=1 ] run
55 | execute as @a[ sort= nearest , limit=1 ] run
56 | execute as @a[ sort = nearest , limit=1 ] run
57 |
58 | execute as @a[ tag = foo , limit = 1 ] run
59 | execute as @a[ tag = ! foo , limit = 1 ] run
60 |
61 | # test valid arguments in separate selectors
62 | execute as @a[sort=nearest] as @s[tag=foo] run
63 | execute as @a[sort=nearest,limit=1] as @a[tag=foo] run
64 | execute as @a[sort=nearest] as @a[tag=foo,tag=bar] run
65 | execute as @a[sort=nearest,limit=1] as @a[tag=foo,tag=bar] run
66 |
67 | # test valid resource location argument
68 | execute as @a[type=minecraft:bat] run
69 | execute as @a[ type = minecraft:bat ] run
70 | execute as @a[ type = ! minecraft:bat ] run
71 | execute as @a[type=minecraft:bat,tag=foo] run
72 | execute as @a[tag=foo,type=minecraft:bat] run
73 | execute as @a[tag=foo,type=minecraft:bat,tag=foo] run
74 |
75 | # test valid tagged resource location argument
76 | execute as @a[type=#minecraft:skeletons] run
77 | execute as @a[ type = #minecraft:skeletons ] run
78 | execute as @a[ type = ! #minecraft:skeletons ] run
79 | execute as @a[type=#minecraft:skeletons,tag=foo] run
80 | execute as @a[tag=foo,type=#minecraft:skeletons] run
81 | execute as @a[tag=foo,type=#minecraft:skeletons,tag=foo] run
82 |
83 | # test valid range argument
84 | execute as @a[distance=..10]
85 | execute as @a[distance=11..19]
86 | execute as @a[distance=20..]
87 | execute as @a[distance=0.5]
88 | execute as @a[distance=..0.1]
89 | execute as @a[distance=0.2..0.8]
90 | execute as @a[distance=0.9..]
91 | execute as @a[tag=foo,distance=1..,tag=bar]
92 | execute as @a[ tag = foo , distance = 1.. , tag = bar ]
93 |
94 | # test valid number argument
95 | execute as @a[distance=15]
96 | execute as @a[distance=1.5]
97 | execute as @a[distance=.5]
98 | execute as @a[distance=-.25]
99 | execute as @a[tag=foo,distance=-.25,tag=bar]
100 | execute as @a[ tag = foo , distance = -.25 , tag = bar ]
101 |
102 | # test valid boolean argument (were it to exist)
103 | execute as @a[somekey=true]
104 | execute as @a[somekey=false]
105 | execute as @a[ somekey = true ]
106 | execute as @a[tag=foo,somekey=true,tag=bar]
107 | execute as @a[ tag = foo , somekey = true , tag = bar ]
108 |
109 | # test valid literal argument
110 | execute as @a[sort=nearest] run
111 | execute as @a[tag=foo,sort=nearest,tag=bar] run
112 | execute as @a[ tag = foo , sort = nearest , tag = bar ] run
113 |
114 | # test valid unquoted string argument
115 | execute as @a[tag=my.custom.tag] run
116 | execute as @a[tag=foo,tag=my.custom.tag,tag=bar] run
117 | execute as @a[ tag = foo , tag = my.custom.tag , tag = bar ] run
118 |
119 | # test valid quoted string argument
120 | execute as @a[tag=foo,name="[",tag=bar] as @s run
121 | execute as @a[tag=foo,name="]",tag=bar] as @s run
122 | execute as @a[tag=foo,name="[]",tag=bar] as @s run
123 | execute as @a[tag=foo,name="[[]]",tag=bar] as @s run
124 | execute as @a[tag=foo,name="foo, bar"] as @s run
125 | execute as @a[tag=foo,name="escaped \" quote"] as @s run
126 | execute as @a[ tag = foo , name = " lots of space " , tag = bar ] as @s run
127 |
128 | # test valid single quoted string argument
129 | execute as @a[tag=foo,name='[',tag=bar] as @s run
130 | execute as @a[tag=foo,name=']',tag=bar] as @s run
131 | execute as @a[tag=foo,name='[]',tag=bar] as @s run
132 | execute as @a[tag=foo,name='[[]]',tag=bar] as @s run
133 | execute as @a[tag=foo,name='foo, bar'] as @s run
134 | execute as @a[tag=foo,name='escaped \' quote'] as @s run
135 | execute as @a[ tag = foo , name = ' lots of space ' , tag = bar ] as @s run
136 |
137 | # test valid nbt argument
138 | execute as @e[nbt={PortalCooldown:0}] run
139 | execute as @e[nbt={ PortalCooldown : 0 }] run
140 | execute as @e[ nbt = { PortalCooldown : 0 } ] run
141 | execute as @e[nbt={Item:{id:"minecraft:diamond",Count:64}}] run
142 | execute as @e[nbt={ Item : { id : "minecraft:diamond", Count : 64 } }] run
143 | execute as @e[ nbt = { Item : { id : "minecraft:diamond" , Count : 64 } } ] run
144 |
145 | # test valid scores argument
146 | execute as @a[scores={myscore=10}] run
147 | execute as @a[scores={myscore=10..12}] run
148 | execute as @a[scores={myscore=5..}] run
149 | execute as @a[scores={myscore=..15}] run
150 | execute as @a[scores={foo=10,bar=1..5}] run
151 | execute as @a[scores={foo=10,bar=1..5,baz=..0}] run
152 | execute as @a[ scores = {foo=10,bar=1..5,baz=..0} ] run
153 | execute as @a[ scores = { foo = 10 , bar = 1..5 , baz = ..0 } ] run
154 | execute as @a[scores={my.score=10}] run
155 | execute as @a[scores={myScore=10}] run
156 |
157 | # test valid advancements argument
158 | execute as @a[advancements={minecraft:story/form_obsidian=true}] run
159 | execute as @a[advancements={minecraft:story/form_obsidian=false}] run
160 | execute as @a[advancements={minecraft:story/obtain_armor={iron_helmet=true}}] run
161 | execute as @a[advancements={minecraft:story/obtain_armor={iron_helmet=true, gold_helmet=false}}] run
162 | execute as @a[ advancements = { minecraft:story/obtain_armor = { iron_helmet = true , gold_helmet = false } } ] run
163 | execute as @a[advancements={minecraft:story/follow_ender_eye=true}] run
164 | execute as @a[advancements={minecraft:story/form_obsidian=true,minecraft:story/follow_ender_eye=true}] run
165 | execute as @a[advancements={minecraft:story/form_obsidian=true,minecraft:story/follow_ender_eye=true,minecraft:story/obtain_armor=true}] run
166 | execute as @a[advancements={minecraft:story/form_obsidian={foo=true, bar=false},minecraft:story/follow_ender_eye={foo=false, bar=true}}] run
167 | execute as @a[ advancements = {minecraft:story/follow_ender_eye=true} ] run
168 | execute as @a[ advancements = { minecraft:story/follow_ender_eye = true } ] run
169 | execute as @a[ advancements = { minecraft:story/form_obsidian = true , minecraft:story/follow_ender_eye = true , minecraft:story/obtain_armor = true } ] run
170 |
171 | # test invalid edge cases
172 | execute as @a[,] as @s run
173 | execute as @a[,,] as @s run
174 | execute as @a[,tag=foo] as @s run
175 | execute as @a[tag=foo,] as @s run
176 | execute as @a[,tag=foo,] as @s run
177 | execute as @a[tag,=foo] as @s run
178 | execute as @a[tag=,foo] as @s run
179 | execute as @a[tag,=,foo] as @s run
180 | execute as @a[,tag,=,foo,] as @s run
181 | execute as @a[tag=foo,name="[[]]"],tag=bar] as @s run
182 |
183 | # test invalid
184 | execute as @
185 | execute as @A
186 | execute as @ab
187 | execute as @0
188 | execute as @_
189 | execute as @a[
190 | execute as @a]
191 |
192 | # test invalid with trailing command
193 | execute as @ run
194 | execute as @a[ run
195 | execute as @a] run
196 |
197 | # test invalid basic arguments
198 | execute as @a[sort] run
199 | execute as @a[sort=] run
200 | execute as @a[=nearest] run
201 |
202 | # test invalid quoted string argument
203 | execute as @a[name=my name] run
204 | execute as @a[name="my name] run
205 | execute as @a[name=my name"] run
206 | ]]
207 |
208 | # test invalid resource location argument
209 | execute as @a[type=mypack:] run
210 | execute as @a[type=:foo] run
211 | execute as @a[type=#mypack:] run
212 | execute as @a[type=#:foo] run
213 | ]
214 |
215 | # test invalid edge cases
216 | execute as @a[gamemode=survival,]] run
217 |
--------------------------------------------------------------------------------
/mcfunction.tmLanguage.yaml:
--------------------------------------------------------------------------------
1 | name: Syntax Mcfunction
2 |
3 | scopeName: source.mcfunction
4 | uuid: 8918dadd-8ebe-42d9-b1e9-0489ab228d9d
5 |
6 | fileTypes:
7 | - mcfunction
8 | - bolt
9 |
10 | patterns:
11 | - include: "#root"
12 |
13 | repository:
14 | root:
15 | patterns:
16 | - include: "#literals"
17 | - include: "#comments"
18 | - include: "#say"
19 | - include: "#names" # we do names before inline since inline comments can eat
20 | - include: "#comments_inline"
21 | - include: "#subcommands"
22 | - include: "#property"
23 | - include: "#operators" # ideally not so low but this eats into fakeplayers
24 | - include: "#selectors"
25 |
26 | # Comments have two styles
27 | # 1. Basic `# comment`, single line
28 | # 2. `#>`, etc. block comments
29 | #
30 | # We provide a subset of command highlighting within comments to enable
31 | # docstring-esque type highlighting
32 | comments:
33 | patterns:
34 | - applyEndPatternLast: 1
35 | begin: ^\s*(#[>!#])(.+)$
36 | beginCaptures:
37 | "1":
38 | name: comment.block.mcfunction
39 | "2":
40 | name: markup.bold.mcfunction
41 | captures:
42 | "0":
43 | name: comment.block.mcfunction
44 | end: ^(?!#)
45 | name: meta.comments
46 | patterns:
47 | - include: "#comments_block"
48 | - captures:
49 | "0":
50 | name: comment.line.mcfunction
51 | match: '^\s*#.*$'
52 | name: meta.comments
53 |
54 | # `execute if entity @a run tellraw "hello" # cool command here`
55 | # ^^^^^^^^^^^^^^^^^^^
56 | comments_inline:
57 | patterns:
58 | - captures:
59 | "0":
60 | name: comment.line.mcfunction
61 | match: "#.*$"
62 | name: meta.comments
63 |
64 | comments_block:
65 | patterns:
66 | - applyEndPatternLast: 1
67 | begin: ^\s*#[>!]
68 | captures:
69 | "0":
70 | name: comment.block.mcfunction
71 | end: $
72 | name: meta.comments_block
73 | patterns:
74 | - include: "#comments_block_emphasized"
75 | - applyEndPatternLast: 1
76 | begin: ^\s*#
77 | captures:
78 | "0":
79 | name: comment.block.mcfunction
80 | end: $
81 | name: meta.comments_block
82 | patterns:
83 | - include: "#comments_block_normal"
84 |
85 | # Header comments (just bolded)
86 | # `#> This function does cool things`
87 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
88 | comments_block_emphasized:
89 | patterns:
90 | - include: "#comments_block_special"
91 | - captures:
92 | "0":
93 | name: markup.bold.mcfunction
94 | match: \S+
95 | name: meta.comments_block_emphasized
96 |
97 | #> Normal comments within a comment block
98 | comments_block_normal:
99 | patterns:
100 | - include: "#comments_block_special"
101 | - captures:
102 | "0":
103 | name: comment.block.mcfunction
104 | match: \S+
105 | name: meta.comments_block_normal
106 | - include: "#whitespace"
107 |
108 | # Special highlighting for resource locations and params
109 | # `# Taco Bell @rx97`
110 | # ^^^^^
111 | # `# Caching handled by storage:location/over/here`
112 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^
113 | # `# $mypack.raycast.result return`
114 | # ^^^^^^^^^^^^^^^^^^^^^^
115 | comments_block_special:
116 | patterns:
117 | - captures:
118 | "0":
119 | name: markup.heading.mcfunction
120 | match: '@\S+'
121 | name: meta.comments_block_special
122 | - include: "#resource-name"
123 | - captures:
124 | "0":
125 | name: variable.other.mcfunction
126 | match: "[#%$][A-Za-z0-9_.#%$]+"
127 | name: meta.comments_block_special
128 |
129 | # Literals encompasses numbers, booleans, UUIDs, and strings
130 | literals:
131 | patterns:
132 | - captures:
133 | "0":
134 | name: constant.numeric.boolean.mcfunction
135 | match: \b(true|false|True|False)\b
136 | name: meta.literals
137 | - captures:
138 | "0":
139 | name: variable.uuid.mcfunction
140 | match: \b[0-9a-fA-F]+(?:-[0-9a-fA-F]+){4}\b
141 | name: meta.names
142 | - captures:
143 | "0":
144 | name: constant.numeric.float.mcfunction
145 | match: '[+-]?\d*\.?\d+([eE]?[+-]?\d+)?[df]?\b'
146 | name: meta.literals
147 | - captures:
148 | "0":
149 | name: constant.numeric.integer.mcfunction
150 | match: '[+-]?\d+(b|B|L|l|s|S)?\b'
151 | name: meta.literals
152 |
153 | # yea this should be operator, but i need this to exist before #names
154 | # otherwise `..0.5` will be a valid name
155 | - captures:
156 | "0":
157 | name: variable.other.mcfunction
158 | match: \.\.
159 | name: meta.ellipse.literals
160 |
161 | # Strings will encompass multiple lines meaning an unclosed quote will
162 | # eat extra tokens.
163 | - applyEndPatternLast: 1
164 | begin: '"'
165 | beginCaptures:
166 | "0":
167 | name: punctuation.definition.string.begin.mcfunction
168 | end: '"'
169 | endCaptures:
170 | "0":
171 | name: punctuation.definition.string.end.mcfunction
172 | name: string.quoted.double.mcfunction
173 | patterns:
174 | - include: "#literals_string-double"
175 | - applyEndPatternLast: 1
176 | begin: "'"
177 | beginCaptures:
178 | "0":
179 | name: punctuation.definition.string.begin.mcfunction
180 | end: "'"
181 | endCaptures:
182 | "0":
183 | name: punctuation.definition.string.begin.mcfunction
184 | name: string.quoted.single.mcfunction
185 | patterns:
186 | - include: "#literals_string-single"
187 |
188 | # Simplistic highlighting for basic subcommands.
189 | subcommands:
190 | patterns:
191 | - captures:
192 | "0":
193 | name: entity.name.class.mcfunction
194 | match: "[a-z_]+" # "[A-Za-z_]+"
195 | name: meta.literals
196 |
197 | # Strings also have to account for `\`s esp, solo at the end of a line
198 | literals_string-double:
199 | patterns:
200 | - captures:
201 | "0":
202 | name: constant.character.escape.mcfunction
203 | match: \\.
204 | name: meta.literals_string-double
205 | - captures:
206 | "0":
207 | name: constant.character.escape.mcfunction
208 | match: \\
209 | name: meta.literals_string-double
210 | - include: "#macro-name"
211 | - captures:
212 | "0":
213 | name: string.quoted.double.mcfunction
214 | match: '[^\\"]'
215 | name: meta.literals_string-double
216 |
217 | literals_string-single:
218 | patterns:
219 | - captures:
220 | "0":
221 | name: constant.character.escape.mcfunction
222 | match: \\.
223 | name: meta.literals_string-single
224 | - captures:
225 | "0":
226 | name: constant.character.escape.mcfunction
227 | match: \\
228 | name: meta.literals_string-double
229 | - include: "#macro-name"
230 | - captures:
231 | "0":
232 | name: string.quoted.single.mcfunction
233 | match: '[^\\'']'
234 | name: meta.literals_string-single
235 |
236 | # We need to hardcode `say` to avoid greedy `'`s to break formatting
237 | # ex: `say Bob's uncle was pretty cool`, this would break commands that follow
238 | say:
239 | patterns:
240 | - begin: ^(\s*)(say)
241 | beginCaptures:
242 | "1":
243 | name: whitespace.mcfunction
244 | "2":
245 | name: keyword.control.flow.mcfunction
246 | end: \n
247 | name: meta.say.mcfunction
248 | patterns:
249 | - captures:
250 | "0":
251 | name: constant.character.escape.mcfunction
252 | match: \\\s*\n
253 | meta: meta.say.backslash.mcfunction
254 | - include: "#literals_string-double"
255 | - include: "#literals_string-single"
256 | - begin: (run)(\s+)(say)
257 | beginCaptures:
258 | "1":
259 | name: entity.name.mcfunction
260 | "2":
261 | name: whitespace.mcfunction
262 | "3":
263 | name: keyword.control.flow.mcfunction
264 | end: \n
265 | name: meta.say.mcfunction
266 | patterns:
267 | - captures:
268 | "0":
269 | name: constant.character.escape.mcfunction
270 | match: \\\s*\n
271 | meta: meta.say.backslash.mcfunction
272 | - include: "#literals_string-double"
273 | - include: "#literals_string-single"
274 |
275 | # Names are a very generic term in this grammar. They specially highlight the
276 | # beginning of a line (and a word after `run`), handle macro commands, and
277 | # fakeplayers.
278 | names:
279 | patterns:
280 | - captures:
281 | "1":
282 | name: whitespace.mcfunction
283 | "2":
284 | name: keyword.control.flow.mcfunction
285 | match: ^(\s*)([a-z_]+)(?=\s)
286 | name: meta.names
287 | - captures:
288 | "1":
289 | name: whitespace.mcfunction
290 | "2":
291 | name: markup.italic.mcfunction
292 | "3":
293 | name: whitespace.mcfunction
294 | "4":
295 | name: keyword.control.flow.mcfunction
296 | match: ^(\s*)(\$)( ?)([a-z_]*)
297 | name: meta.names
298 | - captures:
299 | "1":
300 | name: entity.name.mcfunction
301 | "2":
302 | name: whitespace.mcfunction
303 | "3":
304 | name: keyword.control.flow.mcfunction
305 | match: (run)(\s+)([a-z_]+)
306 | name: meta.names
307 | - include: "#resource-name"
308 | - captures:
309 | "0":
310 | name: entity.name.mcfunction
311 | match: '[A-Za-z]+(?=\W)'
312 | name: meta.names
313 | - captures:
314 | "0":
315 | name: string.unquoted.mcfunction
316 | match: "[A-Za-z_][A-Za-z0-9_.#%$]*"
317 | name: meta.names
318 | - include: "#macro-name"
319 | - captures:
320 | "0":
321 | name: variable.other.mcfunction
322 | match: '([#%$]|((?<=\s)\.))[A-Za-z0-9_.#%$\-]+'
323 | name: meta.names
324 |
325 | # These are for macro-names defined within a macro-line (including strings).
326 | # TODO: only activate this if the beginning of the line starts with `$`
327 | macro-name:
328 | patterns:
329 | - captures:
330 | "1":
331 | name: punctuation.definition.template-expression.begin.mcfunction
332 | "2":
333 | name: variable.other.mcfunction
334 | "3":
335 | name: punctuation.definition.template-expression.end.mcfunction
336 | match: '(\$\()([A-Za-z0-9_]*)(\))'
337 | name: meta.macro-name
338 |
339 | # General operators (including beyond mcfunction)
340 | operators:
341 | patterns:
342 | - captures:
343 | "0":
344 | name: constant.numeric.mcfunction
345 | match: "[~^]"
346 | name: meta.operators
347 | - captures:
348 | "0":
349 | name: keyword.operator.mcfunction
350 | match: '[\-%?!+*<>\\/|&=.:,;]'
351 | name: meta.operators
352 |
353 | # Properties are a subset of definitions that exist within `{}`, `[]`, or `()`s. They are a
354 | # generic formula for highlighting key-value pairs, but are also capable of doing a good job
355 | # for generic scoping (such as in mcbuild), JSON, or even python/js esque expressions. They
356 | # can be nested as many times as needed as long as the brackets match!
357 | #
358 | # Unfortuntely, there's a bit of limitations based on how strict it is with mcfunction
359 | # vs how accepting it is of foreign syntax. For example `[key:val]` and `[key: val]`
360 | # highlight very differently as either a resource-name or a key/value.
361 | #
362 | # In the future, we could attempt a stricter property key-value scheme and then fall-back
363 | # to a generic, more forgiving highlighting if the strict one fails. This would be complex
364 | # though maybe needing some lookaheads, etc which could be not worth.
365 | property:
366 | patterns:
367 | - applyEndPatternLast: 1
368 | begin: \{
369 | captures:
370 | "0":
371 | name: punctuation.mcfunction
372 | end: \}
373 | name: meta.property.curly
374 | patterns:
375 | - include: "#resource-name"
376 | - include: "#literals"
377 | - include: "#property_key"
378 | - include: "#operators"
379 | - include: "#property_value"
380 | - include: $self
381 | - applyEndPatternLast: 1
382 | begin: \[
383 | captures:
384 | "0":
385 | name: variable.other.mcfunction
386 | end: \]
387 | name: meta.property.square
388 | patterns:
389 | - include: "#resource-name"
390 | - include: "#literals"
391 | - include: "#property_key"
392 | - include: "#operators"
393 | - include: "#property_value"
394 | - include: $self
395 | - applyEndPatternLast: 1
396 | begin: \(
397 | captures:
398 | "0":
399 | name: punctuation.mcfunction
400 | end: \)
401 | name: meta.property.paren
402 | patterns:
403 | - include: "#resource-name"
404 | - include: "#literals"
405 | - include: "#property_key"
406 | - include: "#operators"
407 | - include: "#property_value"
408 | - include: $self
409 |
410 | property_key:
411 | patterns:
412 | - captures:
413 | "0":
414 | name: variable.other.mcfunction
415 | match: '#?[a-z_][a-z_\.\-]*\:[a-z0-9_\.\-/]+(?=\s*\=:)'
416 | name: meta.property_key
417 | - captures:
418 | "0":
419 | name: variable.other.mcfunction
420 | match: '#?[a-z_][a-z0-9_\.\-/]+'
421 | name: meta.property_key
422 | - captures:
423 | "0":
424 | name: variable.other.mcfunction
425 | match: '[A-Za-z_]+[A-Za-z_\-\+]*'
426 | name: meta.property_key
427 |
428 | property_value:
429 | patterns:
430 | - captures:
431 | "0":
432 | name: string.unquoted.mcfunction
433 | match: '#?[a-z_][a-z_\.\-]*\:[a-z0-9_\.\-/]+'
434 | name: meta.property_value
435 | - captures:
436 | "0":
437 | name: string.unquoted.mcfunction
438 | match: '#?[a-z_][a-z0-9_\.\-/]+'
439 | name: meta.property_value
440 |
441 | resource-name:
442 | patterns:
443 | - captures:
444 | "0":
445 | name: entity.name.function.mcfunction
446 | match: "#?[a-z_][a-z0-9_.-]*:[a-z0-9_./-]+"
447 | name: meta.resource-name
448 | - captures:
449 | "0":
450 | name: entity.name.function.mcfunction
451 | match: '#?[a-z0-9_\.\-]+\/[a-z0-9_\.\-\/]+'
452 | name: meta.resource-name
453 |
454 | # Selectors consume more than 1 char after an `@` symbol to allow for fancier
455 | # `@param` style highlighting like python decorators or even modded selectors.
456 | selectors:
457 | patterns:
458 | - captures:
459 | "0":
460 | name: support.class.mcfunction
461 | match: "@[a-z]+"
462 | name: meta.selectors
463 |
--------------------------------------------------------------------------------
/tests/bolt.mcfunction:
--------------------------------------------------------------------------------
1 | #> Example of 3rd party commands (bolt)
2 |
3 | say hello
4 | say this is a function file augmented with mecha
5 |
6 | # a = {1, 2, 3}
7 |
8 | if score @s tmp matches 1.. as @a:
9 | for feature in [
10 | "multiline",
11 | "nesting",
12 | "implicit execute",
13 | "relative location",
14 | ]:
15 | say (feature + " is automatically enabled")
16 | message = "abc" * 5
17 | say message.upper()
18 |
19 | def you_can_make_functions():
20 | say you_can_make_functions.__name__.replace("_", " ").capitalize()
21 | tellraw @a [
22 | "",
23 | {"text": "yep"},
24 | ]
25 | return "and return values"
26 |
27 | say you_can_make_functions()
28 |
29 | def fib(n):
30 | if n <= 1:
31 | return n
32 | return fib(n - 1) + fib(n - 2)
33 |
34 | say fib(7)
35 | say fib(8)
36 | say fib(9)
37 |
38 | def default_params_are_neat(
39 | number,
40 | result=fib(number),
41 | thing={
42 | "number": number,
43 | "result": result,
44 | },
45 | ):
46 | say Unlike in python default params are evaluated when the function is called
47 | say number
48 | say result
49 | say thing
50 |
51 | default_params_are_neat(12)
52 |
53 | say this is basically a custom subset of python
54 | say functions are first-class objects just like in python
55 |
56 | my_functions = []
57 |
58 | for i in "abc":
59 | def functions_in_loop(value):
60 | def yo():
61 | say value.upper()
62 | return yo
63 | my_functions.append(functions_in_loop(i * 3))
64 |
65 | my_functions[0]()
66 | my_functions[1]()
67 | my_functions[2]()
68 |
69 | should_break = False
70 |
71 | while True:
72 | if should_break:
73 | break
74 | say just once
75 | should_break = True
76 |
77 | something = '{"text": "Hello", "bold": true}'
78 | as @a at @s if block ~ ~-1 ~ #wool give @s stone{
79 | display: {
80 | Name: something
81 | }
82 | }
83 |
84 | with_tuples = ((((())))) + (1,2,3) + (4,)
85 | say with_tuples
86 | say (with_tuples)
87 | say (with_tuples,)
88 | a = f'\\'
89 | # say f"f-strings {"work".upper()!r} too {a}"
90 | # say f"{{{f"{{{f"{{{7:08}}}\\"}}}\""}}}"
91 |
92 | x = 8
93 | if score @s tmp matches (x, None) say wat
94 | if score @s tmp matches f"{x}.." say wat
95 |
96 |
97 | def copy_items(type, count):
98 | for i in range(count):
99 | item replace entity @a f"{type}.{i}" from entity @s f"{type}.{i}"
100 |
101 | copy_items('hotbar', 9)
102 | copy_items('inventory', 26)
103 |
104 | def f():
105 | yield 1
106 | yield 2
107 | yield 3
108 |
109 | for i in f():
110 | say i
111 |
112 | def wow(ok):
113 | yield from ok()
114 | yield from ok()
115 |
116 | say list(wow(f))
117 |
118 | say ctx.generate.id("hello")
119 |
120 | import math
121 | say math.cos(math.pi)
122 |
123 | import math as m
124 | say (math is m)
125 |
126 | from ./thing import do_stuff
127 |
128 | say do_stuff(1, math.pi)
129 |
130 | import ./thing as thing
131 |
132 | say (thing.do_stuff is do_stuff)
133 |
134 | for i in range(6):
135 | if i == 1:
136 | say 1
137 | elif i == 2:
138 | say 2
139 | elif i == 3:
140 | say 3
141 | else:
142 | say other
143 | say done
144 |
145 | execute
146 | as @a # For each "player",
147 | at @s # start at their feet.
148 | anchored eyes # Looking through their eyes,
149 | facing 0 0 0 # face perfectly at the target
150 | anchored feet # (go back to the feet)
151 | positioned ^ ^ ^1 # and move one block forward.
152 | rotated as @s # Face the direction the player
153 | # is actually facing,
154 | positioned ^ ^ ^-1 # and move one block back.
155 | if entity @s[distance=..0.6] function ./abc:
156 | say foo
157 | say bar
158 |
159 | baz = "demo:xyz"
160 | if predicate foo:bar function baz:
161 | say foo
162 | say bar
163 |
164 | for node in generate_tree("abcdefghijklmnopqrstuvwxyz0123456789"):
165 | append function node.parent:
166 | if node.partition(5):
167 | if score @s thingy matches node.range function node.children
168 | else:
169 | if score @s thingy matches node.range say node.value
170 |
171 | data modify entity @e[type=armor_stand,limit=1] NoBasePlate set value 1b
172 |
173 | from ./thing import call_recursive
174 | call_recursive()
175 |
176 | def try_coordinates():
177 | a = 1
178 | setblock a 2 3 stone
179 | a = "1 2 3"
180 | setblock a stone
181 | a = 1
182 | if block ^ f"^{a}" ^ #planks say 42
183 | if block ("~", "~", "~") #planks say 42
184 |
185 | try_coordinates()
186 |
187 | keyword_arguments = dict(foo=1, bar=2, **{"thing": 42})
188 | say keyword_arguments
189 |
190 | for node in generate_tree(range(8), name="small_tree"):
191 | append function node.parent:
192 | if node.partition():
193 | if score @s thingy matches node.range function node.children
194 | else:
195 | if score @s thingy matches node.range say node.value
196 |
197 | def try_unpacking():
198 | a = [1, *"abc", 2]
199 | b = dict(zip(a, a))
200 | c = {**b, "b": "thing"}
201 | say c
202 |
203 | try_unpacking()
204 |
205 | def try_set_item():
206 | try_set_item.data = {}
207 | try_set_item.data[1] = {}
208 | try_set_item.data[1][2] = "foo"
209 | say try_set_item.data
210 |
211 | try_set_item()
212 |
213 | for node in generate_tree(range(10, 20), key=int):
214 | append function node.parent:
215 | if node.partition():
216 | if score @s thingy matches node.range function node.children
217 | else:
218 | if score @s thingy matches node.range say node.value
219 |
220 | scoreboard objectives setdisplay list some_score_name
221 | color = "red"
222 | scoreboard objectives setdisplay f"sidebar.team.{color}" some_score_name
223 |
224 | weapon = {1: "weapon.offhand", 2: "weapon.mainhand"}
225 | item replace entity @s weapon.offhand from entity @s weapon.mainhand
226 | my_weapon = weapon
227 | item replace entity @s my_weapon.1 from entity @s my_weapon.2
228 |
229 | numbers = list(range(12))
230 | say numbers[:]
231 | say numbers[3:]
232 | say numbers[:9]
233 | say numbers[3:9]
234 | say numbers[::]
235 | say numbers[3::]
236 | say numbers[:9:]
237 | say numbers[3:9:]
238 | say numbers[::-1]
239 | say numbers[9::-1]
240 | say numbers[:3:-1]
241 | say numbers[9:3:-1]
242 |
243 | execute at @s if block ~ ~ ~ #minecraft:beds:
244 | teleport @s ~ ~0.56250 ~
245 |
246 | del numbers[3:]
247 | say numbers
248 |
249 | for loop, value in loop_info("abcd"):
250 | say f"==[{loop.current}]=="
251 | say (value == loop.current)
252 | say loop.before
253 | say loop.after
254 | say loop.first
255 | say loop.last
256 | say loop.cycle("foo", "bar")
257 |
258 | from ./thing import raw
259 |
260 | raw(f"say hello{'!' * 5}")
261 |
262 | execute function demo:bbb:
263 | say 1
264 | append function demo:bbb:
265 | say 2
266 | prepend function demo:bbb:
267 | say 0
268 |
269 | mykey1 = "foo"
270 |
271 | if data storage some:path/to/storage f"some.{mykey1}.path"
272 | if data storage some:path/to/storage f"some.{mykey1}.path" run say hi
273 | if data storage some:path/to/storage f'some.{mykey1}.path{{my: "compound"}}'
274 | if data storage some:path/to/storage f'some.{mykey1}.path{{my: "compound"}}' run say hi
275 |
276 | mykey2 = "bar"
277 |
278 | mypath1 = f"some.{mykey2}.path"
279 | if data storage some:path/to/storage (mypath1)
280 | if data storage some:path/to/storage (mypath1) run say hi
281 |
282 | mypath2 = f'some.{mykey2}.path{{my: "compound"}}'
283 | if data storage some:path/to/storage (mypath2)
284 | if data storage some:path/to/storage (mypath2) run say hi
285 |
286 | mypath3 = f'some.{mykey2}.path[{{my: "subscript"}}]'
287 | if data storage some:path/to/storage (mypath3)
288 | if data storage some:path/to/storage (mypath3) run say hi
289 |
290 | myindex = 42
291 |
292 | if data storage some:path/to/storage f'some.{mykey1}.path{{my: "compound"}}.stuff[{myindex}].beep.{mykey2}[{{my: "subscript"}}].boop' run say hi
293 |
294 | mypath4 = "foo.bar"
295 | if data storage some:path/to/storage mypath4
296 |
297 | if data storage some:path/to/storage "some.foo.path"
298 |
299 | import nbtlib
300 | mypath5 = nbtlib.Path().something.cool[3].foo
301 | if data storage some:path/to/storage mypath5
302 |
303 | foo = nbtlib.Byte(23)
304 | data merge storage some:path/to/storage {Count: foo}
305 |
306 | from uuid import UUID
307 |
308 | def try_entity_interpolation(x):
309 | if score x some_objective matches 0 say yes
310 |
311 | try_entity_interpolation("some_fake_player")
312 | try_entity_interpolation("0-0-0-0-1")
313 | try_entity_interpolation(UUID("12345678-1234-5678-1234-567812345678"))
314 |
315 | entity_type = "creeper"
316 | at @e[type=entity_type] summon lightning_bolt
317 |
318 | language minecraft:aaaa {
319 | "menu.singleplayer": "AAAA"
320 | }
321 |
322 | some_translation = "bonjour"
323 |
324 | merge language minecraft:aaaa {
325 | "something.else": some_translation
326 | }
327 |
328 | merge language minecraft:aaaa:
329 | yaml.key1: some_translation.upper()
330 | yaml.key2: some_translation.title()
331 |
332 | x = 0
333 | y = 1
334 | z = 2
335 |
336 | data merge storage demo:foo:
337 | custom_data1: [x, y, z]
338 | custom_data2:
339 | - x
340 | - y
341 | - z
342 |
343 | def set_at_origin(block):
344 | setblock 0 0 0 block
345 |
346 | set_at_origin(minecraft:stone)
347 |
348 | some_name = ./useless/../no_quotes_lol
349 | function some_name:
350 | say that's neat
351 |
352 | if ./a/b/c == ./x/../a/b/x/../c:
353 | say same thing
354 |
355 | tellraw @a:
356 | text: 'hello world'
357 |
358 | function_tag felix:howdy:
359 | values: ['demo:foo', __name__]
360 |
361 | execute at @s run particle minecraft:dust 0 1 1 0.9 ~ ~1 ~ 0 0 0 0.01 1 force
362 | execute at @s run particle minecraft:block yellow_concrete ~ ~1.62 ~ 0 0.4 0 0 30 force
363 | execute at @s run particle minecraft:block minecraft:light_blue_concrete ~ ~1 ~ 0.05 0.1 0.05 0 3
364 |
365 | particle_file minecraft:end_rod {
366 | "textures": [
367 | "minecraft:glitter_7",
368 | "minecraft:glitter_6",
369 | "minecraft:glitter_5",
370 | "minecraft:glitter_4",
371 | "minecraft:glitter_3",
372 | "minecraft:glitter_2",
373 | "minecraft:glitter_1",
374 | "minecraft:glitter_0"
375 | ]
376 | }
377 |
378 | for obj in ["foo", "bar"]:
379 | as @a[scores={obj=1..}] scoreboard players remove @s obj 1
380 |
381 | x = 8
382 | scoreboard players set @p tmp -x
383 |
384 | x = 12
385 | y = 23
386 | z = 34
387 |
388 | tp @s f"~{x} ~{y} ~{z}"
389 | tp @s f"~{x}" y f"~{z}"
390 |
391 | tp @s x y z
392 | tp @s ~x ~y ~z
393 | tp @s ^x ^y ^z
394 | tp @s -x -y -z
395 | tp @s ~-x ~-y ~-z
396 | tp @s ^-x ^-y ^-z
397 |
398 | for i, x in enumerate("abc"):
399 | say f"{i} {x}"
400 |
401 | major, minor, patch = "1.2.3".split(".")
402 | say major
403 | say minor
404 | say patch
405 |
406 | def check_above(n):
407 | if n > 0:
408 | if block ~ ~n ~ air:
409 | check_above(n - 1)
410 | else:
411 | say nothing above!
412 |
413 | check_above(6)
414 |
415 | math = 0
416 | say math
417 | def wat():
418 | global math
419 | import math
420 | wat()
421 | say math.ceil(0.1)
422 |
423 | say bolt implements a __rebind__(rhs) magic method that gets called when you reassign a value to a variable
424 | say let's try it out by manually building a class
425 |
426 | def init_global_score(self, name):
427 | self.name = name
428 |
429 | def add_global_score(self, rhs):
430 | tmp = GlobalScore(generate_id("tmp.{incr}"))
431 | scoreboard players operation tmp.name global = self.name global
432 | tmp += rhs
433 | return tmp
434 |
435 | def iadd_global_score(self, rhs):
436 | if isinstance(rhs, GlobalScore):
437 | scoreboard players operation self.name global += rhs.name global
438 | else:
439 | scoreboard players add self.name global rhs
440 | return self
441 |
442 | def rebind_global_score(self, rhs):
443 | if self is not rhs:
444 | if isinstance(rhs, GlobalScore):
445 | scoreboard players operation self.name global = rhs.name global
446 | else:
447 | scoreboard players set self.name global rhs
448 | return self
449 |
450 | GlobalScore = type("GlobalScore", (), {
451 | "__init__": init_global_score,
452 | "__add__": add_global_score,
453 | "__iadd__": iadd_global_score,
454 | "__rebind__": rebind_global_score,
455 | })
456 |
457 | a = GlobalScore("a")
458 | a = 123
459 | a = 456
460 |
461 | b = GlobalScore("b")
462 | b = 789
463 | b = a
464 |
465 | a += b + 6 + a
466 | b += 1
467 |
468 | say you can use nonlocal to create fake classes
469 |
470 | def Counter(x=0):
471 | def incr():
472 | nonlocal x
473 | x += 1
474 | return x
475 | return {"incr": incr}
476 |
477 | counter = Counter()
478 | say counter.incr()
479 | say counter.incr()
480 | say Counter(9).incr()x
481 |
482 | def foo(msg):
483 | say msg
484 |
485 | if score #temp abc matches 1..:
486 | foo("foo")
487 |
488 | tag_name = ./yolo_funcs
489 |
490 | function_tag tag_name:
491 | values:
492 | - "demo:foo"
493 |
494 | as @p function #tag_name # this runs the tag
495 |
496 | def truth_table():
497 | for a in [False, True]:
498 | for b in [False, True]:
499 | for c in [False, True]:
500 | for d in [False, True]:
501 | yield (a and b or c and not d) in [True] not in [False]
502 |
503 | say list(truth_table())
504 |
505 | def not_init(self, value):
506 | self.value = value
507 |
508 | def not_not(self):
509 | say self.value
510 | return self
511 |
512 | NotPrint = type("NotPrint", (), {"__init__": not_init, "__not__": not_not})
513 | not not not not NotPrint("hello")
514 |
515 | def thing_within(self, container):
516 | for item in container:
517 | say (self == item)
518 | return self
519 |
520 | def thing_contains(self, item):
521 | say (self == item)
522 | return self
523 |
524 | def thing_equal(self, item):
525 | return f"thing == {item}"
526 |
527 | Thing = type("Thing", (), {"__within__": thing_within, "__contains__": thing_contains, "__eq__": thing_equal})
528 | Thing() in [1, 2, 3] in [99]
529 | "world" in ("hello" in Thing())
530 |
531 | from contextlib import contextmanager
532 |
533 | def dsl_init(self, score, inverted=False):
534 | self.score = score
535 | self.inverted = inverted
536 |
537 | def dsl_not(self):
538 | return DSL(self.score, not self.inverted)
539 |
540 | def dsl_branch(self):
541 | if score @s self.score matches int(not self.inverted):
542 | yield True
543 |
544 | DSL = type("DSL", (), {"__init__": dsl_init, "__not__": dsl_not, "__branch__": contextmanager(dsl_branch)})
545 |
546 | if DSL("foo"):
547 | say yes
548 | if DSL("bar"):
549 | say with bar
550 | else:
551 | say no
552 |
553 | predicate ./check_scores [
554 | {
555 | "condition": "minecraft:entity_scores",
556 | "entity": "this",
557 | "scores": {
558 | "foo": 1
559 | }
560 | },
561 | {
562 | "condition": "minecraft:entity_scores",
563 | "entity": "killer_player",
564 | "scores": {
565 | "bar": 1
566 | }
567 | }
568 | ]
569 |
570 | def cond_init(self, name=generate_id("tmp{incr}")):
571 | self.name = name
572 |
573 | def cond_str(self):
574 | return self.name
575 |
576 | def cond_not(self):
577 | result = Cond()
578 | result = 1
579 | unless score global self matches 0:
580 | result = 0
581 | return result
582 |
583 | def cond_dup(self):
584 | result = Cond()
585 | result = self
586 | return result
587 |
588 | def cond_rebind(self, rhs):
589 | if isinstance(rhs, Cond):
590 | scoreboard players operation global self = global rhs
591 | else:
592 | scoreboard players set global self rhs
593 | return self
594 |
595 | def cond_branch(self):
596 | unless score global self matches 0:
597 | yield True
598 |
599 | Cond = type("Cond", (), {
600 | "__init__": cond_init,
601 | "__str__": cond_str,
602 | "__not__": cond_not,
603 | "__dup__": cond_dup,
604 | "__rebind__": cond_rebind,
605 | "__branch__": contextmanager(cond_branch),
606 | })
607 |
608 | is_awesome = Cond("is_awesome")
609 | is_awesome = Cond("is_cool") and Cond("is_nice")
610 |
611 | if is_awesome or Cond("force_awesomeness"):
612 | say hello
613 |
614 | from ./utils import something
615 | something()
616 |
617 | from ./utils import load_storage
618 | load_storage(./random_data, "random_data.json")
619 | if data storage ./random_data {value: 42} say json loaded successfully
620 |
621 | """
622 | Multiline comments
623 |
624 | are not parsed properly
625 |
626 | apparently
627 | """
--------------------------------------------------------------------------------
/mcfunction.tmLanguage.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Syntax Mcfunction",
3 | "scopeName": "source.mcfunction",
4 | "uuid": "8918dadd-8ebe-42d9-b1e9-0489ab228d9d",
5 | "fileTypes": [
6 | "mcfunction",
7 | "bolt"
8 | ],
9 | "patterns": [
10 | {
11 | "include": "#root"
12 | }
13 | ],
14 | "repository": {
15 | "root": {
16 | "patterns": [
17 | {
18 | "include": "#literals"
19 | },
20 | {
21 | "include": "#comments"
22 | },
23 | {
24 | "include": "#say"
25 | },
26 | {
27 | "include": "#names"
28 | },
29 | {
30 | "include": "#comments_inline"
31 | },
32 | {
33 | "include": "#subcommands"
34 | },
35 | {
36 | "include": "#property"
37 | },
38 | {
39 | "include": "#operators"
40 | },
41 | {
42 | "include": "#selectors"
43 | }
44 | ]
45 | },
46 | "comments": {
47 | "patterns": [
48 | {
49 | "applyEndPatternLast": 1,
50 | "begin": "^\\s*(#[>!#])(.+)$",
51 | "beginCaptures": {
52 | "1": {
53 | "name": "comment.block.mcfunction"
54 | },
55 | "2": {
56 | "name": "markup.bold.mcfunction"
57 | }
58 | },
59 | "captures": {
60 | "0": {
61 | "name": "comment.block.mcfunction"
62 | }
63 | },
64 | "end": "^(?!#)",
65 | "name": "meta.comments",
66 | "patterns": [
67 | {
68 | "include": "#comments_block"
69 | }
70 | ]
71 | },
72 | {
73 | "captures": {
74 | "0": {
75 | "name": "comment.line.mcfunction"
76 | }
77 | },
78 | "match": "^\\s*#.*$",
79 | "name": "meta.comments"
80 | }
81 | ]
82 | },
83 | "comments_inline": {
84 | "patterns": [
85 | {
86 | "captures": {
87 | "0": {
88 | "name": "comment.line.mcfunction"
89 | }
90 | },
91 | "match": "#.*$",
92 | "name": "meta.comments"
93 | }
94 | ]
95 | },
96 | "comments_block": {
97 | "patterns": [
98 | {
99 | "applyEndPatternLast": 1,
100 | "begin": "^\\s*#[>!]",
101 | "captures": {
102 | "0": {
103 | "name": "comment.block.mcfunction"
104 | }
105 | },
106 | "end": "$",
107 | "name": "meta.comments_block",
108 | "patterns": [
109 | {
110 | "include": "#comments_block_emphasized"
111 | }
112 | ]
113 | },
114 | {
115 | "applyEndPatternLast": 1,
116 | "begin": "^\\s*#",
117 | "captures": {
118 | "0": {
119 | "name": "comment.block.mcfunction"
120 | }
121 | },
122 | "end": "$",
123 | "name": "meta.comments_block",
124 | "patterns": [
125 | {
126 | "include": "#comments_block_normal"
127 | }
128 | ]
129 | }
130 | ]
131 | },
132 | "comments_block_emphasized": {
133 | "patterns": [
134 | {
135 | "include": "#comments_block_special"
136 | },
137 | {
138 | "captures": {
139 | "0": {
140 | "name": "markup.bold.mcfunction"
141 | }
142 | },
143 | "match": "\\S+",
144 | "name": "meta.comments_block_emphasized"
145 | }
146 | ]
147 | },
148 | "comments_block_normal": {
149 | "patterns": [
150 | {
151 | "include": "#comments_block_special"
152 | },
153 | {
154 | "captures": {
155 | "0": {
156 | "name": "comment.block.mcfunction"
157 | }
158 | },
159 | "match": "\\S+",
160 | "name": "meta.comments_block_normal"
161 | },
162 | {
163 | "include": "#whitespace"
164 | }
165 | ]
166 | },
167 | "comments_block_special": {
168 | "patterns": [
169 | {
170 | "captures": {
171 | "0": {
172 | "name": "markup.heading.mcfunction"
173 | }
174 | },
175 | "match": "@\\S+",
176 | "name": "meta.comments_block_special"
177 | },
178 | {
179 | "include": "#resource-name"
180 | },
181 | {
182 | "captures": {
183 | "0": {
184 | "name": "variable.other.mcfunction"
185 | }
186 | },
187 | "match": "[#%$][A-Za-z0-9_.#%$]+",
188 | "name": "meta.comments_block_special"
189 | }
190 | ]
191 | },
192 | "literals": {
193 | "patterns": [
194 | {
195 | "captures": {
196 | "0": {
197 | "name": "constant.numeric.boolean.mcfunction"
198 | }
199 | },
200 | "match": "\\b(true|false|True|False)\\b",
201 | "name": "meta.literals"
202 | },
203 | {
204 | "captures": {
205 | "0": {
206 | "name": "variable.uuid.mcfunction"
207 | }
208 | },
209 | "match": "\\b[0-9a-fA-F]+(?:-[0-9a-fA-F]+){4}\\b",
210 | "name": "meta.names"
211 | },
212 | {
213 | "captures": {
214 | "0": {
215 | "name": "constant.numeric.float.mcfunction"
216 | }
217 | },
218 | "match": "[+-]?\\d*\\.?\\d+([eE]?[+-]?\\d+)?[df]?\\b",
219 | "name": "meta.literals"
220 | },
221 | {
222 | "captures": {
223 | "0": {
224 | "name": "constant.numeric.integer.mcfunction"
225 | }
226 | },
227 | "match": "[+-]?\\d+(b|B|L|l|s|S)?\\b",
228 | "name": "meta.literals"
229 | },
230 | {
231 | "captures": {
232 | "0": {
233 | "name": "variable.other.mcfunction"
234 | }
235 | },
236 | "match": "\\.\\.",
237 | "name": "meta.ellipse.literals"
238 | },
239 | {
240 | "applyEndPatternLast": 1,
241 | "begin": "\"",
242 | "beginCaptures": {
243 | "0": {
244 | "name": "punctuation.definition.string.begin.mcfunction"
245 | }
246 | },
247 | "end": "\"",
248 | "endCaptures": {
249 | "0": {
250 | "name": "punctuation.definition.string.end.mcfunction"
251 | }
252 | },
253 | "name": "string.quoted.double.mcfunction",
254 | "patterns": [
255 | {
256 | "include": "#literals_string-double"
257 | }
258 | ]
259 | },
260 | {
261 | "applyEndPatternLast": 1,
262 | "begin": "'",
263 | "beginCaptures": {
264 | "0": {
265 | "name": "punctuation.definition.string.begin.mcfunction"
266 | }
267 | },
268 | "end": "'",
269 | "endCaptures": {
270 | "0": {
271 | "name": "punctuation.definition.string.begin.mcfunction"
272 | }
273 | },
274 | "name": "string.quoted.single.mcfunction",
275 | "patterns": [
276 | {
277 | "include": "#literals_string-single"
278 | }
279 | ]
280 | }
281 | ]
282 | },
283 | "subcommands": {
284 | "patterns": [
285 | {
286 | "captures": {
287 | "0": {
288 | "name": "entity.name.class.mcfunction"
289 | }
290 | },
291 | "match": "[a-z_]+",
292 | "name": "meta.literals"
293 | }
294 | ]
295 | },
296 | "literals_string-double": {
297 | "patterns": [
298 | {
299 | "captures": {
300 | "0": {
301 | "name": "constant.character.escape.mcfunction"
302 | }
303 | },
304 | "match": "\\\\.",
305 | "name": "meta.literals_string-double"
306 | },
307 | {
308 | "captures": {
309 | "0": {
310 | "name": "constant.character.escape.mcfunction"
311 | }
312 | },
313 | "match": "\\\\",
314 | "name": "meta.literals_string-double"
315 | },
316 | {
317 | "include": "#macro-name"
318 | },
319 | {
320 | "captures": {
321 | "0": {
322 | "name": "string.quoted.double.mcfunction"
323 | }
324 | },
325 | "match": "[^\\\\\"]",
326 | "name": "meta.literals_string-double"
327 | }
328 | ]
329 | },
330 | "literals_string-single": {
331 | "patterns": [
332 | {
333 | "captures": {
334 | "0": {
335 | "name": "constant.character.escape.mcfunction"
336 | }
337 | },
338 | "match": "\\\\.",
339 | "name": "meta.literals_string-single"
340 | },
341 | {
342 | "captures": {
343 | "0": {
344 | "name": "constant.character.escape.mcfunction"
345 | }
346 | },
347 | "match": "\\\\",
348 | "name": "meta.literals_string-double"
349 | },
350 | {
351 | "include": "#macro-name"
352 | },
353 | {
354 | "captures": {
355 | "0": {
356 | "name": "string.quoted.single.mcfunction"
357 | }
358 | },
359 | "match": "[^\\\\']",
360 | "name": "meta.literals_string-single"
361 | }
362 | ]
363 | },
364 | "say": {
365 | "patterns": [
366 | {
367 | "begin": "^(\\s*)(say)",
368 | "beginCaptures": {
369 | "1": {
370 | "name": "whitespace.mcfunction"
371 | },
372 | "2": {
373 | "name": "keyword.control.flow.mcfunction"
374 | }
375 | },
376 | "end": "\\n",
377 | "name": "meta.say.mcfunction",
378 | "patterns": [
379 | {
380 | "captures": {
381 | "0": {
382 | "name": "constant.character.escape.mcfunction"
383 | }
384 | },
385 | "match": "\\\\\\s*\\n",
386 | "meta": "meta.say.backslash.mcfunction"
387 | },
388 | {
389 | "include": "#literals_string-double"
390 | },
391 | {
392 | "include": "#literals_string-single"
393 | }
394 | ]
395 | },
396 | {
397 | "begin": "(run)(\\s+)(say)",
398 | "beginCaptures": {
399 | "1": {
400 | "name": "entity.name.mcfunction"
401 | },
402 | "2": {
403 | "name": "whitespace.mcfunction"
404 | },
405 | "3": {
406 | "name": "keyword.control.flow.mcfunction"
407 | }
408 | },
409 | "end": "\\n",
410 | "name": "meta.say.mcfunction",
411 | "patterns": [
412 | {
413 | "captures": {
414 | "0": {
415 | "name": "constant.character.escape.mcfunction"
416 | }
417 | },
418 | "match": "\\\\\\s*\\n",
419 | "meta": "meta.say.backslash.mcfunction"
420 | },
421 | {
422 | "include": "#literals_string-double"
423 | },
424 | {
425 | "include": "#literals_string-single"
426 | }
427 | ]
428 | }
429 | ]
430 | },
431 | "names": {
432 | "patterns": [
433 | {
434 | "captures": {
435 | "1": {
436 | "name": "whitespace.mcfunction"
437 | },
438 | "2": {
439 | "name": "keyword.control.flow.mcfunction"
440 | }
441 | },
442 | "match": "^(\\s*)([a-z_]+)(?=\\s)",
443 | "name": "meta.names"
444 | },
445 | {
446 | "captures": {
447 | "1": {
448 | "name": "whitespace.mcfunction"
449 | },
450 | "2": {
451 | "name": "markup.italic.mcfunction"
452 | },
453 | "3": {
454 | "name": "whitespace.mcfunction"
455 | },
456 | "4": {
457 | "name": "keyword.control.flow.mcfunction"
458 | }
459 | },
460 | "match": "^(\\s*)(\\$)( ?)([a-z_]*)",
461 | "name": "meta.names"
462 | },
463 | {
464 | "captures": {
465 | "1": {
466 | "name": "entity.name.mcfunction"
467 | },
468 | "2": {
469 | "name": "whitespace.mcfunction"
470 | },
471 | "3": {
472 | "name": "keyword.control.flow.mcfunction"
473 | }
474 | },
475 | "match": "(run)(\\s+)([a-z_]+)",
476 | "name": "meta.names"
477 | },
478 | {
479 | "include": "#resource-name"
480 | },
481 | {
482 | "captures": {
483 | "0": {
484 | "name": "entity.name.mcfunction"
485 | }
486 | },
487 | "match": "[A-Za-z]+(?=\\W)",
488 | "name": "meta.names"
489 | },
490 | {
491 | "captures": {
492 | "0": {
493 | "name": "string.unquoted.mcfunction"
494 | }
495 | },
496 | "match": "[A-Za-z_][A-Za-z0-9_.#%$]*",
497 | "name": "meta.names"
498 | },
499 | {
500 | "include": "#macro-name"
501 | },
502 | {
503 | "captures": {
504 | "0": {
505 | "name": "variable.other.mcfunction"
506 | }
507 | },
508 | "match": "([#%$]|((?<=\\s)\\.))[A-Za-z0-9_.#%$\\-]+",
509 | "name": "meta.names"
510 | }
511 | ]
512 | },
513 | "macro-name": {
514 | "patterns": [
515 | {
516 | "captures": {
517 | "1": {
518 | "name": "punctuation.definition.template-expression.begin.mcfunction"
519 | },
520 | "2": {
521 | "name": "variable.other.mcfunction"
522 | },
523 | "3": {
524 | "name": "punctuation.definition.template-expression.end.mcfunction"
525 | }
526 | },
527 | "match": "(\\$\\()([A-Za-z0-9_]*)(\\))",
528 | "name": "meta.macro-name"
529 | }
530 | ]
531 | },
532 | "operators": {
533 | "patterns": [
534 | {
535 | "captures": {
536 | "0": {
537 | "name": "constant.numeric.mcfunction"
538 | }
539 | },
540 | "match": "[~^]",
541 | "name": "meta.operators"
542 | },
543 | {
544 | "captures": {
545 | "0": {
546 | "name": "keyword.operator.mcfunction"
547 | }
548 | },
549 | "match": "[\\-%?!+*<>\\\\/|&=.:,;]",
550 | "name": "meta.operators"
551 | }
552 | ]
553 | },
554 | "property": {
555 | "patterns": [
556 | {
557 | "applyEndPatternLast": 1,
558 | "begin": "\\{",
559 | "captures": {
560 | "0": {
561 | "name": "punctuation.mcfunction"
562 | }
563 | },
564 | "end": "\\}",
565 | "name": "meta.property.curly",
566 | "patterns": [
567 | {
568 | "include": "#resource-name"
569 | },
570 | {
571 | "include": "#literals"
572 | },
573 | {
574 | "include": "#property_key"
575 | },
576 | {
577 | "include": "#operators"
578 | },
579 | {
580 | "include": "#property_value"
581 | },
582 | {
583 | "include": "$self"
584 | }
585 | ]
586 | },
587 | {
588 | "applyEndPatternLast": 1,
589 | "begin": "\\[",
590 | "captures": {
591 | "0": {
592 | "name": "variable.other.mcfunction"
593 | }
594 | },
595 | "end": "\\]",
596 | "name": "meta.property.square",
597 | "patterns": [
598 | {
599 | "include": "#resource-name"
600 | },
601 | {
602 | "include": "#literals"
603 | },
604 | {
605 | "include": "#property_key"
606 | },
607 | {
608 | "include": "#operators"
609 | },
610 | {
611 | "include": "#property_value"
612 | },
613 | {
614 | "include": "$self"
615 | }
616 | ]
617 | },
618 | {
619 | "applyEndPatternLast": 1,
620 | "begin": "\\(",
621 | "captures": {
622 | "0": {
623 | "name": "punctuation.mcfunction"
624 | }
625 | },
626 | "end": "\\)",
627 | "name": "meta.property.paren",
628 | "patterns": [
629 | {
630 | "include": "#resource-name"
631 | },
632 | {
633 | "include": "#literals"
634 | },
635 | {
636 | "include": "#property_key"
637 | },
638 | {
639 | "include": "#operators"
640 | },
641 | {
642 | "include": "#property_value"
643 | },
644 | {
645 | "include": "$self"
646 | }
647 | ]
648 | }
649 | ]
650 | },
651 | "property_key": {
652 | "patterns": [
653 | {
654 | "captures": {
655 | "0": {
656 | "name": "variable.other.mcfunction"
657 | }
658 | },
659 | "match": "#?[a-z_][a-z_\\.\\-]*\\:[a-z0-9_\\.\\-/]+(?=\\s*\\=:)",
660 | "name": "meta.property_key"
661 | },
662 | {
663 | "captures": {
664 | "0": {
665 | "name": "variable.other.mcfunction"
666 | }
667 | },
668 | "match": "#?[a-z_][a-z0-9_\\.\\-/]+",
669 | "name": "meta.property_key"
670 | },
671 | {
672 | "captures": {
673 | "0": {
674 | "name": "variable.other.mcfunction"
675 | }
676 | },
677 | "match": "[A-Za-z_]+[A-Za-z_\\-\\+]*",
678 | "name": "meta.property_key"
679 | }
680 | ]
681 | },
682 | "property_value": {
683 | "patterns": [
684 | {
685 | "captures": {
686 | "0": {
687 | "name": "string.unquoted.mcfunction"
688 | }
689 | },
690 | "match": "#?[a-z_][a-z_\\.\\-]*\\:[a-z0-9_\\.\\-/]+",
691 | "name": "meta.property_value"
692 | },
693 | {
694 | "captures": {
695 | "0": {
696 | "name": "string.unquoted.mcfunction"
697 | }
698 | },
699 | "match": "#?[a-z_][a-z0-9_\\.\\-/]+",
700 | "name": "meta.property_value"
701 | }
702 | ]
703 | },
704 | "resource-name": {
705 | "patterns": [
706 | {
707 | "captures": {
708 | "0": {
709 | "name": "entity.name.function.mcfunction"
710 | }
711 | },
712 | "match": "#?[a-z_][a-z0-9_.-]*:[a-z0-9_./-]+",
713 | "name": "meta.resource-name"
714 | },
715 | {
716 | "captures": {
717 | "0": {
718 | "name": "entity.name.function.mcfunction"
719 | }
720 | },
721 | "match": "#?[a-z0-9_\\.\\-]+\\/[a-z0-9_\\.\\-\\/]+",
722 | "name": "meta.resource-name"
723 | }
724 | ]
725 | },
726 | "selectors": {
727 | "patterns": [
728 | {
729 | "captures": {
730 | "0": {
731 | "name": "support.class.mcfunction"
732 | }
733 | },
734 | "match": "@[a-z]+",
735 | "name": "meta.selectors"
736 | }
737 | ]
738 | }
739 | }
740 | }
741 |
--------------------------------------------------------------------------------
/mcfunction.tmLanguage:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | fileTypes
6 |
7 | mcfunction
8 | bolt
9 |
10 | name
11 | Syntax Mcfunction
12 | patterns
13 |
14 |
15 | include
16 | #root
17 |
18 |
19 | repository
20 |
21 | comments
22 |
23 | patterns
24 |
25 |
26 | applyEndPatternLast
27 | 1
28 | begin
29 | ^\s*(#[>!#])(.+)$
30 | beginCaptures
31 |
32 | 1
33 |
34 | name
35 | comment.block.mcfunction
36 |
37 | 2
38 |
39 | name
40 | markup.bold.mcfunction
41 |
42 |
43 | captures
44 |
45 | 0
46 |
47 | name
48 | comment.block.mcfunction
49 |
50 |
51 | end
52 | ^(?!#)
53 | name
54 | meta.comments
55 | patterns
56 |
57 |
58 | include
59 | #comments_block
60 |
61 |
62 |
63 |
64 | captures
65 |
66 | 0
67 |
68 | name
69 | comment.line.mcfunction
70 |
71 |
72 | match
73 | ^\s*#.*$
74 | name
75 | meta.comments
76 |
77 |
78 |
79 | comments_block
80 |
81 | patterns
82 |
83 |
84 | applyEndPatternLast
85 | 1
86 | begin
87 | ^\s*#[>!]
88 | captures
89 |
90 | 0
91 |
92 | name
93 | comment.block.mcfunction
94 |
95 |
96 | end
97 | $
98 | name
99 | meta.comments_block
100 | patterns
101 |
102 |
103 | include
104 | #comments_block_emphasized
105 |
106 |
107 |
108 |
109 | applyEndPatternLast
110 | 1
111 | begin
112 | ^\s*#
113 | captures
114 |
115 | 0
116 |
117 | name
118 | comment.block.mcfunction
119 |
120 |
121 | end
122 | $
123 | name
124 | meta.comments_block
125 | patterns
126 |
127 |
128 | include
129 | #comments_block_normal
130 |
131 |
132 |
133 |
134 |
135 | comments_block_emphasized
136 |
137 | patterns
138 |
139 |
140 | include
141 | #comments_block_special
142 |
143 |
144 | captures
145 |
146 | 0
147 |
148 | name
149 | markup.bold.mcfunction
150 |
151 |
152 | match
153 | \S+
154 | name
155 | meta.comments_block_emphasized
156 |
157 |
158 |
159 | comments_block_normal
160 |
161 | patterns
162 |
163 |
164 | include
165 | #comments_block_special
166 |
167 |
168 | captures
169 |
170 | 0
171 |
172 | name
173 | comment.block.mcfunction
174 |
175 |
176 | match
177 | \S+
178 | name
179 | meta.comments_block_normal
180 |
181 |
182 | include
183 | #whitespace
184 |
185 |
186 |
187 | comments_block_special
188 |
189 | patterns
190 |
191 |
192 | captures
193 |
194 | 0
195 |
196 | name
197 | markup.heading.mcfunction
198 |
199 |
200 | match
201 | @\S+
202 | name
203 | meta.comments_block_special
204 |
205 |
206 | include
207 | #resource-name
208 |
209 |
210 | captures
211 |
212 | 0
213 |
214 | name
215 | variable.other.mcfunction
216 |
217 |
218 | match
219 | [#%$][A-Za-z0-9_.#%$]+
220 | name
221 | meta.comments_block_special
222 |
223 |
224 |
225 | comments_inline
226 |
227 | patterns
228 |
229 |
230 | captures
231 |
232 | 0
233 |
234 | name
235 | comment.line.mcfunction
236 |
237 |
238 | match
239 | #.*$
240 | name
241 | meta.comments
242 |
243 |
244 |
245 | literals
246 |
247 | patterns
248 |
249 |
250 | captures
251 |
252 | 0
253 |
254 | name
255 | constant.numeric.boolean.mcfunction
256 |
257 |
258 | match
259 | \b(true|false|True|False)\b
260 | name
261 | meta.literals
262 |
263 |
264 | captures
265 |
266 | 0
267 |
268 | name
269 | variable.uuid.mcfunction
270 |
271 |
272 | match
273 | \b[0-9a-fA-F]+(?:-[0-9a-fA-F]+){4}\b
274 | name
275 | meta.names
276 |
277 |
278 | captures
279 |
280 | 0
281 |
282 | name
283 | constant.numeric.float.mcfunction
284 |
285 |
286 | match
287 | [+-]?\d*\.?\d+([eE]?[+-]?\d+)?[df]?\b
288 | name
289 | meta.literals
290 |
291 |
292 | captures
293 |
294 | 0
295 |
296 | name
297 | constant.numeric.integer.mcfunction
298 |
299 |
300 | match
301 | [+-]?\d+(b|B|L|l|s|S)?\b
302 | name
303 | meta.literals
304 |
305 |
306 | captures
307 |
308 | 0
309 |
310 | name
311 | variable.other.mcfunction
312 |
313 |
314 | match
315 | \.\.
316 | name
317 | meta.ellipse.literals
318 |
319 |
320 | applyEndPatternLast
321 | 1
322 | begin
323 | "
324 | beginCaptures
325 |
326 | 0
327 |
328 | name
329 | punctuation.definition.string.begin.mcfunction
330 |
331 |
332 | end
333 | "
334 | endCaptures
335 |
336 | 0
337 |
338 | name
339 | punctuation.definition.string.end.mcfunction
340 |
341 |
342 | name
343 | string.quoted.double.mcfunction
344 | patterns
345 |
346 |
347 | include
348 | #literals_string-double
349 |
350 |
351 |
352 |
353 | applyEndPatternLast
354 | 1
355 | begin
356 | '
357 | beginCaptures
358 |
359 | 0
360 |
361 | name
362 | punctuation.definition.string.begin.mcfunction
363 |
364 |
365 | end
366 | '
367 | endCaptures
368 |
369 | 0
370 |
371 | name
372 | punctuation.definition.string.begin.mcfunction
373 |
374 |
375 | name
376 | string.quoted.single.mcfunction
377 | patterns
378 |
379 |
380 | include
381 | #literals_string-single
382 |
383 |
384 |
385 |
386 |
387 | literals_string-double
388 |
389 | patterns
390 |
391 |
392 | captures
393 |
394 | 0
395 |
396 | name
397 | constant.character.escape.mcfunction
398 |
399 |
400 | match
401 | \\.
402 | name
403 | meta.literals_string-double
404 |
405 |
406 | captures
407 |
408 | 0
409 |
410 | name
411 | constant.character.escape.mcfunction
412 |
413 |
414 | match
415 | \\
416 | name
417 | meta.literals_string-double
418 |
419 |
420 | include
421 | #macro-name
422 |
423 |
424 | captures
425 |
426 | 0
427 |
428 | name
429 | string.quoted.double.mcfunction
430 |
431 |
432 | match
433 | [^\\"]
434 | name
435 | meta.literals_string-double
436 |
437 |
438 |
439 | literals_string-single
440 |
441 | patterns
442 |
443 |
444 | captures
445 |
446 | 0
447 |
448 | name
449 | constant.character.escape.mcfunction
450 |
451 |
452 | match
453 | \\.
454 | name
455 | meta.literals_string-single
456 |
457 |
458 | captures
459 |
460 | 0
461 |
462 | name
463 | constant.character.escape.mcfunction
464 |
465 |
466 | match
467 | \\
468 | name
469 | meta.literals_string-double
470 |
471 |
472 | include
473 | #macro-name
474 |
475 |
476 | captures
477 |
478 | 0
479 |
480 | name
481 | string.quoted.single.mcfunction
482 |
483 |
484 | match
485 | [^\\']
486 | name
487 | meta.literals_string-single
488 |
489 |
490 |
491 | macro-name
492 |
493 | patterns
494 |
495 |
496 | captures
497 |
498 | 1
499 |
500 | name
501 | punctuation.definition.template-expression.begin.mcfunction
502 |
503 | 2
504 |
505 | name
506 | variable.other.mcfunction
507 |
508 | 3
509 |
510 | name
511 | punctuation.definition.template-expression.end.mcfunction
512 |
513 |
514 | match
515 | (\$\()([A-Za-z0-9_]*)(\))
516 | name
517 | meta.macro-name
518 |
519 |
520 |
521 | names
522 |
523 | patterns
524 |
525 |
526 | captures
527 |
528 | 1
529 |
530 | name
531 | whitespace.mcfunction
532 |
533 | 2
534 |
535 | name
536 | keyword.control.flow.mcfunction
537 |
538 |
539 | match
540 | ^(\s*)([a-z_]+)(?=\s)
541 | name
542 | meta.names
543 |
544 |
545 | captures
546 |
547 | 1
548 |
549 | name
550 | whitespace.mcfunction
551 |
552 | 2
553 |
554 | name
555 | markup.italic.mcfunction
556 |
557 | 3
558 |
559 | name
560 | whitespace.mcfunction
561 |
562 | 4
563 |
564 | name
565 | keyword.control.flow.mcfunction
566 |
567 |
568 | match
569 | ^(\s*)(\$)( ?)([a-z_]*)
570 | name
571 | meta.names
572 |
573 |
574 | captures
575 |
576 | 1
577 |
578 | name
579 | entity.name.mcfunction
580 |
581 | 2
582 |
583 | name
584 | whitespace.mcfunction
585 |
586 | 3
587 |
588 | name
589 | keyword.control.flow.mcfunction
590 |
591 |
592 | match
593 | (run)(\s+)([a-z_]+)
594 | name
595 | meta.names
596 |
597 |
598 | include
599 | #resource-name
600 |
601 |
602 | captures
603 |
604 | 0
605 |
606 | name
607 | entity.name.mcfunction
608 |
609 |
610 | match
611 | [A-Za-z]+(?=\W)
612 | name
613 | meta.names
614 |
615 |
616 | captures
617 |
618 | 0
619 |
620 | name
621 | string.unquoted.mcfunction
622 |
623 |
624 | match
625 | [A-Za-z_][A-Za-z0-9_.#%$]*
626 | name
627 | meta.names
628 |
629 |
630 | include
631 | #macro-name
632 |
633 |
634 | captures
635 |
636 | 0
637 |
638 | name
639 | variable.other.mcfunction
640 |
641 |
642 | match
643 | ([#%$]|((?<=\s)\.))[A-Za-z0-9_.#%$\-]+
644 | name
645 | meta.names
646 |
647 |
648 |
649 | operators
650 |
651 | patterns
652 |
653 |
654 | captures
655 |
656 | 0
657 |
658 | name
659 | constant.numeric.mcfunction
660 |
661 |
662 | match
663 | [~^]
664 | name
665 | meta.operators
666 |
667 |
668 | captures
669 |
670 | 0
671 |
672 | name
673 | keyword.operator.mcfunction
674 |
675 |
676 | match
677 | [\-%?!+*<>\\/|&=.:,;]
678 | name
679 | meta.operators
680 |
681 |
682 |
683 | property
684 |
685 | patterns
686 |
687 |
688 | applyEndPatternLast
689 | 1
690 | begin
691 | \{
692 | captures
693 |
694 | 0
695 |
696 | name
697 | punctuation.mcfunction
698 |
699 |
700 | end
701 | \}
702 | name
703 | meta.property.curly
704 | patterns
705 |
706 |
707 | include
708 | #resource-name
709 |
710 |
711 | include
712 | #literals
713 |
714 |
715 | include
716 | #property_key
717 |
718 |
719 | include
720 | #operators
721 |
722 |
723 | include
724 | #property_value
725 |
726 |
727 | include
728 | $self
729 |
730 |
731 |
732 |
733 | applyEndPatternLast
734 | 1
735 | begin
736 | \[
737 | captures
738 |
739 | 0
740 |
741 | name
742 | variable.other.mcfunction
743 |
744 |
745 | end
746 | \]
747 | name
748 | meta.property.square
749 | patterns
750 |
751 |
752 | include
753 | #resource-name
754 |
755 |
756 | include
757 | #literals
758 |
759 |
760 | include
761 | #property_key
762 |
763 |
764 | include
765 | #operators
766 |
767 |
768 | include
769 | #property_value
770 |
771 |
772 | include
773 | $self
774 |
775 |
776 |
777 |
778 | applyEndPatternLast
779 | 1
780 | begin
781 | \(
782 | captures
783 |
784 | 0
785 |
786 | name
787 | punctuation.mcfunction
788 |
789 |
790 | end
791 | \)
792 | name
793 | meta.property.paren
794 | patterns
795 |
796 |
797 | include
798 | #resource-name
799 |
800 |
801 | include
802 | #literals
803 |
804 |
805 | include
806 | #property_key
807 |
808 |
809 | include
810 | #operators
811 |
812 |
813 | include
814 | #property_value
815 |
816 |
817 | include
818 | $self
819 |
820 |
821 |
822 |
823 |
824 | property_key
825 |
826 | patterns
827 |
828 |
829 | captures
830 |
831 | 0
832 |
833 | name
834 | variable.other.mcfunction
835 |
836 |
837 | match
838 | #?[a-z_][a-z_\.\-]*\:[a-z0-9_\.\-/]+(?=\s*\=:)
839 | name
840 | meta.property_key
841 |
842 |
843 | captures
844 |
845 | 0
846 |
847 | name
848 | variable.other.mcfunction
849 |
850 |
851 | match
852 | #?[a-z_][a-z0-9_\.\-/]+
853 | name
854 | meta.property_key
855 |
856 |
857 | captures
858 |
859 | 0
860 |
861 | name
862 | variable.other.mcfunction
863 |
864 |
865 | match
866 | [A-Za-z_]+[A-Za-z_\-\+]*
867 | name
868 | meta.property_key
869 |
870 |
871 |
872 | property_value
873 |
874 | patterns
875 |
876 |
877 | captures
878 |
879 | 0
880 |
881 | name
882 | string.unquoted.mcfunction
883 |
884 |
885 | match
886 | #?[a-z_][a-z_\.\-]*\:[a-z0-9_\.\-/]+
887 | name
888 | meta.property_value
889 |
890 |
891 | captures
892 |
893 | 0
894 |
895 | name
896 | string.unquoted.mcfunction
897 |
898 |
899 | match
900 | #?[a-z_][a-z0-9_\.\-/]+
901 | name
902 | meta.property_value
903 |
904 |
905 |
906 | resource-name
907 |
908 | patterns
909 |
910 |
911 | captures
912 |
913 | 0
914 |
915 | name
916 | entity.name.function.mcfunction
917 |
918 |
919 | match
920 | #?[a-z_][a-z0-9_.-]*:[a-z0-9_./-]+
921 | name
922 | meta.resource-name
923 |
924 |
925 | captures
926 |
927 | 0
928 |
929 | name
930 | entity.name.function.mcfunction
931 |
932 |
933 | match
934 | #?[a-z0-9_\.\-]+\/[a-z0-9_\.\-\/]+
935 | name
936 | meta.resource-name
937 |
938 |
939 |
940 | root
941 |
942 | patterns
943 |
944 |
945 | include
946 | #literals
947 |
948 |
949 | include
950 | #comments
951 |
952 |
953 | include
954 | #say
955 |
956 |
957 | include
958 | #names
959 |
960 |
961 | include
962 | #comments_inline
963 |
964 |
965 | include
966 | #subcommands
967 |
968 |
969 | include
970 | #property
971 |
972 |
973 | include
974 | #operators
975 |
976 |
977 | include
978 | #selectors
979 |
980 |
981 |
982 | say
983 |
984 | patterns
985 |
986 |
987 | begin
988 | ^(\s*)(say)
989 | beginCaptures
990 |
991 | 1
992 |
993 | name
994 | whitespace.mcfunction
995 |
996 | 2
997 |
998 | name
999 | keyword.control.flow.mcfunction
1000 |
1001 |
1002 | end
1003 | \n
1004 | name
1005 | meta.say.mcfunction
1006 | patterns
1007 |
1008 |
1009 | captures
1010 |
1011 | 0
1012 |
1013 | name
1014 | constant.character.escape.mcfunction
1015 |
1016 |
1017 | match
1018 | \\\s*\n
1019 | meta
1020 | meta.say.backslash.mcfunction
1021 |
1022 |
1023 | include
1024 | #literals_string-double
1025 |
1026 |
1027 | include
1028 | #literals_string-single
1029 |
1030 |
1031 |
1032 |
1033 | begin
1034 | (run)(\s+)(say)
1035 | beginCaptures
1036 |
1037 | 1
1038 |
1039 | name
1040 | entity.name.mcfunction
1041 |
1042 | 2
1043 |
1044 | name
1045 | whitespace.mcfunction
1046 |
1047 | 3
1048 |
1049 | name
1050 | keyword.control.flow.mcfunction
1051 |
1052 |
1053 | end
1054 | \n
1055 | name
1056 | meta.say.mcfunction
1057 | patterns
1058 |
1059 |
1060 | captures
1061 |
1062 | 0
1063 |
1064 | name
1065 | constant.character.escape.mcfunction
1066 |
1067 |
1068 | match
1069 | \\\s*\n
1070 | meta
1071 | meta.say.backslash.mcfunction
1072 |
1073 |
1074 | include
1075 | #literals_string-double
1076 |
1077 |
1078 | include
1079 | #literals_string-single
1080 |
1081 |
1082 |
1083 |
1084 |
1085 | selectors
1086 |
1087 | patterns
1088 |
1089 |
1090 | captures
1091 |
1092 | 0
1093 |
1094 | name
1095 | support.class.mcfunction
1096 |
1097 |
1098 | match
1099 | @[a-z]+
1100 | name
1101 | meta.selectors
1102 |
1103 |
1104 |
1105 | subcommands
1106 |
1107 | patterns
1108 |
1109 |
1110 | captures
1111 |
1112 | 0
1113 |
1114 | name
1115 | entity.name.class.mcfunction
1116 |
1117 |
1118 | match
1119 | [a-z_]+
1120 | name
1121 | meta.literals
1122 |
1123 |
1124 |
1125 |
1126 | scopeName
1127 | source.mcfunction
1128 | uuid
1129 | 8918dadd-8ebe-42d9-b1e9-0489ab228d9d
1130 |
1131 |
1132 |
--------------------------------------------------------------------------------