Skip to content

Sparkles Package Overview

Sparkles is a D monorepo for CLI applications and supporting libraries. sparkles:base provides allocation-conscious foundation modules; sparkles:core-cli builds on it with pretty-printing, UI components, CLI helpers, and process utilities.

Table of Contents

Installation

Add the package you need as a dependency. Use sparkles:base for styling, logging, SmallBuffer, lifetime helpers, and text readers/writers. Use sparkles:core-cli when you also need pretty-printing, UI components, CLI argument parsing, or process utilities.

sdl
dependency "sparkles:base" version="*"
dependency "sparkles:core-cli" version="*"
json
"dependencies": {
    "sparkles:base": "*",
    "sparkles:core-cli": "*"
}

Terminal Styling

The term_style module provides ANSI terminal colors and text attributes.

Style Enum

Available styles include:

  • Colors: red, green, yellow, blue, magenta, cyan, white, gray
  • Bright colors: brightRed, brightGreen, brightYellow, etc.
  • Background: bgRed, bgGreen, bgBlue, etc.
  • Attributes: bold, dim, italic, underline, strikethrough, inverse

Basic Usage

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "styledemo"
    dependency "sparkles:base" version="*"
+/
import std.stdio : writeln;
import sparkles.base.term_style : Style, stylize;

void main()
{
    writeln("Error: ".stylize(Style.red) ~ "Something went wrong");
    writeln("Success: ".stylize(Style.green) ~ "Operation completed");
    writeln("Warning".stylize(Style.bold).stylize(Style.yellow));
}
Error: Something went wrong
Success: Operation completed
Warning

Compile-Time Builder

For CTFE-compatible styling, use stylizedTextBuilder:

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "builderdemo"
    dependency "sparkles:base" version="*"
+/
import std.stdio : writeln;
import sparkles.base.term_style : stylizedTextBuilder;

void main()
{
    // Chain multiple styles fluently
    enum styledText = "Important".stylizedTextBuilder.bold.underline.red;
    writeln(styledText);
}
Important

Styled Templates (IES)

The styled_template module provides a template syntax for applying terminal styles using D's Interpolated Expression Sequences (IES).

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "styledtemplatedemo"
    dependency "sparkles:base" version="*"
+/
import sparkles.base.styled_template;

void main()
{
    int cpu = 75;
    styledWriteln(i"CPU: {red $(cpu)%} Status: {green OK}");
}
CPU: 75% Status: OK

Syntax Reference

SyntaxDescription
{red text}Apply single style
{bold.red text}Chain multiple styles
{bold outer {red inner}}Nested blocks (inner inherits outer)
{red text {~red normal}}Negation with ~ removes a style
#{Escaped literal {
#}Escaped literal }

Available Functions

FunctionDescription
styledText(i"...")Returns styled string
styledWriteln(i"...")Writes to stdout with newline
styledWrite(i"...")Writes to stdout without newline
styledWritelnErr(i"...")Writes to stderr with newline
styledWriteErr(i"...")Writes to stderr without newline
styled(i"...")Returns lazy wrapper for deferred processing
writeStyled(writer, i"...")Writes to any output range

More Examples

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "styledexamples"
    dependency "sparkles:base" version="*"
+/
import sparkles.base.styled_template;

void main()
{
    // Chained styles
    styledWriteln(i"{bold.italic.green Bold italic green text}");

    // Nested with inheritance
    styledWriteln(i"{bold Bold {red bold+red} back to bold}");

    // Style negation
    styledWriteln(i"{bold.red Both {~red just bold} both again}");

    // Practical usage
    string file = "main.d";
    int errors = 3;
    styledWriteln(i"{dim $(file):} {red.bold $(errors) errors}");

    // Escaped braces for literals
    styledWriteln(i"Use #{style text#} syntax");
}
Bold italic green text
Bold bold+red back to bold
Both just bold both again
main.d: 3 errors
Use {style text} syntax

Pretty Printing

