Rix is the official package layer for Vix.cpp Browse packages
Skip to content

Format

This page explains the formatting helpers provided by rix/debug.

The examples use the public Rix facade:

cpp
#include <rix.hpp>

and access formatting through:

cpp
rix.debug.format

Formatting is useful when you want to build a string with placeholders before printing it, storing it, returning it, or passing it to another API.

For production application logs, prefer the Vix logging system.

Basic example

Create a file:

bash
mkdir -p ~/rix-debug-format
cd ~/rix-debug-format
touch format.cpp

Add:

cpp
#include <rix.hpp>

#include <string>

int main()
{
  const std::string one =
      rix.debug.format("Hello, {}", "Ada");

  const std::string two =
      rix.debug.format(
          "{0} builds on {1}",
          "Rix",
          "Vix.cpp");

  const std::string three =
      rix.debug.format(
          "{{ package }} = {}",
          "rix/debug");

  rix.debug.print(one);
  rix.debug.print(two);
  rix.debug.print(three);

  return 0;
}

Run it:

bash
vix run format.cpp

If Rix is not available yet for single-file usage:

bash
vix install -g rix/rix
vix run format.cpp

Expected output

The output should look like this:

txt
Hello, Ada
Rix builds on Vix.cpp
{ package } = rix/debug

rix.debug.format

Use:

cpp
rix.debug.format(...)

to create a formatted string.

Example:

cpp
const auto message =
    rix.debug.format("Package: {}", "rix/debug");

rix.debug.print(message);

Output:

txt
Package: rix/debug

format returns a std::string.

It does not print by itself.

Automatic placeholders

Use {} to insert arguments in order:

cpp
const auto message =
    rix.debug.format("{} uses {}", "Rix", "C++");

Output:

txt
Rix uses C++

Each {} consumes the next argument.

Example:

cpp
const auto message =
    rix.debug.format(
        "name: {}, language: {}, rows: {}",
        "Ada",
        "C++",
        3);

Output:

txt
name: Ada, language: C++, rows: 3

Explicit placeholders

Use {0}, {1}, and other numeric indexes when the position should be explicit:

cpp
const auto message =
    rix.debug.format("{0} + {0} = {1}", "C++", "Vix.cpp");

Output:

txt
C++ + C++ = Vix.cpp

Explicit indexes are useful when the same value appears more than once.

Do not mix placeholder styles

Do not mix automatic placeholders and explicit placeholders in the same format string.

Wrong:

cpp
rix.debug.format("{} {0}", "Rix");

Use automatic placeholders:

cpp
rix.debug.format("{} {}", "Rix", "Debug");

or explicit placeholders:

cpp
rix.debug.format("{0} {1}", "Rix", "Debug");

Escaped braces

Use double opening braces and double closing braces when you need literal braces:

cpp
const auto message =
    rix.debug.format("{{ package }} = {}", "rix/debug");

Output:

txt
{ package } = rix/debug

This is useful when printing template-like text, configuration blocks, or examples.

Unsupported format specifiers

rix.debug.format intentionally keeps formatting small.

It does not support format specifiers such as:

txt
{:>10}
{:.2f}
{:04d}

Wrong:

cpp
rix.debug.format("{:.2f}", 3.14159);

Use simple placeholders:

cpp
rix.debug.format("value: {}", 3.14159);

For advanced formatting, use another formatting library or normal C++ formatting tools where appropriate.

Format different value types

rix.debug.format uses the Rix rendering pipeline.

You can format strings, numbers, booleans, and other supported printable values.

cpp
const auto message =
    rix.debug.format(
        "name: {}, rows: {}, ready: {}",
        "Ada",
        3,
        true);

rix.debug.print(message);

Output shape:

txt
name: Ada, rows: 3, ready: true

Append formatted output

Use:

cpp
rix.debug.format.append(...)

to append formatted text to an existing string.

Example:

cpp
std::string out = "Rix: ";

rix.debug.format.append(
    out,
    "{}",
    "debug");

rix.debug.print(out);

Output:

txt
Rix: debug

Append is useful when you are building a longer string in steps.

Replace a string with formatted output

Use:

cpp
rix.debug.format.to(...)

to replace an existing string with formatted output.

Example:

