Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a lexer for Schemas for Minecraft Add-ons and 4 examples, merging lexers #2276

Merged
merged 6 commits into from Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions pygments/lexers/_mapping.py
Expand Up @@ -275,7 +275,8 @@
'LogosLexer': ('pygments.lexers.objective', 'Logos', ('logos',), ('*.x', '*.xi', '*.xm', '*.xmi'), ('text/x-logos',)),
'LogtalkLexer': ('pygments.lexers.prolog', 'Logtalk', ('logtalk',), ('*.lgt', '*.logtalk'), ('text/x-logtalk',)),
'LuaLexer': ('pygments.lexers.scripting', 'Lua', ('lua',), ('*.lua', '*.wlua'), ('text/x-lua', 'application/x-lua')),
'MCFunctionLexer': ('pygments.lexers.mcfunction', 'MCFunction', ('mcfunction', 'mcf'), ('*.mcfunction',), ('text/mcfunction',)),
'MCFunctionLexer': ('pygments.lexers.minecraft', 'MCFunction', ('mcfunction', 'mcf'), ('*.mcfunction',), ('text/mcfunction',)),
'MCSchemaLexer': ('pygments.lexers.minecraft', 'MCSchema', ('mcschema',), ('*.mcschema',), ('text/mcschema',)),
'MIMELexer': ('pygments.lexers.mime', 'MIME', ('mime',), (), ('multipart/mixed', 'multipart/related', 'multipart/alternative')),
'MIPSLexer': ('pygments.lexers.mips', 'MIPS', ('mips',), ('*.mips', '*.MIPS'), ()),
'MOOCodeLexer': ('pygments.lexers.scripting', 'MOOCode', ('moocode', 'moo'), ('*.moo',), ('text/x-moocode',)),
Expand Down Expand Up @@ -428,7 +429,7 @@
'SASLexer': ('pygments.lexers.sas', 'SAS', ('sas',), ('*.SAS', '*.sas'), ('text/x-sas', 'text/sas', 'application/x-sas')),
'SLexer': ('pygments.lexers.r', 'S', ('splus', 's', 'r'), ('*.S', '*.R', '.Rhistory', '.Rprofile', '.Renviron'), ('text/S-plus', 'text/S', 'text/x-r-source', 'text/x-r', 'text/x-R', 'text/x-r-history', 'text/x-r-profile')),
'SMLLexer': ('pygments.lexers.ml', 'Standard ML', ('sml',), ('*.sml', '*.sig', '*.fun'), ('text/x-standardml', 'application/x-standardml')),
'SNBTLexer': ('pygments.lexers.mcfunction', 'SNBT', ('snbt',), ('*.snbt',), ('text/snbt',)),
'SNBTLexer': ('pygments.lexers.minecraft', 'SNBT', ('snbt',), ('*.snbt',), ('text/snbt',)),
'SarlLexer': ('pygments.lexers.jvm', 'SARL', ('sarl',), ('*.sarl',), ('text/x-sarl',)),
'SassLexer': ('pygments.lexers.css', 'Sass', ('sass',), ('*.sass',), ('text/x-sass',)),
'SaviLexer': ('pygments.lexers.savi', 'Savi', ('savi',), ('*.savi',), ()),
Expand Down
104 changes: 95 additions & 9 deletions pygments/lexers/mcfunction.py → pygments/lexers/minecraft.py
@@ -1,8 +1,19 @@
"""
pygments.lexers.mcfunction
~~~~~~~~~~~~~~~~~~~~~~~~~~

Lexers for MCFunction and related languages.
pygments.lexers.minecraft
~~~~~~~~~~~~~~~~~~~~~~~~~

Lexers for Minecraft related languages.

SNBT. A data communication format used in Minecraft.
wiki: https://minecraft.fandom.com/wiki/NBT_format

MCFunction. The Function file for Minecraft Data packs and Add-ons.
official: https://learn.microsoft.com/en-us/minecraft/creator/documents/functionsintroduction
wiki: https://minecraft.fandom.com/wiki/Function

MCSchema. A kind of data Schema for Minecraft Add-on Development.
official: https://learn.microsoft.com/en-us/minecraft/creator/reference/content/schemasreference/
community example: https://www.mcbe-dev.net/addons/data-driven/manifest.html

:copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS.
:license: BSD, see LICENSE for details.
Expand All @@ -12,13 +23,13 @@
from pygments.token import Comment, Keyword, Literal, Name, Number, Operator, \
Punctuation, String, Text, Whitespace

__all__ = ['SNBTLexer', 'MCFunctionLexer']
__all__ = ['SNBTLexer', 'MCFunctionLexer', 'MCSchemaLexer']


class SNBTLexer(RegexLexer):
"""Lexer for stringified NBT, a data format used in Minecraft

