How to Preserve and Emit YAML Comments in yaml-cpp: A Complete Guide
yaml-cpp parses comments during scanning but discards them immediately—they are not stored in the node tree, so you must explicitly emit comments using the YAML::Comment helper and the emitter API.
The yaml-cpp library is a popular C++ parser and emitter for YAML files. While it handles the data structure perfectly, many developers are surprised to discover that comments are not preserved after parsing. If you need to retain or generate comments in your output, you must understand how to emit them manually using the library's emitter API. This guide explains how to preserve and emit YAML comments in yaml-cpp based on the actual source code implementation in the jbeder/yaml-cpp repository.
Why yaml-cpp Does Not Preserve Comments Automatically
Understanding the parser's behavior is essential before attempting to emit comments. The scanner recognizes comment tokens, but they never enter the node tree.
Comment Detection During Scanning
In src/scanner.cpp, the Scanner::ScanToNextToken method (lines 190-205) detects comments starting with # and skips them until a line break. The regular expression used for this pattern is defined in src/exp.h as Exp::Comment() (line 124). However, this token is discarded rather than stored.
The Node Tree Limitation
Because yaml-cpp's Node class represents only data values (scalars, sequences, and maps), there is no attachment point for comment metadata. This design choice keeps the API simple and memory-efficient, but it means you cannot retrieve comments from a parsed document.
How to Emit YAML Comments in yaml-cpp
To emit comments, you use the Emitter class with the YAML::Comment helper. This creates an internal _Comment object that the emitter knows how to format.
The Emitter API for Comments
The core emission logic resides in three locations:
src/emitter.cpp(lines 49-60): TheEmitter::Write(const _Comment&)overload receives the comment object and forwards it to the output routine.src/emitterutils.cpp(lines 58-75): TheUtils::WriteCommentfunction handles the actual formatting, including line break splitting and indentation.src/emitterstate.h(lines 106-109): Stores thepreCommentIndentandpostCommentIndentvalues that control spacing.
Basic Comment Emission Example
Here is how to emit a simple comment before a map:
YAML::Emitter out;
out.SetPreCommentIndent(2); // spaces before '#'
out.SetPostCommentIndent(1); // spaces after '#'
out << YAML::Comment("This is a comment");
out << YAML::BeginMap
<< YAML::Key << "name" << YAML::Value << "Alice"
<< YAML::EndMap;
std::cout << out.c_str();
Output:
# This is a comment
{
name: Alice
}
Controlling Comment Indentation
The Emitter class exposes two methods to control comment appearance:
SetPreCommentIndent(n): Sets how many spaces appear before the#character.SetPostCommentIndent(n): Sets how many spaces appear between the#and the comment text.
These values are stored in the EmitterState object and consulted by Utils::WriteComment when formatting output.
Advanced Comment Emission Patterns
Multi-line comments and programmatic document construction require specific handling to maintain proper formatting.
Multi-Line Comments
When you pass a string containing newlines to YAML::Comment, the emitter splits it and prefixes each line with the comment marker. The Utils::WriteComment implementation in src/emitterutils.cpp handles this automatically:
YAML::Emitter out;
out.SetPreCommentIndent(4); // four spaces before '#'
out.SetPostCommentIndent(0); // no space after '#'
out << YAML::Comment("First line\nSecond line\nThird line")
<< YAML::BeginSeq
<< "item1" << "item2"
<< YAML::EndSeq;
Output:
#First line
#Second line
#Third line
[
item1,
item2
]
Comments in Programmatic Document Construction
You can interleave comments when building documents from existing Node objects:
YAML::Node root;
root["version"] = "1.0";
YAML::Emitter out;
out << YAML::Comment("Generated by my tool")
<< YAML::BeginMap
<< YAML::Key << "settings" << YAML::Value << root
<< YAML::EndMap;
std::cout << out.c_str();
Output:
# Generated by my tool
{
settings:
version: 1.0
}
Summary
Key points for preserving and emitting YAML comments in yaml-cpp:
- yaml-cpp discards comments during parsing—they are recognized by the scanner in
src/scanner.cppbut never stored in the node tree. - Use
YAML::Commentwith anEmitterto emit comments explicitly; this creates an internal_Commentobject processed byEmitter::Writeinsrc/emitter.cpp. - Control indentation with
SetPreCommentIndentandSetPostCommentIndentto match your formatting requirements. - Multi-line comments are automatically split and re-indented by the
Utils::WriteCommentfunction insrc/emitterutils.cpp. - Comments cannot be retrieved from parsed documents—if you need to preserve comments from input, you must capture them separately before parsing.
Frequently Asked Questions
Can yaml-cpp preserve comments when loading a file?
No. The scanner in src/scanner.cpp detects and skips comments during tokenization, but they are not attached to the resulting Node objects. If you need to preserve comments from an existing file, you must implement a custom scanner or preprocess the file to capture comment positions separately.
How do I add comments to specific nodes in a YAML document?
Since comments are not node properties, you must emit them at the correct position in the output stream using YAML::Comment before the relevant content. The emitter processes comments in the order they are written, so place out << YAML::Comment("...") immediately before the key, value, or sequence element you want to annotate.
What is the difference between pre-comment and post-comment indentation?
Pre-comment indentation (SetPreCommentIndent) controls how many spaces appear before the # character, typically used to align comments with surrounding content. Post-comment indentation (SetPostCommentIndent) controls the space between the # and the comment text, commonly set to 1 for readability or 0 for compact output. These values are stored in EmitterState and applied by Utils::WriteComment in src/emitterutils.cpp.
Can I emit comments at the end of a line (inline comments)?
The yaml-cpp emitter API does not directly support inline end-of-line comments. The YAML::Comment helper emits comments on their own lines. To achieve inline comments, you would need to manipulate the raw output stream or use a different library, as the current implementation in src/emitter.cpp always places comments on new lines.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →