Skip to content

Text markup

This document defines the syntax and semantics of text markup in neumaRk: common formatting rules applicable to all textual containers of the language (markers, end-decorators, comment-labels, note annotations, section labels, form prose).

The goal is to provide a unified and orthogonal system in which a first axis decides the graphical box (container), a second axis decides the default style (hosting construct), and a third axis — optional — allows the user to apply explicit markup.


1. Three orthogonal axes

Text rendering in neumaRk is a function of three independent axes:

  1. Container[…] (with box) or "…" (without box).
  2. Default style — determined by the hosting construct (marker, comment-label, annotation, prose, etc.).
  3. User markup — optional, defined through a subset of Markdown applied inside the container.

None of the three axes constrains the others. The same text can be expressed in any combination of box/no-box, any default semantics, with or without explicit markup.

Exception: marker M). In markers of the M) line (sections and annotations, see neumaRk_markers.md §3.1) the container […] vs "…" also carries structural semantics, not just a graphical box: […] = section (target of PLAY/FORM, delimits collapsible scopes), "…" = annotation (descriptive text, non-structural). The rule of "syntactic interchangeability" of §2.1 therefore has a normative exception in M).


2. Textual containers

2.1 Forms

A textual container is a sequence of characters delimited by:

  • []container with box;
  • ""container without box.

The two forms are syntactically interchangeable in every context that admits one of the two. The difference is the presence of the graphical box in rendering, except for markers of the M) line where the two forms also carry distinct structural semantics (section vs annotation, see neumaRk_markers.md §3.1).

2.2 Where markup applies

The markup defined in this document applies to all textual containers of the language:

Construct Allowed containers Reference
Section M) […] neumaRk_markers.md §3.1
Annotation M) "…" neumaRk_markers.md §3.1
Textual end-decorator […], "…" neumaRk_flow_and_repeats.md §4.3
Comment-label chord / group / row […], "…" neumaRk_chords.md §7
Note annotation […], "…" neumaRk_notes_and_durations.md §8
Dynamics D) annotation […], "…" neumaRk_dynamics.md §3.4
Articulation A) label (wave, bracket) "…" neumaRk_articulations.md §10.2/§10.3
Top/bottom section label box "…" neumaRk_play_and_form.md §3.3
Free prose in PLAY) / FORM) all the prose neumaRk_play_and_form.md §5

Markup does not apply to:

  • header values (title, credits, year, style, key, meter, BPM), which are rendered autonomously by the system;
  • technical marker names when referenced in PLAY) / FORM), where matching is by text-equality (markup, if present, is applied in display but stripped for matching);
  • volta begin (|[1.]), which is a predetermined box-like container and does not admit internal markup.

3. Markup syntax

neumaRk markup is a subset of Markdown, chosen to be deterministic and single-line.

3.1 Text size

The 3 prefixes #/##/### select a relative size that depends on the size role of the construct (see §5):

  • role reduced (default for: comment-label chord/group/row, note annotation, D) annotation, PLAY/FORM label, marker "…" annotation): the default is the smallest size; the prefixes scale only ABOVE.
  • role body (default for: marker M) [NAME], PLAY/FORM prose): the default is the medium size; the prefixes scale ABOVE and BELOW.
Prefix role reduced role body
# large (2.0× default) large (1.5× default)
## medium (1.5× default) medium (1.0× default = body)
### default (1.0×, = no prefix) small (0.7× default)

Rules:

  • the space after #/##/### is mandatory: #hashtag is literal, # title opens the span;
  • the prefix appears only at the beginning of the container text or at the beginning of a prose run (in PLAY) / FORM), after a structural token or at the beginning of the body);
  • the span opened by #/##/### closes at the first of the following events: end of the container, next structural token in PLAY) / FORM) ([…], &kw, $, @);
  • #### and beyond are treated as literals;
  • ### is allowed to make explicit one's own size level even if it is redundant with the default (e.g. in role reduced).

3.2 Emphasis

Three forms of emphasis, activated by paired delimiters:

Syntax Effect
*foo* italic
**foo** bold
***foo*** bold + italic

Rules:

  • the spans are closed delimiters: an unclosed * is literal (no partial render);
  • the closing asterisk must be preceded by non-empty content;
  • the spans may appear in any position of the text;
  • nesting is not allowed for emphasis (for example **foo *bar* baz** is invalid): the form ***foo*** is atomic.

3.3 Underline

Syntax activated by the double underscore:

Syntax Effect
__foo__ underline

