Convert Callouts to Definition Lists
Converts AsciiDoc code blocks with callout-style annotations to a cleaner definition list format with “where:” prefix.
Choosing the Right Tool
This is the batch conversion tool - it processes all code blocks with a single target format. Use this when you want consistent formatting across all files or need to automate conversions in scripts.
For per-code-block control where you choose the format for each individual code block interactively, see convert-callouts-interactive.
Quick Decision Guide:
- Same format for all blocks → Use this tool (
convert-callouts-to-deflist
)- Different formats per block → Use
convert-callouts-interactive
- Automation/CI pipelines → Use this tool (
convert-callouts-to-deflist
)- Editorial review needed → Use
convert-callouts-interactive
Overview
Traditional AsciiDoc callouts use numbered markers (<1>
, <2>
, etc.) in code blocks with corresponding explanation lines below. This format can be visually cluttered and harder to maintain. This tool converts them to a cleaner definition list format that uses the actual code lines as terms.
Important: This tool is designed to assist your conversion efforts. You must:
- Carefully review all content changes before committing them to ensure accuracy and readability
- Pay special attention to merged callouts - when multiple callouts appear on the same line, their explanations are automatically merged (see example below)
- Pay attention to any warnings displayed during processing
- Review the warning summary at the end and address any callout mismatches before re-running
- Test documentation builds after converting to verify correctness
Installation
Install with the doc-utils package:
pipx install rolfedh-doc-utils
Then run directly as a command:
convert-callouts-to-deflist [options] [path]
The tool automatically processes all .adoc
files recursively in the specified directory (or current directory by default).
Transformation Examples
Example 1: Callouts with User-Replaceable Values
Before (Callout Style):
[source,yaml]
----
apiVersion: v1
kind: Secret
metadata:
name: <my-secret> <1>
data:
key: <my-key> <2>
----
<1> The secret name
<2> The secret key value
After (Definition List Style):
[source,yaml]
----
apiVersion: v1
kind: Secret
metadata:
name: <my-secret>
data:
key: <my-key>
----
where:
`<my-secret>`::
The secret name
`<my-key>`::
The secret key value
Example 2: Callouts Explaining Code Lines
Before (Callout Style):
[source,java]
----
httpSecurity
.get("/public/*").permit() <1>
.path("/admin/*").roles("admin") <2>
.path("/forbidden").authorization().deny(); <3>
----
<1> Permits all GET requests to paths matching `/public/*` without authentication.
<2> Restricts access to users with the `admin` role.
<3> Denies all access to the `/forbidden` path.
After (Definition List Style):
[source,java]
----
httpSecurity
.get("/public/*").permit()
.path("/admin/*").roles("admin")
.path("/forbidden").authorization().deny();
----
where:
`.get("/public/*").permit()`::
Permits all GET requests to paths matching `/public/*` without authentication.
`.path("/admin/*").roles("admin")`::
Restricts access to users with the `admin` role.
`.path("/forbidden").authorization().deny();`::
Denies all access to the `/forbidden` path.
Example 3: Multiple Callouts on Same Line (Merged Explanations)
⚠️ REVIEW CAREFULLY: When multiple callouts appear on the same code line, the tool automatically merges their explanations into a single definition list entry using AsciiDoc’s list continuation marker (+
). This behavior is correct for most cases, but you should verify that the merged explanations read naturally together.
Before (Callout Style):
[source,java]
----
@Path("hello")
public class HelloResource {
@BasicAuthentication <1> <2>
@Path("basic")
public String basicAuthMechanism() {
return "basic";
}
}
----
<1> Enables basic authentication for this endpoint.
<2> Authentication is required by default when using this annotation.
After (Definition List Style - Merged):
[source,java]
----
@Path("hello")
public class HelloResource {
@BasicAuthentication
@Path("basic")
public String basicAuthMechanism() {
return "basic";
}
}
----
where:
`@BasicAuthentication`::
Enables basic authentication for this endpoint.
+
Authentication is required by default when using this annotation.
Why This Matters:
- Both callouts reference the same code element (
@BasicAuthentication
) - Their explanations are semantically related (the first explains what it does, the second adds important context)
- The merged format is cleaner and avoids duplicate terms in the definition list
- The
+
continuation marker properly connects the related explanations
When to Review:
- If the merged explanations feel redundant or repetitive
- If the explanations would read better as separate items (consider refactoring the callouts in the source)
- If the order of explanations affects understanding (they merge in callout number order)
Output Formats
The tool supports three output formats, selectable via the --format
option:
Definition List Format (Default)
Uses AsciiDoc definition lists with “where:” prefix. This is the default format.
convert-callouts-to-deflist modules/
Output:
where:
`<my-secret>`::
The secret name
`<my-key>`::
The secret key value
Bulleted List Format
Uses AsciiDoc bulleted lists following the Red Hat Style Guide format. Best for explaining YAML structures or multi-line code blocks.
convert-callouts-to-deflist --format bullets modules/
Output:
* `<my-secret>`: The secret name
* `<my-key>`: The secret key value
Inline Comments Format
Converts callouts to inline comments within the code itself, using appropriate comment syntax for the code block’s language. This removes the separate explanation section entirely.
convert-callouts-to-deflist --format comments modules/
Output:
[source,yaml]
----
apiVersion: v1
kind: Secret
metadata:
name: <my-secret> # The secret name
data:
key: <my-key> # The secret key value
----
The tool automatically detects the programming language from the [source,language]
attribute and uses the appropriate comment syntax:
//
for Java, JavaScript, TypeScript, C, C++, Go, Rust, etc.#
for Python, Ruby, Bash, YAML, etc.--
for SQL, Lua<!--
for HTML, XML
When to use each format:
- Definition list (
--format deflist
): Default choice, works well for most cases, provides semantic “where:” prefix - Bulleted list (
--format bullets
): Follows Red Hat style guide, preferred for YAML files and complex configurations - Inline comments (
--format comments
): Best for code examples where explanations are brief and fit naturally as comments
All formats support merged callouts, optional markers, and user-replaceable values.
Usage
Process All Files in Current Directory (Default)
convert-callouts-to-deflist
Automatically scans all .adoc
files recursively in the current directory.
Process Specific Directory
convert-callouts-to-deflist modules/
Process Single File
convert-callouts-to-deflist assemblies/my-guide.adoc
Preview Changes (Dry Run)
convert-callouts-to-deflist --dry-run
Shows what would be changed without modifying files.
Exclude Directories
convert-callouts-to-deflist --exclude-dir archive --exclude-dir temp
Excludes specified directories from processing. Note: .vale
is excluded by default.
Use Exclusion List File
convert-callouts-to-deflist --exclude-list .docutils-ignore
Example .docutils-ignore
file:
# Directories to exclude
.vale/
archive/
temp/
# Specific files
test-file.adoc
Verbose Mode
convert-callouts-to-deflist --verbose
Shows detailed processing information.
Options
path
- File or directory to process (default: current directory)-n, --dry-run
- Preview changes without modifying files-v, --verbose
- Enable detailed logging-f, --format {deflist,bullets,comments}
- Output format: “deflist” for definition list with “where:” (default), “bullets” for bulleted list per Red Hat style guide, “comments” for inline comments--exclude-dir DIR
- Exclude directory (can be used multiple times)--exclude-file FILE
- Exclude file (can be used multiple times)--exclude-list FILE
- Load exclusion list from file-h, --help
- Show help message
Features
Intelligent Value Extraction
The script extracts user-replaceable values from code:
- Primary Method: Extracts angle-bracket enclosed replacement values (
<value>
) from the code line. - Fallback: If no replacement value found in code, extracts the line of code.
- Heredoc-aware: Ignores heredoc syntax (
<<EOF
) and only captures user values
Validation and Safety
The script validates callouts before converting:
- Ensures callout numbers in code match explanation numbers
- Skips blocks where numbers don’t match (prevents false conversions)
- Preserves legitimate angle brackets (e.g., Java generics like
List<String>
) - Non-destructive: Always test with
--dry-run
first
Optional Markers
Preserves optional markers from explanations:
Input:
<2> Optional. The name of the ConfigMap
Output:
`<config-name>`::
Optional. The name of the ConfigMap
Non-Sequential Callouts
Handles non-sequential callout numbers correctly:
<1> First item
<3> Third item
<5> Fifth item
Edge Cases Handled
- Multiple code blocks - Processes each block independently
- Multiple callouts on same line - Automatically merges explanations using AsciiDoc
+
continuation marker - Non-sequential numbers - Handles callouts like
<1>
,<3>
,<5>
- Heredoc syntax - Ignores
<<EOF
and similar patterns - Legitimate angle brackets - Skips Java generics, comparison operators, etc.
- Mixed content - Preserves text before and after code blocks
- Different delimiters - Supports both
----
and....
code block delimiters - No language specified - Works with
[source]
blocks without language - Callout mismatches - Skips blocks where numbers don’t align and displays a warning with file and line numbers
- Vale fixtures - Automatically excludes
.vale
directory by default
Callout Mismatch Warnings
When the tool detects a mismatch between callout numbers in code and their explanations, it displays a warning immediately and skips that code block:
WARNING: my-file.adoc lines 141-145: Callout mismatch: code has [1, 2], explanations have [1, 3]
At the end of processing, a summary of all warnings is displayed:
Processed 147 AsciiDoc file(s)
Would modify 3 file(s) with 3 code block conversion(s)
⚠️ 2 Warning(s):
WARNING: file1.adoc lines 15-19: Callout mismatch: code has [1, 2], explanations have [2, 3]
WARNING: file2.adoc lines 141-145: Callout mismatch: code has [1, 2], explanations have [1, 3]
This prevents incorrect conversions when:
- Callout numbers are non-consecutive in the code but explanations use different numbers
- An explanation is missing for a callout in the code
- An explanation exists for a callout that’s not in the code
Real-World Example
Complex Secret Configuration
Before:
[source,yaml]
----
cat <<EOF | oc -n {my-product-namespace} create -f -
apiVersion: v1
kind: Secret
metadata:
name: <my-product-database-certificates-secrets> <1>
type: Opaque
stringData:
postgres-ca.pem: |-
-----BEGIN CERTIFICATE-----
<ca-certificate-key> <2>
postgres-key.key: |-
-----BEGIN CERTIFICATE-----
<tls-private-key> <3>
postgres-crt.pem: |-
-----BEGIN CERTIFICATE-----
<tls-certificate-key> <4>
EOF
----
<1> Specifies the name of the certificate secret.
<2> Specifies the CA certificate key.
<3> Optional. Specifies the TLS private key.
<4> Optional. Specifies the TLS certificate key.
After:
[source,yaml]
----
cat <<EOF | oc -n {my-product-namespace} create -f -
apiVersion: v1
kind: Secret
metadata:
name: <my-product-database-certificates-secrets>
type: Opaque
stringData:
postgres-ca.pem: |-
-----BEGIN CERTIFICATE-----
<ca-certificate-key>
postgres-key.key: |-
-----BEGIN CERTIFICATE-----
<tls-private-key>
postgres-crt.pem: |-
-----BEGIN CERTIFICATE-----
<tls-certificate-key>
EOF
----
where:
`<my-product-database-certificates-secrets>`::
Specifies the name of the certificate secret.
`<ca-certificate-key>`::
Specifies the CA certificate key.
`<tls-private-key>` Optional::
Specifies the TLS private key.
`<tls-certificate-key>` Optional::
Specifies the TLS certificate key.
Technical Details
Pattern Matching
- Code block detection:
^\[source(?:,\s*(\w+))?\]
followed by----
or....
- Callout in code:
<(\d+)>
(supports multiple callouts per line) - Callout explanation:
^<(\d+)>\s+(.+)$
- User values:
(?<!<)<([a-zA-Z][^>]*)>
(excludes heredoc syntax)
Processing Algorithm
- Parse document and identify all code blocks
- For each code block:
- Extract callout numbers and associated values from code
- Group callouts that appear on the same code line
- Extract callout explanations following the block
- Validate that numbers match
- If valid:
- Remove callout markers from code
- Create definition list from callout groups
- For groups with multiple callouts, merge explanations with
+
continuation - Replace old explanations with definition list
- Process blocks in reverse order to maintain line numbers
Limitations
- Only processes AsciiDoc files
- Requires exact
<N>
format for callouts (numbers only) - Callout explanations must immediately follow code blocks (with optional blank lines or
+
markers in between) - Supports continuation lines within callout explanations, but explanations must start with the
<N>
pattern
Testing
The repository includes a comprehensive test file: test-callouts.adoc
Run tests:
python3 convert-callouts-to-deflist.py test-callouts.adoc /tmp/output.adoc -v
The test file includes:
- Basic callouts
- Optional markers
- Complex examples with multiple values
- Non-sequential numbers
- Legitimate angle brackets (should be skipped)
- Mixed content scenarios
- Different code block delimiters
- Callout mismatches (should be skipped)
Best Practices
- Always work in a git branch before converting files
- Use
--dry-run
first to preview what will be changed - Choose the appropriate format:
- Use
--format deflist
(default) for general documentation - Use
--format bullets
for YAML files and complex configurations (follows Red Hat style guide)
- Use
- Review changes with
git diff
before committing - Test documentation builds after converting
- Start with a small batch to verify behavior
Example Workflow
# Create a feature branch
git checkout -b convert-callouts
# Preview changes on entire repository (.vale is excluded by default)
cd ~/rhbquarkus
convert-callouts-to-deflist --dry-run
# Example output:
# Found 292 AsciiDoc file(s) to process
# Would modify: asciidoc/logging.adoc (3 code block(s))
# Would modify: asciidoc/security-jwt.adoc (3 code block(s))
# ...
# Would modify 19 file(s) with 104 code block conversion(s)
# Process a specific directory
convert-callouts-to-deflist --dry-run asciidoc/
# Convert files
convert-callouts-to-deflist
# Review changes
git diff
# Test build
./scripts/build-docs.sh
# Commit changes
git add .
git commit -m "Convert callouts to definition list format"
# Or use bulleted list format for YAML files
convert-callouts-to-deflist --format bullets --dry-run deployment-guides/
convert-callouts-to-deflist --format bullets deployment-guides/
git commit -m "Convert YAML callouts to bulleted list format"
See the main Tools Reference for more documentation utilities.