.. versionadded:: 2.12
.. versionadded:: 2.12.0
"""

name = "SNBT"
Expand Down Expand Up @@ -127,8 +138,8 @@ class MCFunctionLexer(RegexLexer):
include("resource-name"),
# normal command names and scoreboards
# there's no way to know the differences unfortuntely
(r"[A-Za-z_][A-Za-z0-9_.#%$]+", Keyword.Constant),
(r"[#%$][A-Za-z0-9_.#%$]+", Name.Variable.Magic),
(r"[A-Za-z_][\w.#%$]+", Keyword.Constant),
(r"[#%$][\w.#%$]+", Name.Variable.Magic),
],

"resource-name": [
Expand Down Expand Up @@ -173,7 +184,7 @@ class MCFunctionLexer(RegexLexer):
include("resource-name"),

# Scoreboard player names
(r"[#%$][A-Za-z0-9_.#%$]+", Name.Variable.Magic),
(r"[#%$][\w.#%$]+", Name.Variable.Magic),
],

"operators": [
Expand Down Expand Up @@ -306,3 +317,78 @@ class MCFunctionLexer(RegexLexer):
default("#pop"),
],
}


class MCSchemaLexer(RegexLexer):
"""Lexer for Minecraft Add-ons data Schemas, an interface structure standard used in Minecraft