Rules:

  • like the emphasis spans, the span is a closed delimiter: an unclosed __ is literal;
  • the closing __ must be preceded by non-empty content;
  • the span may appear in any position of the text;
  • single underscore _ is literal: _x_ is not alternative italic (NRK does not adopt the Markdown convention of _ as an alias of *);
  • ___foo___ (three or more opening/closing underscores) is treated as literal, analogously to #### for size prefixes.

Underline is not a form of emphasis: it is an orthogonal axis to bold/italic. The "no nesting of emphasis" rule of §3.2 does not apply to underline.

3.4 Combination

Multiple emphasis spans can coexist in the same text, provided they are disjoint:

*foo* and **bar**            ✓  disjoint italic + bold
*foo and **bar***            ✗  nesting not allowed
***foo*** plain ***bar***    ✓  two disjoint bold-italic spans

Underline is an orthogonal axis: it can coexist with bold and italic in the same span:

**__foo__**                  ✓  bold + underline
*__foo__*                    ✓  italic + underline
***__foo__***                ✓  bold + italic + underline
__**foo**__                  ✓  free delimiter order
__*foo* and **bar**__        ✓  underline over a span with internal disjoint emphasis

An emphasis or underline span can coexist with a size prefix: the prefix applies to the entire text span, the other delimiters modify only the inner portion:

# Title with **bold** and __underline__ words

4. Escape

The character \ (backslash) precedes a meta-character to make it literal.

Token Escaped form
* \*
_ \_
# \#
[ \[
] \]
" \"
\ \\

The escape \_ is needed when one wants to insert a literal __ in a text that would otherwise be consumed by the markup (rare: single _ are already literal by default).

Examples:

M) | [The \*Real\* Book] |
c4"track \#3"

A \ not followed by a meta-character is literal.


5. Default style per construct

The container […] vs "…" decides only the presence of the box. The default style (size, weight, italic) is a property of the hosting construct.

Construct Default style
Marker M) [NAME] bold, body size (role body, see §3.1)
Marker M) "…" annotation plain, reduced size (role reduced)
Textual end-decorator plain, body size (role body)
Comment-label chord / group / row italic, reduced size (role reduced)
Note annotation plain, reduced size (role reduced)
Dynamics D) annotation plain, reduced size (role reduced)
PLAY/FORM top/bottom label box plain, reduced size (role reduced)
PLAY/FORM prose plain, body size (role body)

The size role decides how the prefixes #/##/### scale above the default (see §3.1 table). Constructs with role body admit ### to go BELOW the default; those with role reduced do not (### = default).

User markup (§3) always overrides the default. For example in comment-label chord"*plain*" it stays italic (the construct default) and applies * as an additional visual override.


6. Parsing rules

6.1 Disambiguation of […] by role

In neumaRk the delimiter […] is shared among several constructs (polychord, volta, end-decorator, comment-label, note annotation, grace block, etc.). The disambiguation is positional and defined in the specs of the individual constructs. Once the parser has identified the role of the […], the content is interpreted according to the rules of this document.

6.2 Single-line inside container

The containers […] and "…" are single-line: they do not admit newline characters. A ] or " not closed within the end of the line is a parsing error.

The prose of PLAY) / FORM) admits line continuation (see related documents).

6.3 Empty containers

[] and "" are literals: they are not interpreted as containers.

6.4 Reserved prefixes

In note annotation, if the first character after the opening of the container is $ followed by a reserved uppercase letter ($F, $S, etc., see neumaRk_notes_and_durations.md §8), markup is disabled on the entire annotation: the content is interpreted as a structural directive (fingering, string number, etc.).


7. Edge cases

7.1 Markup in reference names

Inside [NAME] of references in PLAY) / FORM), the NAME is interpreted as text. The internal markup is applied in display but removed before matching with the defined markers:

PLAY) [**Solo**] [A]

[**Solo**] looks for a marker named "Solo" and renders it in bold if found. If the NAME contains unclosed or malformed markup, the fallback is literal matching including the markup characters.

7.2 Spaces around emphasis and underline delimiters

Unlike standard Markdown, neumaRk does not require that the delimiters (*, __) be "tight" with respect to the content: * foo * is equivalent to *foo*, __ foo __ is equivalent to __foo__. The choice reduces common errors and keeps the markup more tolerant.

7.3 Mix of containers in constructs that admit both

Sections that admit both containers ([…] and "…") may use them freely at different points of the same document. The choice is guided by the intended graphical meaning (with or without box).

M) | [Intro] | "freely" | [Verse 1] |

8. Summary

Axis Values Decides
Container […] / "…" box / no-box
Construct marker, label, annotation, … default size + weight + italic
User markup *…*, **…**, __…__, # …, etc. explicit override

The three axes are orthogonal. None of the three constrains the others.


This document defines the unified text formatting system of neumaRk, applicable to all textual containers of the language.