Adding text

Add Markdown text to a document with the @, |, and call forms.

Every line of prose in a CMX document is a text block. You append one by handing a string to doc. Start with the example, then pick the form that reads best.

from cmx import doc

doc.config(__file__)

doc @ "# Experiment Report"
doc @ "Training finished. Results follow."

doc.flush()
# Experiment Report
Training finished. Results follow.

The three equivalent forms

There are three ways to append a text block. They do the same thing — append a Text block (with end="\n" by default) and return doc — so you can chain further calls off any of them.

doc("# Title", end="\n")   # call form (end="\n" is the default)
doc @ "# Title"            # prefix @ operator
"# Title" | doc            # postfix | operator

Every block ends with end="\n" unless you override it on the call form — see Controlling line endings below.

A tuple spreads into one block per item:

doc @ ("First paragraph.", "Second paragraph.")

Warning

The pipe only works with the string on the left: "text" | doc. The left-side form doc | other raises NotImplementedError.

Multi-line text and dedent

Use a triple-quoted string for multi-line content. Text is dedented by default (dedent=True), so the common leading indentation is stripped and indented source stays clean in the output.

with doc:
    doc @ """
    ## Results

    The model converged after 12 epochs.

    - Accuracy: 0.97
    - Loss: 0.08
    """
## Results

The model converged after 12 epochs.

- Accuracy: 0.97
- Loss: 0.08

The leading spaces from the source indentation are gone, but the blank lines and list structure are preserved.

Controlling line endings with end=

Each text block ends with a single newline by default (end="\n"). Pass end= on the call form to change it. Only the trailing run of newlines is replaced — newlines inside the block are left alone.

Use end="" to keep the next block on the same line:

doc("Status: ")
doc("OK")
Status:
OK

With end="" on the first block, the two join:

doc("Status: ", end="")
doc("OK")
Status: OK

Because only the trailing newlines change, a multi-line block keeps its internal structure while you control just the final separator.

Note

end= is a keyword argument, so it is available on the call form doc("...", end="..."). The @ and | operators take a single value and use the default ending.

When to use each form

All three forms are functionally identical; choose for readability.

Form

Reads best for

doc("...")

Passing arguments such as end=; explicit, lints cleanly.

doc @ "..."

Quick prose where the document leads the line.

`“…”

doc`

Be consistent within a file. Reach for the call form whenever you need a keyword argument, since @ and | accept only the text.

Inside with doc:

All three forms work inside a capture block. The captured source and any text you append appear in document order, interleaved with doc.print() output.

with doc:
    doc @ "## Summary"
    "Run completed without errors." | doc
    doc.print(f"Elapsed: {elapsed:.1f}s")

Next steps

  • Printing — Add computed output with doc.print().

  • Context managers — Control what appears using with doc:, doc.hide, and doc.skip.