The Language Playground is BBEdit’s authoring environment for Declarative
Language Modules. It lets you describe a language, test the description against
sample text, review validation issues, and export an installable .bbdlm
language module.
The playground is designed for iterative work. You can add a rule, immediately see how it affects the sample text, adjust the rule, and export only when the generated module validates cleanly.
Language Playground documents use the .bblpg filename extension. A playground
document is not an installed language module; it is an authoring document that
stores editable rules, sample text, window state, and other information used by
the playground.
Saving a playground saves the .bblpg authoring document. Exporting from the
playground writes the generated .bbdlm runtime language module.
Choose File > New > Language Playground to create a new playground.
Opening a .bblpg file opens the saved playground document.
Opening a .bbdlm, .bbdlmd, or legacy codeless language module imports that
module into a new playground document. The imported runtime module is not edited
in place. The new playground’s suggested save name is based on the source module
name with a .bblpg extension.
You can also use the playground’s Import… button to import a legacy
codeless language module, a .bbdlm file, or a .bbdlmd package into the
current playground.
The top section describes the language:
???? as
a placeholder so the sample preview can run; replace it before exporting.1.0 or
2.1.3.The rule tabs describe the language’s syntax, symbols, folds, and optional language server settings. Use the add/remove segmented controls in each tab to create or delete rows. New rows are added at the end of the list. On the Delimited tab and in the Folds tab’s Paired Delimiters list, when the default start delimiter for a new row could never match – because a row already in the list, an enabled intrinsic fold (brace folds are on in a new playground), or on the Folds tab a delimited run would claim it first – the new row starts empty, with the insertion point in its start delimiter. Until you fill it in, the Issues tab reports the empty delimiter as an error, so export is disabled, and the sample text is colored and folded without that row.
Drag a row up or down to reorder the rules in a list. Row order is the order in which the rules are declared in the generated module. Where the module tries rules one after another and stops at the first that matches, the rule higher in the list wins; the notes under each tab say which lists work that way and when it matters.
The Keywords tab defines keyword groups. Each row has a run kind and a summary. Double-click the summary to edit the group in a popover.
A keyword group may contain literal keywords, a keyword PCRE pattern, or a keyword file reference when the generated module will be packaged. The playground can import a text file containing one keyword per line and merge the keywords into the selected keyword group. When no group is selected, or the selected group holds a keyword pattern or a keyword file reference rather than a word list, the keywords go into a new keyword group at the end of the list.
A word in a group’s literal keyword list always takes that group’s run kind,
even when a keyword pattern in a group higher in the list would also match it.
Keyword patterns are tried only for words that are in no literal list, in row
order, and the first pattern that matches the whole word wins. A word listed in
more than one group’s keyword list takes the run kind of the group highest in
the list, whether or not the language is case-sensitive; in a case-insensitive
language, IF and if count as the same word. The Issues tab warns about a
word that groups with different run kinds both list, and its navigation control
selects the lower group, whose run kind the word does not get.
The Delimited tab defines syntax spans that start with a literal delimiter and end at another literal delimiter or at the end of the line. Use these for common comments and strings.
Each row specifies a run kind, start delimiter, optional end delimiter, optional escape character, and whether the span ends at a line break.
Delimited runs are tried in row order at each position in the text, and the
first whose start delimiter matches wins. When one start delimiter begins with
another (for example """ and "), put the longer one higher in the list, or it
will never match. The Issues tab warns about a row that can never match, and
its navigation control selects that row.
The Patterns tab defines syntax runs with PCRE patterns. Use these for tokens that are not naturally described as fixed delimiters or keyword lists, such as numbers or special operators.
Double-click a pattern cell to edit the pattern in a syntax-colored popover. The popover validates the pattern before applying it.
When matches from different patterns overlap, the one that begins first wins, whatever its position in the list, and the other patterns resume matching after it. When two matches begin at the same place, the pattern higher in the list wins, whatever the lengths of the matches. Put more specific patterns (for example, an ISO 8601 date) above more general ones (such as the Numbers pattern) so that the general pattern does not claim the text first.
The Symbols tab defines function and symbol scanning rules. Each row specifies a PCRE function pattern, optional capture names, a function kind, and whether the symbol should generate a fold range.
Function patterns should provide a named capture for the displayed symbol name.
By default, BBEdit looks for function_name.
The sample text’s symbol menu updates from these rules, so you can test function and callout scanning without installing the module.
Every Symbols rule contributes its own matches; a rule lower in the list is never suppressed by one above it. When two rules match at the same place, the longer match’s entry comes first in the symbol menu and the shorter one is nested inside it; when the matches are the same length, the higher rule’s entry comes first and the lower rule’s is nested inside it.
The Folds tab defines automatic fold generation. You can enable intrinsic folds
for parentheses, braces, and brackets, and you can add explicit paired
delimiter folds such as begin / end.
Paired Delimiters rows specify a fold kind, start delimiter, and end delimiter.
They are tried in row order at each position, after the intrinsic folds, and
the first whose start delimiter matches wins. Put a longer start delimiter above
a shorter one it begins with, or it will never match. A pair whose start
delimiter begins with an enabled intrinsic bracket (for example \{\{ with brace
folds on) never opens, because the intrinsic fold is tried first. Nor does a
pair whose start delimiter begins with a delimited run’s (a #region pair with
a # line comment, for example), because the delimited run takes that text
first, unless the pair’s delimiters are exactly the run’s own. The Issues tab
warns about a pair that can never open.
Pattern Delimiters rows specify a fold kind, a start pattern, and an end pattern. Each rule’s patterns are matched on their own, so row order does not change where a rule’s delimiters match. Folds from different rules nest by position, but a fold that is still open when a fold opened before it closes is dropped. When two rules’ start patterns match at the same place, the higher rule’s fold is the outer one.
The LSP tab defines optional language server settings:
--stdio.Leave the LSP fields blank if the language does not have a language server.
The sample text view shows how the generated language module colors real text. As you change module properties or rules, BBEdit regenerates the language module description as needed and reapplies syntax coloring to the sample text.
The symbol menu above the sample text shows functions, symbols, and comment callouts found by the current symbol rules. Choosing an item in the menu selects the corresponding text in the sample.
The Issues tab lists validation errors, warnings, and notes for the generated module and the current sample text.
Errors are structural or content problems that prevent the generated DLM from loading. Export is disabled while errors are present.
Warnings identify conditions that do not prevent loading but may keep the module from behaving as expected.
When an issue refers to a specific rule row, the issue line includes a navigation control. Use it to switch to the relevant tab and select the corresponding row.
When a legacy codeless language module is imported, BBEdit translates the parts that have direct DLM equivalents into editable playground rules. This includes keyword lists and keyword patterns, comment/string/number patterns, simple delimited comments and strings, function patterns, identifier characters, filename matching, and language server settings.
Legacy-only loading data is omitted from the playground’s editable model and from DLMs exported by the playground.
A legacy module colors a word that it lists in more than one keyword list (for example, as both a keyword and a predefined name) with the run kind of the later list when it is case-sensitive, and of the earlier list when it is not. So that the imported rules color the same way, and give the Issues tab nothing to warn about, the import keeps each such word only in the group whose run kind it gets.
Click Export DLM… to write the generated .bbdlm file. The playground
validates the generated description before export; the button is disabled while
validation errors are present.
On export, the build number is incremented and written into the generated DLM. After writing the file, BBEdit reads the exported module back, validates it, and tries to create a temporary language module instance. This catches problems in the exported file before you install it.
After a successful export, BBEdit offers to install the module. Installing copies the exported DLM to BBEdit’s active Language Modules folder and offers to relaunch BBEdit so the language is available immediately.
If you export directly into the active Language Modules folder, BBEdit skips the install prompt and offers to relaunch.
The Language Playground is the preferred authoring surface. The exported DLM is the runtime language module that BBEdit loads.
For schema details and hand-authoring reference, see the Declarative Language Modules User Guide.