The prettyprint module formats any D type with syntax highlighting.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "prettyprintdemo"
    dependency "sparkles:base" version="*"
+/
import std.stdio : writeln;
import sparkles.base.prettyprint : prettyPrint, PrettyPrintOptions;

struct Server { string host; int port; bool ssl; }

void main()
{
    auto server = Server("localhost", 8080, true);
    writeln(prettyPrint(server));

    // Custom options
    int[] numbers = [1, 2, 3, 4, 5];
    writeln(prettyPrint(numbers, PrettyPrintOptions!void(colored: false)));
}
Server(host: "localhost", port: 8080, ssl: true)
[1, 2, 3, 4, 5]

PrettyPrintOptions

PrettyPrintOptions is a struct template parameterized on SourceUriHook:

d
PrettyPrintOptions!void(...)              // default: file:// URIs
PrettyPrintOptions!(SchemeHook!"code")    // VS Code URIs
PrettyPrintOptions!EditorDetectHook       // auto-detect from $EDITOR/$VISUAL
OptionDefaultDescription
indentStep2Spaces per indent level
maxDepth8Maximum recursion depth
maxItems32Max items shown for arrays/AAs
softMaxWidth80Try single-line if output fits (0 = always multi-line)
coloredtrueEnable ANSI colors
useOscLinksfalseWrap type names in OSC 8 hyperlinks to source location

Source URI Hooks

The SourceUriHook template parameter controls the URI scheme for OSC 8 hyperlinks on type names. Available hooks from sparkles.base.source_uri:

HookDescription
void (default)file:// URIs with absolute paths
SchemeHook!"code"VS Code (vscode://) URIs
SchemeHook!"cursor"Cursor editor URIs
SchemeHook!"idea"JetBrains IDE URIs
SchemeHook!"subl"Sublime Text URIs
EditorDetectHookAuto-detects from $VISUAL/$EDITOR at runtime

Custom hooks implement static void writeSourceUri(string path, size_t line, size_t col, Writer)(ref Writer w) — source location is passed as template parameters for CTFE evaluation.

UI Components

Tables

Render data as ASCII tables with Unicode box-drawing characters.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "tabledemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.table : drawTable;
import sparkles.base.term_style : Style, stylize;

void main()
{
    string[][] data = [
        ["Name".stylize(Style.bold), "Status".stylize(Style.bold)],
        ["web-01", "Running".stylize(Style.green)],
        ["web-02", "Stopped".stylize(Style.red)],
    ];
    writeln(drawTable(data));
}
╭────────┬─────────╮
NameStatus
│ web-01 │ Running
│ web-02 │ Stopped
╰────────┴─────────╯

Boxes

Draw bordered boxes around content with optional titles.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "boxdemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.box : drawBox;

void main()
{
    writeln(["Line 1", "Line 2", "Line 3"].drawBox("My Box"));
}
╭──╼ My Box ╾───╮
│ Line 1        │
│ Line 2        │
│ Line 3        │
╰───────────────╯

Use BoxProps to add a footer to boxes:

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "boxfooterdemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.box : drawBox, BoxProps;

void main()
{
    writeln(["Processing..."].drawBox("Status", BoxProps(footer: "Press Q to cancel")));
}
╭──╼ Status ╾──────────────╮
│ Processing...            │
╰──╼ Press Q to cancel ╾───╯

Headers

Create section dividers and banners.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "headerdemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.header : drawHeader, HeaderProps, HeaderStyle;

void main()
{
    // Divider style (default)
    writeln("Configuration".drawHeader);

    // Banner style
    writeln("Main Section".drawHeader(HeaderProps(
        style: HeaderStyle.banner,
        width: 30
    )));
}
── Configuration ──
══════════════════════════════
         Main Section
══════════════════════════════

Make text clickable in terminal emulators that support OSC 8.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "osclinkdemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.osc_link : oscLink;
import sparkles.base.term_style : Style;

void main()
{
    // Plain clickable link
    writeln(oscLink(text: "Example", uri: "https://example.com"));

    // Styled clickable link (blue text)
    writeln(oscLink(text: "D Language", uri: "https://dlang.org", style: Style.blue));
}
]8;;https://example.comExample]8;;
]8;;https://dlang.orgD Language]8;;

