BBEdit Language Playground User Guide

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.

Playground Documents

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.

Creating and Opening

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.

Basic Properties

The top section describes the language:

  • Name is the display name shown in BBEdit’s language menus and preferences.
  • Language Code is the language’s four-character code. Shorter codes are padded with spaces when the DLM is generated. New playgrounds use ???? as a placeholder so the sample preview can run; replace it before exporting.
  • Version is the language module’s marketing version, such as 1.0 or 2.1.3.
  • Extensions is a space- or comma-separated list of filename extensions, without leading periods.
  • Preferred Extension selects the preferred extension from the extension list.
  • File Names accepts exact file names and wildcard file names.
  • Identifier Characters optionally overrides the characters used for keyword and identifier recognition.
  • Comment Defaults specify the delimiters used by commands such as Un/Comment. If they are blank, the playground shows inferred defaults when it can.
  • Case Sensitive controls keyword and PCRE matching for language features that honor case sensitivity.

Rules

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.

Keywords

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.

Delimited

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.

Patterns

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.

Symbols

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.

Folds

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.

LSP

The LSP tab defines optional language server settings:

  • Command is the language server executable.
  • Arguments are the command-line arguments, such as --stdio.
  • Language ID is the identifier sent to the server for opened documents. If blank, BBEdit uses the lowercased language name with spaces replaced by hyphens.
  • Initialization Options is JSON used as language server initialization options.

Leave the LSP fields blank if the language does not have a language server.

Sample Text and Symbol Menu

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.

Issues

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.

Importing Legacy Codeless Language Modules

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.

Exporting and Installing

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.

Relationship to Declarative Language Modules

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.

Back to Technical Notes