.. versionadded:: 2.14.0
"""

name = 'MCSchema'
url = 'https://learn.microsoft.com/en-us/minecraft/creator/reference/content/schemasreference/'
aliases = ['mcschema']
filenames = ['*.mcschema']
mimetypes = ['text/mcschema']

tokens = {
'commentsandwhitespace': [
(r'\s+', Whitespace),
(r'//.*?$', Comment.Single),
(r'/\*.*?\*/', Comment.Multiline)
],
'slashstartsregex': [
include('commentsandwhitespace'),
(r'/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/'
jeanas marked this conversation as resolved.
Show resolved Hide resolved
r'([gimuysd]+\b|\B)', String.Regex, '#pop'),
(r'(?=/)', Text, ('#pop', 'badregex')),
default('#pop')
],
'badregex': [
(r'\n', Whitespace, '#pop')
],
'singlestring': [
(r'\\.', String.Escape),
(r"'", String.Single, '#pop'),
(r"[^\\']+", String.Single),
],
'doublestring': [
(r'\\.', String.Escape),
(r'"', String.Double, '#pop'),
(r'[^\\"]+', String.Double),
],
'root': [
(r'^(?=\s|/|<!--)', Text, 'slashstartsregex'),
include('commentsandwhitespace'),

# keywords for optional word and field types
(r'(?<=: )opt', Operator.Word),
(r'(?<=\s)[\w-]*(?=(\s+"|\n))', Keyword.Declaration),

# numeric literals
(r'0[bB][01]+', Number.Bin),
(r'0[oO]?[0-7]+', Number.Oct),
(r'0[xX][0-9a-fA-F]+', Number.Hex),
(r'\d+', Number.Integer),
(r'(\.\d+|\d+\.\d*|\d+)([eE][-+]?\d+)?', Number.Float),

# possible punctuations
(r'\.\.\.|=>', Punctuation),
(r'\+\+|--|~|\?\?=?|\?|:|\\(?=\n)|'
r'(<<|>>>?|==?|!=?|(?:\*\*|\|\||&&|[-<>+*%&|^/]))=?', Operator, 'slashstartsregex'),
(r'[{(\[;,]', Punctuation, 'slashstartsregex'),
(r'[})\].]', Punctuation),

# strings
(r"'", String.Single, 'singlestring'),
(r'"', String.Double, 'doublestring'),

# title line
(r'[\w-]*?(?=:\{?\n)', String.Symbol),
# title line with a version code, formatted
# `major.minor.patch-prerelease+buildmeta`
(r'([\w-]*?)(:)(\d+)(?:(\.)(\d+)(?:(\.)(\d+)(?:(\-)((?:[^\W_]|-)*(?:\.(?:[^\W_]|-)*)*))?(?:(\+)((?:[^\W_]|-)+(?:\.(?:[^\W_]|-)+)*))?)?)?(?=:\{?\n)', bygroups(String.Symbol, Operator, Number.Integer, Operator, Number.Integer, Operator, Number.Integer, Operator, String, Operator, String)),

(r'.*\n', Text),
]
}
145 changes: 145 additions & 0 deletions tests/examplefiles/mcschema/actor_animation.mcschema
@@ -0,0 +1,145 @@
actor_animation:1.8.0:{
version "format_version"
object "animations"
{
object "animation.<identifier>"
{
bool "loop" : opt // should this animation stop, loop, or stay on the last frame when finished (true, false, "hold_on_last_frame"
string "loop"<"hold_on_last_frame"> : opt // should this animation stop, loop, or stay on the last frame when finished (true, false, "hold_on_last_frame"
molang "start_delay" : opt // How long to wait in seconds before playing this animation. Note that this expression is evaluated once before playing, and only re-evaluated if asked to play from the beginning again. A looping animation should use 'loop_delay' if it wants a delay between loops.
molang "loop_delay" : opt // How long to wait in seconds before looping this animation. Note that this expression is evaluated after each loop and on looping animation only.
molang "anim_time_update" : opt // how does time pass when playing the animation. Defaults to "query.anim_time + query.delta_time" which means advance in seconds.
molang "blend_weight" : opt
bool "override_previous_animation" : opt // reset bones in this animation to the default pose before applying this animation
object "bones" : opt
{
object "<identifier>"
{
object "relative_to" : opt
{
string "rotation"<"entity"> : opt // if set, makes the bone rotation relative to the entity instead of the bone's parent
}
molang "position" : opt
array "position" : opt
{
molang "<any array element>"
}
object "position" : opt
{
array "<time_stamp>"[3]
{
molang "<any array element>"
}
object "<time_stamp>"
{
enumerated_value "lerp_mode"<"linear", "catmullrom"> : opt
array "pre"[3] : opt
{
molang "<any array element>"
}
array "post"[3] : opt
{
molang "<any array element>"
}
}
}
molang "rotation" : opt
array "rotation" : opt
{
molang "<any array element>"
object "<any array element>"
{
molang "[xyz]"
}
}
object "rotation" : opt
{
array "<time_stamp>"[3]
{
molang "<any array element>"
}
object "<time_stamp>"
{
enumerated_value "lerp_mode"<"linear", "catmullrom"> : opt
array "pre"[3] : opt
{
molang "<any array element>"
}
array "post"[3] : opt
{
molang "<any array element>"
}
}
}
molang "scale" : opt
array "scale" : opt
{
molang "<any array element>"
}
object "scale" : opt
{
array "<time_stamp>"[3]
{
molang "<any array element>"
}
object "<time_stamp>"
{
enumerated_value "lerp_mode"<"linear", "catmullrom"> : opt
array "pre"[3] : opt
{
molang "<any array element>"
}
array "post"[3] : opt
{
molang "<any array element>"
}
}
}
}
}
object "particle_effects" : opt
{
object "<time_stamp>" : opt
{
string "effect" // The name of a particle effect that should be played
string "locator" : opt // The name of a locator on the actor where the effect should be located
molang "pre_effect_script" : opt // A Molang script that will be run when the particle emitter is initialized
bool "bind_to_actor" : opt // Set to false to have the effect spawned in the world without being bound to an actor (by default an effect is bound to the actor).
}
array "<time_stamp>" : opt
{
object "<any array element>" : opt
{
string "effect" // The name of a particle effect that should be played
string "locator" : opt // The name of a locator on the actor where the effect should be located
molang "pre_effect_script" : opt // A Molang script that will be run when the particle emitter is initialized
bool "bind_to_actor" : opt // Set to false to have the effect spawned in the world without being bound to an actor (by default an effect is bound to the actor).
}
}
}
object "sound_effects" : opt // sound effects to trigger as this animation plays, keyed by time
{
object "<time_stamp>" : opt
{
string "effect" // Valid sound effect names should be listed in the entity's resource_definition json file.
}
array "<time_stamp>" : opt
{
object "<any array element>" : opt
{
string "effect" // Valid sound effect names should be listed in the entity's resource_definition json file.
}
}
}
object "timeline" : opt
{
string "<time_stamp>" : opt
array "<time_stamp>" : opt
{
string "<any array element>" : opt
}
}
float "animation_length" : opt // override calculated value (set as the max keyframe or event time) and set animation length in seconds.
}
}
}