API

FunctionDescription
oscLink(text, uri)Wrap text in an OSC 8 hyperlink
oscLink(text, uri, style)Wrap styled text in an OSC 8 link
oscLinkOpenSeq(uri, props)Opening escape sequence only
oscLinkCloseSeq(props)Closing escape sequence only

Configure via OscLinkProps:

FieldDefaultDescription
terminatorOscTerminator.belBEL (\x07) or ST (\x1b\\)
idnullOptional link id for grouping

Meters & Progress

Proportional bars with eighth-cell precision (▏▎▍▌▋▊▉█), a count/max form, an ASCII fallback, and the composed ProgressBar (determinate) / ProgressLine (spinner) one-liners that live regions repaint.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "meterdemo"
    dependency "sparkles:core-cli" version="*"
+/
import core.time : msecs;
import std.stdio : writeln;
import sparkles.core_cli.ui.meter : meter, meterGlyphs, ProgressBar;
import sparkles.core_cli.ui.progress : ProgressLine;

void main()
{
    writeln("|", meter(0.33, 16), "|");
    writeln("|", meter(7, 9, 16, meterGlyphs(false)), "|"); // ASCII fallback
    writeln(ProgressBar(done: 5, total: 40, barWidth: 16));
    writeln(ProgressLine(frame: 3, done: 12, total: 40, elapsed: 1500.msecs));
}
|█████▎          |
|############----|
██                5/40
⠸ 12/40 (1.5s)

Tree Views

renderTree draws ├─/└─ guides over flat, pre-ordered (label, depth) nodes — the storage any depth-first traversal already produces; no recursive node objects. The guides compose as a table's first column (see the tree example for that variation).

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "treedemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.tree : renderTree, TreeNode;

void main()
{
    foreach (line; renderTree([
        TreeNode("src", 0),
        TreeNode("app.d", 1),
        TreeNode("ui", 1),
        TreeNode("table.d", 2),
        TreeNode("docs", 0),
    ]))
        writeln(line);
}
src
├─ app.d
└─ ui
   └─ table.d
docs

Layout Helpers

hjoin zips pre-rendered blocks side by side (top-aligned, padded by visible width, so ANSI styling and CJK content line up); kvList renders aligned label/value lines.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "layoutdemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.box : drawBox;
import sparkles.core_cli.ui.layout : hjoin, kvList;

void main()
{
    writeln(hjoin([
        drawBox(kvList([["host", "web-01"], ["port", "8080"]]), "server"),
        drawBox(["ok"], "health"),
    ]));
}
╭──╼ server ╾───╮  ╭──╼ health ╾───╮
│ host  web-01  │  │ ok            │
│ port  8080    │  ╰───────────────╯
╰───────────────╯

Live Regions & Task Lists

sparkles.core_cli.ui.live.LiveRegion repaints a block of lines in place at the bottom of the normal scrollback flow — no alternate screen. Every repaint is wrapped in DEC 2026 synchronized-output markers (no tearing), rows are clamped to the terminal width, and printAbove graduates permanent lines into the scrollback above the block. On piped output the frames are skipped entirely and only the permanent lines appear, so redirected runs see no escape codes.

sparkles.core_cli.ui.tasklist.TaskReporter drives a checklist through a region: add/start/succeed/fail/skip per task, with each running task's output streaming into a bounded tail pane via TaskReporter.output(id, line) — pair it with sparkles.core_cli.process_utils.runStreaming, which hands a child process's merged output to a sink line by line.

The row renderers are pure, so they are testable (and demoable) without a terminal:

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "tasklistdemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writeln;
import sparkles.core_cli.ui.tasklist : renderTaskList, TaskItem, TaskStatus;
import sparkles.core_cli.ui.theme : Theme;

