:copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS.
:license: BSD, see LICENSE for details. """
import re
from pygments.lexer import bygroups, default, inherit, words from pygments.lexers.lisp import SchemeLexer from pygments.lexers._lilypond_builtins import (
keywords, pitch_language_names, clefs, scales, repeat_types, units,
chord_modifiers, pitches, music_functions, dynamics, articulations,
music_commands, markup_commands, grobs, translators, contexts,
context_properties, grob_properties, scheme_functions, paper_variables,
header_variables
) from pygments.token import Token
__all__ = ["LilyPondLexer"]
# In LilyPond, (unquoted) name tokens only contain letters, hyphens, # and underscores, where hyphens and underscores must not start or end # a name token. # # Note that many of the entities listed as LilyPond built-in keywords # (in file `_lilypond_builtins.py`) are only valid if surrounded by # double quotes, for example, 'hufnagel-fa1'. This means that # `NAME_END_RE` doesn't apply to such entities in valid LilyPond code.
NAME_END_RE = r"(?=\d|[^\w\-]|[\-_][\W\d])"
class LilyPondLexer(SchemeLexer): """
Lexer for input to LilyPond, a text-based music typesetter.
.. important::
This lexer is meant to be used in conjunction with the ``lilypond`` style. """
name = 'LilyPond'
url = 'https://lilypond.org'
aliases = ['lilypond']
filenames = ['*.ly']
mimetypes = []
version_added = '2.11'
flags = re.DOTALL | re.MULTILINE
# Because parsing LilyPond input is very tricky (and in fact # impossible without executing LilyPond when there is Scheme # code in the file), this lexer does not try to recognize # lexical modes. Instead, it catches the most frequent pieces # of syntax, and, above all, knows about many kinds of builtins.
# In order to parse embedded Scheme, this lexer subclasses the SchemeLexer. # It redefines the 'root' state entirely, and adds a rule for #{ #} # to the 'value' state. The latter is used to parse a Scheme expression # after #.
def get_tokens_unprocessed(self, text): """Highlight Scheme variables as LilyPond builtins when applicable.""" for index, token, value in super().get_tokens_unprocessed(text): if token is Token.Name.Function or token is Token.Name.Variable: if value in scheme_functions:
token = Token.Name.Builtin.SchemeFunction elif token is Token.Name.Builtin:
token = Token.Name.Builtin.SchemeBuiltin yield index, token, value
# End of embedded LilyPond in Scheme.
(r"#\}", Token.Punctuation, "#pop"),
# Embedded Scheme, starting with # ("delayed"), # or $ (immediate). #@ and and $@ are the lesser known # "list splicing operators".
(r"[#$]@?", Token.Punctuation, "value"),
# Any kind of punctuation: # - sequential music: { }, # - parallel music: << >>, # - voice separator: << \\ >>, # - chord: < >, # - bar check: |, # - dot in nested properties: \revert NoteHead.color, # - equals sign in assignments and lists for various commands: # \override Stem.color = red, # - comma as alternative syntax for lists: \time 3,3,2 4/4, # - colon in tremolos: c:32, # - double hyphen and underscore in lyrics: li -- ly -- pond __ # (which must be preceded by ASCII whitespace)
(r"""(?x)
\\\\
| (?<= \s ) (?: -- | __ )
| [{}<>=.,:|] """, Token.Punctuation),
# Pitches, with optional octavation marks, octave check, # and forced or cautionary accidental.
(words(pitches, suffix=r"=?[',]*!?\??" + NAME_END_RE), Token.Pitch),
# Strings, optionally with direction specifier.
(r'[\-_^]?"', Token.String, "string"),
# Numbers.
(r"-?\d+\.\d+", Token.Number.Float), # 5. and .5 are not allowed
(r"-?\d+/\d+", Token.Number.Fraction), # Integers, or durations with optional augmentation dots. # We have no way to distinguish these, so we highlight # them all as numbers. # # Normally, there is a space before the integer (being an # argument to a music function), which we check here. The # case without a space is handled below (as a fingering # number).
(r"""(?x)
(?<= \s ) -\d+
| (?: (?: \d+ | \\breve | \\longa | \\maxima )
\.* ) """, Token.Number), # Separates duration and duration multiplier highlighted as fraction.
(r"\*", Token.Number),
# Builtins.
(builtin_words(keywords, "mandatory"), Token.Keyword),
(builtin_words(pitch_language_names, "disallowed"), Token.Name.PitchLanguage),
(builtin_words(clefs, "disallowed"), Token.Name.Builtin.Clef),
(builtin_words(scales, "mandatory"), Token.Name.Builtin.Scale),
(builtin_words(repeat_types, "disallowed"), Token.Name.Builtin.RepeatType),
(builtin_words(units, "mandatory"), Token.Number),
(builtin_words(chord_modifiers, "disallowed"), Token.ChordModifier),
(builtin_words(music_functions, "mandatory"), Token.Name.Builtin.MusicFunction),
(builtin_words(dynamics, "mandatory"), Token.Name.Builtin.Dynamic), # Those like slurs that don't take a backslash are covered above.
(builtin_words(articulations, "mandatory"), Token.Name.Builtin.Articulation),
(builtin_words(music_commands, "mandatory"), Token.Name.Builtin.MusicCommand),
(builtin_words(markup_commands, "mandatory"), Token.Name.Builtin.MarkupCommand),
(builtin_words(grobs, "disallowed"), Token.Name.Builtin.Grob),
(builtin_words(translators, "disallowed"), Token.Name.Builtin.Translator), # Optional backslash because of \layout { \context { \Score ... } }.
(builtin_words(contexts, "optional"), Token.Name.Builtin.Context),
(builtin_words(context_properties, "disallowed"), Token.Name.Builtin.ContextProperty),
(builtin_words(grob_properties, "disallowed"),
Token.Name.Builtin.GrobProperty, "maybe-subproperties"), # Optional backslashes here because output definitions are wrappers # around modules. Concretely, you can do, e.g., # \paper { oddHeaderMarkup = \evenHeaderMarkup }
(builtin_words(paper_variables, "optional"), Token.Name.Builtin.PaperVariable),
(builtin_words(header_variables, "optional"), Token.Name.Builtin.HeaderVariable),
# Other backslashed-escaped names (like dereferencing a # music variable), possibly with a direction specifier.
(r"[\-_^]?\\.+?" + NAME_END_RE, Token.Name.BackslashReference),
# Definition of a variable. Support assignments to alist keys # (myAlist.my-key.my-nested-key = \markup \spam \eggs).
(r"""(?x)
(?: [^\W\d] | - )+
(?= (?: [^\W\d] | [\-.] )* \s* = ) """, Token.Name.Lvalue),
# Virtually everything can appear in markup mode, so we highlight # as text. Try to get a complete word, or we might wrongly lex # a suffix that happens to be a builtin as a builtin (e.g., "myStaff").
(r"([^\W\d]|-)+?" + NAME_END_RE, Token.Text),
(r".", Token.Text),
], "string": [
(r'"', Token.String, "#pop"),
(r'\\.', Token.String.Escape),
(r'[^\\"]+', Token.String),
], "value": [ # Scan a LilyPond value, then pop back since we had a # complete expression.
(r"#\{", Token.Punctuation, ("#pop", "root")),
inherit,
], # Grob subproperties are undeclared and it would be tedious # to maintain them by hand. Instead, this state allows recognizing # everything that looks like a-known-property.foo.bar-baz as # one single property name. "maybe-subproperties": [
(r"\s+", Token.Text.Whitespace),
(r"(\.)((?:[^\W\d]|-)+?)" + NAME_END_RE,
bygroups(Token.Punctuation, Token.Name.Builtin.GrobProperty)),
default("#pop"),
]
}
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.