Use when authoring or debugging MPS TextGen — concept-to-plain-text serialisation for languages whose final output is text (source files, config, scripts, DDL, XML, markdown). Covers `ConceptTextGenDeclaration` roots, `append` / `indent buffer` / `with indent` statements, text layout areas, context objects (e.g. imports sets), attributes, the base text gen component (`LanguageTextGenDeclaration`), binary `write`, `found error`, and the indentation-buffer model. Reach for this skill whenever the task involves editing `<lang>/languageModels/textGen.mps`.
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
TextGen turns a model (usually the output of generation) into plain text files. It is how BaseLanguage becomes .java on disk, and how any text-targeting language serialises its models. Lives in <lang>/languageModels/textGen.mps, language jetbrains.mps.lang.textGen. Rule bodies are BaseLanguage + smodel + textgen-specific statements (append, indent buffer, with indent).
Prerequisite for any insert: the textGen model must exist (mps_mcp_create_model with modelName: "<lang>.textGen" — aspect ID textGen, case-sensitive, no @ suffix; see aspect-model-stereotypes.md) and must import jetbrains.mps.lang.textGen, jetbrains.mps.baseLanguage, and jetbrains.mps.lang.smodel as used languages before the first mps_mcp_insert_root_node_from_json. Missing any of these three causes node inserts to fail with unresolved-concept errors. See step 1 of the Common-Path Workflow.
ConceptTextGenDeclaration root per concept you want to serialise. Only the file-generating root concept needs extension / filename / encoding; structural concepts inside the file need only textGenBlock.extension is a function body returning a string, not a literal property. It must return a string.ConceptTextGenDeclaration (even an empty one) — or its output will be silently missing. See references/dispatch-and-base-component.md.with indent / increase depth / decrease depth and the withIndent flag on NodeAppendPart only mutate the counter — whitespace is emitted only when indent buffer is called. Always pair append \n ; with indent buffer ; on the next line that should be indented. See references/indentation-model.md.with indent { ... } over paired increase depth ; … ; decrease depth ; — the block form cannot leak depth on an early return or exception. Use the paired form only when the scope is not a block.BinaryWriteOperation (write) cannot be mixed with text appends in the same ConceptTextGenDeclaration. A rule emits either text or bytes, not both.$ref{node.reference<target>} syntax is deprecated. Use a NodeAppendPart over a resolved node (or over .name).mps_mcp_insert_root_node_from_json, mps_mcp_update_node). Do not hand-edit .mps files.mps_mcp_check_root_node_problems and rebuild the language; regenerate consumers.textGen model (mps_mcp_create_model with modelName: "<lang>.textGen"; aspect ID is textGen — case-sensitive, no @ suffix) if absent, then before any insert add the three required used languages: jetbrains.mps.lang.textGen (for ConceptTextGenDeclaration, AppendOperation, parts, NodeParameter, etc.), jetbrains.mps.baseLanguage (for StatementList, DotExpression, control flow, returns), and jetbrains.mps.lang.smodel (for SPropertyAccess, SLinkAccess, SLinkListAccess used to read node data). Also add the structure language whose concepts you serialise (referenced by conceptDeclaration and inside smodel accesses), and jetbrains.mps.baseLanguage.collections if you use maps/lists. Skipping any of the three core languages causes mps_mcp_insert_root_node_from_json to fail with unresolved-concept errors — don't add them piecemeal after a failure.ConceptTextGenDeclaration root via mps_mcp_insert_root_node_from_json. The file-generating concept also needs extension, optionally encoding / filename / filePath / layout / contextObjects.textGenBlock body — a StatementList of appends, indent buffer, with indent { ... }, and standard BaseLanguage control flow. See references/statements-and-appends.md for the part vocabulary and references/json-blueprints.md for AST shapes.node.hasNewLineAfter() pattern). See references/delegating-to-behavior.md.TextUnitLayout, a UnitContextDeclaration in the base LanguageTextGenDeclaration, and per-concept UnitContextObjects. See references/layout-and-context-objects.md.mps_mcp_check_root_node_problems, rebuild the language module, regenerate any consumer, and inspect the produced text.| Aspect | Role |
|---|---|
| Generator | Model → Model (typed AST transformation) |
| TextGen | Model → Text (final serialisation) |
A custom language usually has both: a generator rewrites into BaseLanguage + runtime API, and BaseLanguage's TextGen emits .java. Write your own TextGen only if you target text directly (as jetbrains.mps.core.xml does).
mps-aspect-generator — model-to-model step that usually precedes TextGen; emits the AST you serialise.mps-aspect-behavior — host for layout-heuristic helper methods called from textgen bodies.mps-model-manipulation — BaseLanguage + smodel + collections used inside textgen bodies (StatementList, DotExpression, SLinkAccess, SLinkListAccess, StaticMethodCall).mps-quotations — anti-quotations may appear inside Quotations used as ${...} expression values.mps-aspect-structure-concepts — when introducing the concepts a textgen will serialise.references/concept-textgen-root.md when adding or editing a ConceptTextGenDeclaration — slot purposes (extension, encoding, filename, filePath, layout, contextObjects, textGenBlock), the editor shorthand, and what each child holds.references/statements-and-appends.md when writing the body — AppendOperation and its part vocabulary (ConstantStringAppendPart, NodeAppendPart, CollectionAppendPart, NewLineAppendPart), the $list{... with sep} form, BinaryWriteOperation (write), FoundErrorOperation (found error), control flow, and the smodel/behavior accessors usable inside a body.references/indentation-model.md when indentation is wrong — the depth-counter mental model, rules of thumb (always pair \n with indent buffer, prefer with indent { ... }, use withIndent flag for one-shot dispatch), and worked examples from IfStatement_TextGen, BlockStatement_TextGen, and ClassConcept_TextGen.references/layout-and-context-objects.md when emitting multi-region files (headers, imports, body) or threading per-generation state — TextUnitLayout with append to AREA { ... }, LanguageTextGenDeclaration, UnitContextDeclaration types, and per-concept UnitContextObject bindings (the imports-set pattern). Also covers attribute dispatch order (reverse containment) and ${attributed node}.references/dispatch-and-base-component.md for concept-exact dispatch — why an extending concept needs its own (possibly empty) ConceptTextGenDeclaration, and how the base LanguageTextGenDeclaration exposes reusable OperationDeclarations / UtilityMethodDeclarations / UnitContextDeclarations; inheriting between language base components via extends.references/delegating-to-behavior.md when textgen bodies grow tangled with formatting heuristics — the xml pattern of moving hasNewLineAfter / isMultiline / onNewLine into behavior and calling them from textgen, plus utility classes (XmlCharEscape) for escaping/formatting.references/json-blueprints.md when inserting nodes via MCP — full validated AST shapes for each statement/part (AppendOperation with literal/expression/list parts, WithIndentOperation, IncreaseDepthOperation/DecreaseDepthOperation, NodeAppendPart with withIndent), the minimal file-generating-concept skeleton, layout/context skeletons, and the full validated concept reference (FQNs, concept refs, child roles).references/common-failures.md when output is missing, indentation is broken, file extension is wrong, special characters appear unescaped, subclasses emit nothing, imports leak inline, attributes are ignored, or write and append collide.52c9d63
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.