void main()
{
    auto items = [
        TaskItem(label: "fetch", status: TaskStatus.ok), // already in scrollback
        TaskItem(label: "build", status: TaskStatus.running,
            tail: ["compiling module 12"]),
        TaskItem(label: "publish", status: TaskStatus.pending),
    ];
    foreach (line; renderTaskList(items, Theme(colors: false)))
        writeln(line);
}
⠋ build
  compiling module 12
○ publish

Run libs/core-cli/examples/live-tasklist.d in a terminal for the animated version (and pipe it through cat to see the escape-free transition log).

Interactive Prompts

sparkles.core_cli.prompts provides line-based select, confirm, and textInput. Every prompt takes a PromptPolicyinteractive asks (re-prompting on invalid input), takeDefault resolves silently (for --auto flags or piped stdin), fail returns an error — and returns Expected, so EOF is an error, never an accidental default.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "promptsdemo"
    dependency "sparkles:core-cli" version="*"
+/
import std.stdio : writefln;
import sparkles.core_cli.prompts;
import sparkles.core_cli.term_caps : isTerminal, StdStream;

void main()
{
    // Interactive on a terminal; takes the defaults when piped (as here).
    const policy = isTerminal(StdStream.stdin)
        ? PromptPolicy.interactive : PromptPolicy.takeDefault;
    auto io = stdioPromptIo();

    auto bump = select("Version bump:", [
        SelectOption("patch"), SelectOption("minor", "(suggested)"),
        SelectOption("major"),
    ], 1, policy, io);
    auto go = confirm("Push to origin?", defaultYes: true, policy, io);
    writefln!"bump=%s push=%s"(bump.value + 1, go.value);
}
bump=2 push=true

Terminal Capabilities & Themes

sparkles.core_cli.term_caps is the single place the "what can this terminal do" decision is made: terminalSize() (a ScreenSize!ushort; 0 components mean unknown), isTerminal(stream), and detectTermCaps() — the one-shot snapshot combining tty-ness, the color decision ($NO_COLOR, TERM=dumb, $CLICOLOR_FORCE; on Windows it also sets the UTF-8 code page and enables VT processing), a UTF-8 locale heuristic, and the size. setTermWindowSizeHandler delivers resize notifications (POSIX SIGWINCH).

sparkles.core_cli.ui.theme turns a TermCaps into rendering decisions: makeTheme(detectTermCaps()) yields a Theme with semantic styles (Semantic.success/failure/warning/accent/muted via paint/mark), a status-glyph vocabulary (✔ ✖ ⚠ ○ ┄ with ASCII fallbacks), and one BorderStyle selector (rounded/square/ascii/double_/heavy) shared by drawBox, drawHeader, and drawTable — so a non-UTF-8 terminal degrades consistently everywhere. sparkles.base.term_control supplies the underlying control sequences (CtlSeq erase/cursor/alt-screen/synchronized-output constants and writeCursor*/DecMode writers) for anything the components don't cover.

Logger

The sparkles.base.logger module provides CoreLogger, a std.logger.Logger base class with a Sparkles @safe nothrow @nogc logging path, plus DeltaTimeLogger, a stderr logger that prints wall-clock time, elapsed time since start, and elapsed time since the previous log entry.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "loggerdemo"
    dependency "sparkles:base" version="*"
+/
import std.logger : log, logf, LogLevel;
import sparkles.base.logger : initLogger;