cpp
std::string out = "old value";

rix.debug.format.to(
    out,
    "Package: {}",
    "rix/debug");

rix.debug.print(out);

Output:

txt
Package: rix/debug

The previous content of out is cleared.

format vs print

Use format when you need a string:

cpp
const auto message =
    rix.debug.format("rows: {}", 3);

rix.debug.print(message);

Use print when you only want to write values immediately:

cpp
rix.debug.print("rows:", 3);

print separates values with spaces.

format replaces placeholders and returns a string.

format vs sprint

Use format when you want placeholder-based formatting:

cpp
const auto message =
    rix.debug.format("Package: {}", "rix/debug");

Use sprint when you want the same rendering style as print, but returned as a string:

cpp
const auto line =
    rix.debug.sprint("Package:", "rix/debug");

Both return std::string.

The difference is the style:

txt
format -> placeholder replacement
sprint -> print-style value joining

Complete append example

cpp
#include <rix.hpp>

#include <string>

int main()
{
  std::string output;

  rix.debug.format.append(
      output,
      "package: {}\n",
      "rix/debug");

  rix.debug.format.append(
      output,
      "status: {}\n",
      "ready");

  rix.debug.format.append(
      output,
      "rows: {}\n",
      3);

  rix.debug.print(output);

  return 0;
}

Run:

bash
vix run format.cpp

Expected output:

txt
package: rix/debug
status: ready
rows: 3

Complete replace example

cpp
#include <rix.hpp>

#include <string>

int main()
{
  std::string message;

  rix.debug.format.to(
      message,
      "Hello, {}",
      "Rix");

  rix.debug.print(message);

  rix.debug.format.to(
      message,
      "Package: {}",
      "rix/debug");

  rix.debug.print(message);

  return 0;
}

Run:

bash
vix run format.cpp

Expected output:

txt
Hello, Rix
Package: rix/debug

Formatting errors

Invalid format strings can throw rixlib::format_error.

Examples of invalid usage:

cpp
rix.debug.format("{", "Rix");
rix.debug.format("}", "Rix");
rix.debug.format("{2}", "Rix");
rix.debug.format("{} {0}", "Rix");
rix.debug.format("{:.2f}", 3.14);

For examples and small tools, keep format strings simple.

For user-provided format strings, handle errors explicitly.

Example:

cpp
try
{
  const auto message =
      rix.debug.format("{} {}", "Rix", "Debug");

  rix.debug.print(message);
}
catch (const rixlib::format_error &error)
{
  rix.debug.eprint("format error:", error.what());
  return 1;
}

Format CSV output messages

Formatting is useful when reporting CSV results:

cpp
#include <rix.hpp>

int main()
{
  const auto table = rix.csv.parse(
      "name,language\n"
      "Ada,C++\n"
      "Gaspard,Vix\n");

  const auto message =
      rix.debug.format("loaded {} rows", table.size());

  rix.debug.print(message);

  return 0;
}

Format Auth errors

Formatting can help create readable Auth diagnostics:

cpp
#include <rix.hpp>

int main()
{
  auto auth = rix.auth.memory();

  auto login = auth.login({
      "ada@example.com",
      "wrong-password"});

  if (login.failed())
  {
    const auto &error = login.error();

    const auto message =
        rix.debug.format(
            "auth error: {}: {}",
            rix.auth.error.to_string(error),
            error.message());

    rix.debug.eprint(message);
    return 1;
  }

  return 0;
}

Do not format or print authentication secrets in production.

Avoid printing:

txt
plain-text passwords
password hashes
session ids
raw token values

Format PDF messages

Formatting is useful when reporting generated files:

cpp
#include <rix.hpp>

int main()
{
  auto saved = rix.pdf.make_text(
      "hello.pdf",
      "Hello from rix.pdf",
      "Rix PDF");

  if (saved.failed())
  {
    const auto message =
        rix.debug.format(
            "pdf error: {}: {}",
            rix.pdf.error.to_string(saved.error()),
            saved.error().message());

    rix.debug.eprint(message);
    return 1;
  }

  rix.debug.print(
      rix.debug.format("created: {}", "hello.pdf"));

  return 0;
}

Use in a Vix project

Create a Vix application:

