standout-render 3.4.0

Styled terminal rendering with templates, themes, and adaptive color support
Documentation

standout-render

Rich terminal output with templates, themes, and automatic light/dark mode support.

use standout_render::{render, Theme};
use console::Style;

let theme = Theme::new()
    .add("title", Style::new().cyan().bold())
    .add("count", Style::new().yellow());

let output = render(
    "[title]{{ name }}[/title]: [count]{{ count }}[/count] items",
    &json!({"name": "Tasks", "count": 42}),
    &theme,
)?;

Why standout-render?

Terminal output is stuck in the 1970s: scattered println! statements, cryptic ANSI escape codes, and presentation logic tangled with business logic. Every change requires recompilation. Nobody bothers with polish because iteration is painful.

standout-render fixes this with ideas borrowed from web development:

  • Templates — MiniJinja (Jinja2 syntax) for readable, declarative output
  • Style tags — BBCode-like [style]content[/style] syntax, not escape codes
  • Themes — Centralized style definitions in CSS or YAML
  • Hot reload — Edit templates during development, see changes instantly
  • Graceful degradation — Same template renders rich or plain based on terminal

The result: output that's easy to write, easy to change, and looks polished.

Features

Two-Pass Rendering Pipeline

Template + Data → MiniJinja → Text with style tags → BBParser → ANSI output
  1. Pass 1: Variable substitution, loops, conditionals (MiniJinja)
  2. Pass 2: Style tag replacement with ANSI codes (or stripping for plain text)

Adaptive Themes

Automatic OS detection for light/dark terminals:

# theme.yaml
title:
  fg: cyan
  bold: true
panel:
  light:
    bg: "#f5f5f5"
  dark:
    bg: "#1a1a1a"

Or CSS syntax:

.title { color: cyan; font-weight: bold; }

@media (prefers-color-scheme: dark) {
    .panel { background: #1a1a1a; }
}

Multiple Output Modes

One template, many formats:

// Rich terminal output
render_with_output(template, &data, &theme, OutputMode::Term)?;

// Plain text (pipes, redirects)
render_with_output(template, &data, &theme, OutputMode::Text)?;

// Structured data (skip template entirely)
render_auto(template, &data, &theme, OutputMode::Json)?;
render_auto(template, &data, &theme, OutputMode::Yaml)?;

Tabular Layout

Sophisticated column formatting with world-class alignment and layout:

{% set t = tabular([
    {"name": "id", "width": 8},
    {"name": "name", "width": "fill"},
    {"name": "status", "width": 10, "anchor": "right"}
], separator="  ") %}
{% for entry in entries %}
{{ t.row([entry.id, entry.name, entry.status]) }}
{% endfor %}

Features: flexible truncation (start/middle/end), expanding columns, word wrapping, multi-line row alignment, justification, variable width, fractional sizing—all Unicode-aware and ANSI-safe.

Hot Reload

During development, templates reload from disk on each render:

let mut renderer = Renderer::new(theme)?;
renderer.add_template_dir("./templates")?;

// Edit templates/report.jinja, re-run, see changes immediately
let output = renderer.render("report", &data)?;

In release builds, templates embed into the binary—no runtime file access.

Quick Start

[dependencies]
standout-render = "2.1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
use standout_render::{render, Theme};
use serde::Serialize;

#[derive(Serialize)]
struct Report { title: String, items: Vec<String> }

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let theme = Theme::from_yaml(r#"
        title: { fg: cyan, bold: true }
        item: green
        count: { dim: true }
    "#)?;

    let report = Report {
        title: "Status".into(),
        items: vec!["server-1".into(), "server-2".into()],
    };

    let template = r#"
[title]{{ title }}[/title]
{% for item in items %}
  [item]{{ item }}[/item]
{% endfor %}
[count]{{ items | length }} items[/count]
"#;

    let output = render(template, &report, &theme)?;
    print!("{}", output);
    Ok(())
}

Documentation

Guides

Topics

Reference

Used By

This crate provides the rendering foundation for the standout CLI framework, which adds command dispatch, hooks, and clap integration. Use standout-render directly when you want rendering without the framework.

License

MIT