void main()
{
    initLogger(LogLevel.trace);

    log(LogLevel.info, "Listening on port 8080");
    log(LogLevel.warning, "Disk usage above 80%");
    log(LogLevel.error, "Connection to database lost");
    log(LogLevel.critical, "Out of memory");

    immutable host = "db-01.prod";
    logf(LogLevel.info, "Reconnected to %s:%d", host, 5432);
}
[ 12:44:39 | Δt 122.7µs | Δtᵢ 122.7µs | INF | loggerdemo.d:13 ]: Listening on port 8080
[ 12:44:39 | Δt 232.9µs | Δtᵢ 110.2µs | WRN | loggerdemo.d:14 ]: Disk usage above 80%
[ 12:44:39 | Δt 274.4µs | Δtᵢ 41.5µs | ERR | loggerdemo.d:15 ]: Connection to database lost
[ 12:44:39 | Δt 316.7µs | Δtᵢ 42.2µs | CRT | loggerdemo.d:16 ]: Out of memory
[ 12:44:39 | Δt 388.1µs | Δtᵢ 71.4µs | INF | loggerdemo.d:19 ]: Reconnected to db-01.prod:5432

Features

  • Delta timestamps: Each line shows Δt (total elapsed) and Δtᵢ (since previous entry) for quick performance profiling
  • Colored output: Log levels are color-coded (green=info, yellow=warn, red=error, bold+red=critical/fatal) using writeStyled IES
  • Thread-safe: Uses core.atomic for delta tracking, safe as a shared global logger
  • Human-friendly durations: Automatically scales to ms, s, m, h, or d with one decimal place

API

Function / typeDescription
CoreLoggerstd.logger.Logger base class with a Sparkles @nogc log path
sharedCoreLogAtomic process-wide Sparkles logger
coreGlobalLogLevelAtomic process-wide Sparkles log-level filter
initLogger(level)Install DeltaTimeLogger for both Phobos and Sparkles globals
writeLogPrefix(...)Write prefix to an output range (zero-allocation)

SmallBuffer (@nogc)

A @nogc container with Small Buffer Optimization (SBO). Stores small data inline, automatically switches to heap when capacity is exceeded.

d
#!/usr/bin/env dub
/+ dub.sdl:
    name "smallbufferdemo"
    dependency "sparkles:base" version="*"
+/
import std.stdio : writeln;
import sparkles.base.smallbuffer : SmallBuffer;

void main()
{
    // 64 chars inline, heap if exceeded
    SmallBuffer!(char, 64) buf;

    buf ~= "Hello";
    buf ~= ' ';
    buf ~= "World";

    writeln(buf[]);  // "Hello World"
    writeln("On heap: ", buf.onHeap);  // false
}
Hello World
On heap: false

Key Features

  • @nogc @safe: No garbage collector allocations in hot paths
  • Output range: Works with std.algorithm and other range-based APIs
  • Automatic growth: Switches to heap allocation when needed
  • Slicing: Access elements via buf[] or buf[start..end]

Running Examples

Examples in libs/base/examples/ and libs/core-cli/examples/ are standalone runnable files:

bash
# Run directly with dub
dub run --single libs/base/examples/logger.d
dub run --single libs/base/examples/prettyprint.d

# Or make executable and run
chmod +x libs/core-cli/examples/color.d
./libs/core-cli/examples/color.d

Available examples:

  • color.d - Style and color palette showcase
  • logger.d - Delta-time-prefixed logging (libs/base/examples/)
  • prettyprint.d - Type formatting demonstration (libs/base/examples/)
  • text-fields.d - alignField/truncateField cell-accurate fields (libs/base/examples/)
  • term-control.d - Redraw-in-place control sequences (libs/base/examples/)
  • styled-template.d - IES-based template styling
  • table.d - Table rendering gallery (spans, alignment, titles, streaming views)
  • box.d - Box layouts with nested content
  • header.d - Header styles
  • osc-link.d - OSC 8 terminal hyperlinks
  • theme.d - Border presets, status glyphs, semantic styles
  • meter.d - Meters, progress bars, spinner lines
  • tree.d - Tree views (flat nodes; also as a table stub column)
  • layout.d - hjoin side-by-side blocks and kvList receipts
  • prompts.d - Interactive select/confirm/input (run in a terminal)
  • live-tasklist.d - Live region + task list + streamed child output (run in a terminal)
  • term-caps.d - Terminal capability detection and resize handling