bash
vix new debug-format --app
cd debug-format

Add Rix:

bash
vix add rix/rix
vix install

In vix.app, make sure Rix is listed under deps:

txt
deps = [
  "rix/rix",
]

A small vix.app can look like this:

txt
name = "debug-format"
type = "executable"
standard = "c++20"
output_dir = "bin"

sources = [
  "src/main.cpp",
]

include_dirs = [
  "include",
  "src",
]

deps = [
  "rix/rix",
]

packages = [
  "vix",
]

links = [
  "vix::vix",
]

Then use formatting in src/main.cpp:

cpp
#include <rix.hpp>

int main()
{
  const auto message =
      rix.debug.format("Package: {}", "rix/debug");

  rix.debug.print(message);

  return 0;
}

Build and run:

bash
vix build
vix run

Single-file usage

For small scripts, examples, and experiments:

bash
vix run format.cpp

If Rix is installed globally for single-file usage:

bash
vix install -g rix/rix
vix run format.cpp

For project usage, prefer:

bash
vix add rix/rix
vix install

and keep the dependency in vix.app:

txt
deps = [
  "rix/rix",
]

Use only Debug with the facade

If you want the rix.* facade style but only want Debug mounted, define the feature macro before including rix.hpp:

cpp
#define RIX_ENABLE_DEBUG
#include <rix.hpp>

int main()
{
  const auto message =
      rix.debug.format("Hello, {}", "Rix");

  rix.debug.print(message);

  return 0;
}

When at least one RIX_ENABLE_* macro is defined, only selected modules are mounted.

Use the independent package

For independent usage, install:

bash
vix add rix/debug
vix install

In vix.app:

txt
deps = [
  "rix/debug",
]

Then include the independent package header:

cpp
#include <rix/debug.hpp>

Use this style when a project only needs Debug and does not need the full unified Rix facade.

For most application documentation, prefer:

cpp
#include <rix.hpp>

Logging note

rix.debug.format creates strings.

It is useful for examples and local diagnostics.

For real application logs, prefer the Vix logging system.

Use this rule:

txt
rix.debug -> examples, local diagnostics, quick tools
Vix logging -> production logs, service logs, request logs

Common mistakes

Expecting print to replace placeholders

Wrong:

cpp
rix.debug.print("Package: {}", "rix/debug");

Use format:

cpp
rix.debug.print(
    rix.debug.format("Package: {}", "rix/debug"));

Mixing automatic and explicit placeholders

Wrong:

cpp
rix.debug.format("{} {0}", "Rix");

Use one style:

cpp
rix.debug.format("{} {}", "Rix", "Debug");

or:

cpp
rix.debug.format("{0} {1}", "Rix", "Debug");

Using unsupported format specifiers

Wrong:

cpp
rix.debug.format("{:.2f}", 3.14159);

Use simple placeholders:

cpp
rix.debug.format("value: {}", 3.14159);

Forgetting escaped braces

Wrong:

cpp
rix.debug.format("{ package } = {}", "rix/debug");

Use:

cpp
rix.debug.format("{{ package }} = {}", "rix/debug");

Formatting secrets

Do not format or print:

txt
plain-text passwords
password hashes
session ids
raw token values

This matters especially with rix/auth.

Forgetting deps

For a Vix project, do not put Rix packages in packages.

Use:

txt
deps = [
  "rix/rix",
]

packages is for CMake package discovery.

deps is for Vix Registry packages.

What you should remember

Format a string:

cpp
auto message = rix.debug.format("Hello, {}", "Rix");

Use automatic placeholders:

cpp
rix.debug.format("{} uses {}", "Rix", "C++");

Use explicit placeholders:

cpp
rix.debug.format("{0} + {0} = {1}", "C++", "Vix.cpp");

Escape braces:

cpp
rix.debug.format("{{ package }} = {}", "rix/debug");

Append:

cpp
rix.debug.format.append(out, "{}", "debug");

Replace:

cpp
rix.debug.format.to(out, "Package: {}", "rix/debug");

Use simple placeholders only.

For a Vix project, install Rix:

bash
vix add rix/rix
vix install

and use:

txt
deps = [
  "rix/rix",
]

Next step

Learn inspection.

Next: Inspect

Released under the MIT License.