prompts.dhover×82all
#!/usr/bin/env dub
/+ dub.sdl:
    name "prompts"
    dependency "sparkles:core-cli" path="../../.."
    targetPath "build"
    // Optimised, assertions live, `debug {}` blocks out — the build every nix
    // artifact uses. Neither `debug` (which compiles those blocks in) nor
    // `release` (which deletes assert *expressions*, side effects included).
    buildType "checked" {
        buildOptions "optimize" "inline" "debugInfo"
    }
+/

// ci: build-only

// Line-based interactive prompts (`sparkles.core_cli.prompts`): a numbered
// `select` (default marked, re-prompt on invalid input), a y/N `confirm`, and
// a validated `textInput` — each carrying a `PromptPolicy` so `--auto` runs
// and piped stdin resolve uniformly (take the default / fail) instead of every
// app hand-rolling it. Interactive, so `ci` only builds this; run it yourself.

module 
(module) prompts_example
prompts_example
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) prompts_example.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
,
(alias template) prompts_example.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
import
(package) sparkles
sparkles
.
(package) sparkles.core_cli
core_cli
.
(module) sparkles.core_cli.prompts

Blocking, line-based interactive prompts: a numbered select, a yes/no confirm, and a validated free-text textInput.

Every prompt takes a PromptPolicy so non-interactive callers (--auto flags, piped stdin) are handled uniformly instead of per call site: interactive asks (re-prompting on invalid input), takeDefault resolves silently to the default, and fail returns an error. I/O goes through an injectable PromptIo pair, so prompts are unit-testable with canned input; EOF on stdin is an error, never an accidental default.

Line-based by default (works over any pipe/ssh, and is what confirm/ textInput always use); select additionally layers a cursor-driven mode on top when PromptIo.beginKeySession is available (a real terminal — see stdioKeySession), falling back to the numbered flow otherwise.

prompts
;
import
(package) sparkles
sparkles
.
(package) sparkles.base
base
.
(module) sparkles.base.term_caps

Terminal capability probing: the synchronous size query (terminalSize), tty and color detection (detectTermCaps), and resize notifications (setTermWindowSizeHandler).

This is the single place the "what can this terminal do" decision is made; renderers stay pure producers that take explicit widths/flags. It lives in sparkles:base rather than a UI package because it is an environment query, not a presentation concern — a logger, a CLI tool and a full-screen UI all need it, and none of them should pull in a UI stack to ask.

TermSize is deliberately a plain POD rather than a Vector specialization: base sits below sparkles:math, and a capability snapshot never does vector arithmetic. The terminal's geometry types — positions you add offsets to — live in sparkles:tui (TermPosition), which is free to specialize Vector.

term_caps
:
(alias) prompts_example.isTerminal = bool sparkles.base.term_caps.isTerminal(sparkles.base.term_caps.StdStream stream = StdStream.stdout) nothrow @nogc @trusted

Is stream attached to a terminal? POSIX: isatty; Windows: GetConsoleMode succeeds (it fails when the handle is redirected — the non-tty check).

isTerminal
,
(enum) sparkles.base.term_caps.StdStream

A standard stream, for tty queries.

StdStream
;
import
(package) sparkles
sparkles
.
(package) sparkles.ui
ui
.
(package) sparkles.ui.components
components
.
(module) sparkles.ui.components.theme

Theme layer: one border-charset selector shared by every framed component (drawBox / drawHeader / drawTable), the status-glyph vocabulary with ASCII fallbacks, semantic styles, and a Theme snapshot derived from TermCaps.

Components stay pure producers — the theme only selects glyphs/styles once at the edge (typically makeTheme(detectTermCaps()) at app startup); callers thread the resulting values through the existing BoxProps/TableProps/colored parameters.

theme
:
(alias) prompts_example.makeTheme = sparkles.ui.components.theme.Theme sparkles.ui.components.theme.makeTheme(in sparkles.base.term_caps.OutputCapabilities caps) pure nothrow @nogc @safe

The theme for a target's output affordances: ASCII borders + fallback glyphs without Unicode, colors per the color tier. A TermCaps converts implicitly (its output is alias this), so ``makeTheme(detectTermCaps()) reads as before; a GUI target passes its own declaration.

makeTheme
,
(struct) sparkles.ui.components.theme.Theme

A resolved theme snapshot: the color/unicode decisions plus the selected charsets. Build one with makeTheme and thread it (or its fields) through the app.

Theme
;
import
(package) sparkles
sparkles
.
(package) sparkles.base
base
.
(module) sparkles.base.term_caps

Terminal capability probing: the synchronous size query (terminalSize), tty and color detection (detectTermCaps), and resize notifications (setTermWindowSizeHandler).

This is the single place the "what can this terminal do" decision is made; renderers stay pure producers that take explicit widths/flags. It lives in sparkles:base rather than a UI package because it is an environment query, not a presentation concern — a logger, a CLI tool and a full-screen UI all need it, and none of them should pull in a UI stack to ask.

TermSize is deliberately a plain POD rather than a Vector specialization: base sits below sparkles:math, and a capability snapshot never does vector arithmetic. The terminal's geometry types — positions you add offsets to — live in sparkles:tui (TermPosition), which is free to specialize Vector.

term_caps
:
(alias) prompts_example.detectTermCaps = sparkles.base.term_caps.TermCaps sparkles.base.term_caps.detectTermCaps(bool noColors = false) @safe

Detects capabilities and prepares the console.

Colors are on only when stdout is a terminal and neither noColors, $NO_COLOR, nor TERM=dumb disables them; a non-empty, non-"0" $CLICOLOR_FORCE forces them on for a non-tty (but never overrides an explicit disable). colorDepth is the tier (classifyColorDepth over $COLORTERM/$TERM) when colors are on, else none. On Windows this additionally sets the output code page to UTF-8 (so ✓ ✗ ⚙ render even without colors) and enables virtual-terminal processing (so ANSI escapes are interpreted rather than printed literally); colors stay off when stdout is redirected or VT can't be enabled.

detectTermCaps
;
void
void D main()
main
()
{ const
(local variable) const(sparkles.ui.components.theme.Theme) theme
theme
=
sparkles.ui.components.theme.Theme sparkles.ui.components.theme.makeTheme(in sparkles.base.term_caps.OutputCapabilities caps) pure nothrow @nogc @safe

The theme for a target's output affordances: ASCII borders + fallback glyphs without Unicode, colors per the color tier. A TermCaps converts implicitly (its output is alias this), so ``makeTheme(detectTermCaps()) reads as before; a GUI target passes its own declaration.

makeTheme
(
sparkles.base.term_caps.TermCaps sparkles.base.term_caps.detectTermCaps(bool noColors = false) @safe

Detects capabilities and prepares the console.

Colors are on only when stdout is a terminal and neither noColors, $NO_COLOR, nor TERM=dumb disables them; a non-empty, non-"0" $CLICOLOR_FORCE forces them on for a non-tty (but never overrides an explicit disable). colorDepth is the tier (classifyColorDepth over $COLORTERM/$TERM) when colors are on, else none. On Windows this additionally sets the output code page to UTF-8 (so ✓ ✗ ⚙ render even without colors) and enables virtual-terminal processing (so ANSI escapes are interpreted rather than printed literally); colors stay off when stdout is redirected or VT can't be enabled.

detectTermCaps
());
// Piped stdin? Resolve every prompt to its default instead of blocking. const
(local variable) const(sparkles.core_cli.prompts.PromptPolicy) policy
policy
=
bool sparkles.base.term_caps.isTerminal(sparkles.base.term_caps.StdStream stream = StdStream.stdout) nothrow @nogc @trusted

Is stream attached to a terminal? POSIX: isatty; Windows: GetConsoleMode succeeds (it fails when the handle is redirected — the non-tty check).

Examples

The query never throws and is @nogc; the value is environment-dependent.

cast(void) isTerminal();
cast(void) isTerminal(StdStream.stderr);
isTerminal
(
(enum) sparkles.base.term_caps.StdStream

A standard stream, for tty queries.

StdStream
.
(enum value) sparkles.base.term_caps.StdStream.stdin = 0
stdin
)
?
(enum) sparkles.core_cli.prompts.PromptPolicy

How a prompt resolves when it cannot, or should not, actually ask.

PromptPolicy
.
(enum value) sparkles.core_cli.prompts.PromptPolicy.interactive = 0

Ask on the terminal, re-prompting on invalid input.

interactive
:
(enum) sparkles.core_cli.prompts.PromptPolicy

How a prompt resolves when it cannot, or should not, actually ask.

PromptPolicy
.
(enum value) sparkles.core_cli.prompts.PromptPolicy.takeDefault = 1

Do not ask; resolve to the default (e.g. --auto runs).

takeDefault
;
auto
(local variable) sparkles.core_cli.prompts.PromptIo io
io
=
sparkles.core_cli.prompts.PromptIo sparkles.core_cli.prompts.stdioPromptIo()

The real stdin/stdout PromptIo.

stdioPromptIo
();
auto
(local variable) expected.Expected!(ulong, string, Abort) bump
bump
=
expected.Expected!(ulong, string, Abort) sparkles.core_cli.prompts.select(string question, const(sparkles.core_cli.prompts.SelectOption)[] options, ulong defaultIndex, sparkles.core_cli.prompts.PromptPolicy policy, sparkles.core_cli.prompts.PromptIo io, const(sparkles.ui.components.theme.Theme) theme = Theme(false, true, BorderStyle.rounded, StatusGlyphs("\xe2\x9c\x94", "\xe2\x9c\x96", "\xe2\x9a\xa0", "\xe2\x80\xa2", "\xe2\x97\x8b", "\xe2\x97\x90", "\xe2\x94\x84", "\xe2\x80\xa6")), bool wrapAround = true)

Ask the user to pick one of options by number. Renders the list (default marked and painted accent), then loops until a valid number or an empty line (= the default). Returns the chosen index; errors on EOF or a non- interactive fail policy.

When io`.beginKeySession` is available (a real terminal), arrow keys move the highlighted row instead: Up/Down move, Enter confirms, Esc/Ctrl+C/ Ctrl+D cancel. wrapAround`` (on by default) makes Up from the first row jump to the last (and Down from the last jump to the first); pass false to clamp at the ends instead.

select
("Version bump:", [
(struct) sparkles.core_cli.prompts.SelectOption

One choice of a select.

SelectOption
("patch", "v0.5.0 → v0.5.1"),
(struct) sparkles.core_cli.prompts.SelectOption

One choice of a select.

SelectOption
("minor", "v0.5.0 → v0.6.0 (suggested: 4 feat)"),
(struct) sparkles.core_cli.prompts.SelectOption

One choice of a select.

SelectOption
("major", "v0.5.0 → v1.0.0"),
], 1,
(local variable) const(sparkles.core_cli.prompts.PromptPolicy) policy
policy
,
(local variable) sparkles.core_cli.prompts.PromptIo io
io
,
(local variable) const(sparkles.ui.components.theme.Theme) theme
theme
);
if (
(local variable) expected.Expected!(ulong, string, Abort) bump
bump
.
bool expected.Expected!(ulong, string, expected.Abort).hasError!()() const pure nothrow @nogc @property @safe

Checks if Expected has error

hasError
)
return
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(
(local variable) expected.Expected!(ulong, string, Abort) bump
bump
.
inout(string) expected.Expected!(ulong, string, expected.Abort).error() inout nothrow @nogc @property ref @safe

Returns the error value. May only be called when hasValue returns false.

If there is no error value, it calls hook's onAccessEmptyError.

It returns E.init when hook doesn't provide onAccessEmptyError.

error
);
void std.stdio.writefln!("picked option %s", ulong)(ulong __param_0) @safe

Equivalent to writef(fmt, args, '\n').

writefln
!"picked option %s"(
(local variable) expected.Expected!(ulong, string, Abort) bump
bump
.
inout(ulong) expected.Expected!(ulong, string, expected.Abort).value!()() inout pure nothrow @nogc @property ref @safe

Returns the expected value if there is one.

With default Abort hook, it asserts when there is no value. It calls hook's onAccessEmptyValue otherwise.

It returns T.init when hook doesn't provide onAccessEmptyValue.

value
+ 1);
auto
(local variable) expected.Expected!(bool, string, Abort) go
go
=
expected.Expected!(bool, string, Abort) sparkles.core_cli.prompts.confirm(string question, bool defaultYes, sparkles.core_cli.prompts.PromptPolicy policy, sparkles.core_cli.prompts.PromptIo io, const(sparkles.ui.components.theme.Theme) theme = Theme(false, true, BorderStyle.rounded, StatusGlyphs("\xe2\x9c\x94", "\xe2\x9c\x96", "\xe2\x9a\xa0", "\xe2\x80\xa2", "\xe2\x97\x8b", "\xe2\x97\x90", "\xe2\x94\x84", "\xe2\x80\xa6")))

Ask a yes/no question (y/yes/n/no, case-insensitive; empty = the default, shown as [Y/n]/[y/N]). Errors on EOF or the fail policy.

confirm
("Push to origin?", defaultYes: true,
(local variable) const(sparkles.core_cli.prompts.PromptPolicy) policy
policy
,
(local variable) sparkles.core_cli.prompts.PromptIo io
io
,
(local variable) const(sparkles.ui.components.theme.Theme) theme
theme
);
if (
(local variable) expected.Expected!(bool, string, Abort) go
go
.
bool expected.Expected!(bool, string, expected.Abort).hasError!()() const pure nothrow @nogc @property @safe

Checks if Expected has error

hasError
)
return
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(
(local variable) expected.Expected!(bool, string, Abort) go
go
.
inout(string) expected.Expected!(bool, string, expected.Abort).error() inout nothrow @nogc @property ref @safe

Returns the error value. May only be called when hasValue returns false.

If there is no error value, it calls hook's onAccessEmptyError.

It returns E.init when hook doesn't provide onAccessEmptyError.

error
);
void std.stdio.writefln!("confirmed: %s", bool)(bool __param_0) @safe

Equivalent to writef(fmt, args, '\n').

writefln
!"confirmed: %s"(
(local variable) expected.Expected!(bool, string, Abort) go
go
.
inout(bool) expected.Expected!(bool, string, expected.Abort).value!()() inout pure nothrow @nogc @property ref @safe

Returns the expected value if there is one.

With default Abort hook, it asserts when there is no value. It calls hook's onAccessEmptyValue otherwise.

It returns T.init when hook doesn't provide onAccessEmptyValue.

value
);
auto
(local variable) expected.Expected!(string, string, Abort) name
name
=
expected.Expected!(string, string, Abort) sparkles.core_cli.prompts.textInput(string question, string defaultValue, string delegate(string answer) validate, sparkles.core_cli.prompts.PromptPolicy policy, sparkles.core_cli.prompts.PromptIo io)

Ask for free text, re-prompting until validate accepts it (returns null) or the user submits an empty line with a defaultValue present. validate returns the error message to show for a rejected answer.

textInput
("Release codename", "sparkling",
(
(alias) object.string = string
string
(parameter) string s
s
) =>
(parameter) string s
s
.
(field) ulong string.length
length
>= 3 ? null : "at least 3 characters, please",
(local variable) const(sparkles.core_cli.prompts.PromptPolicy) policy
policy
,
(local variable) sparkles.core_cli.prompts.PromptIo io
io
);
if (
(local variable) expected.Expected!(string, string, Abort) name
name
.
bool expected.Expected!(string, string, expected.Abort).hasError!()() const pure nothrow @nogc @property @safe

Checks if Expected has error

hasError
)
return
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(
(local variable) expected.Expected!(string, string, Abort) name
name
.
inout(string) expected.Expected!(string, string, expected.Abort).error() inout nothrow @nogc @property ref @safe

Returns the error value. May only be called when hasValue returns false.

If there is no error value, it calls hook's onAccessEmptyError.

It returns E.init when hook doesn't provide onAccessEmptyError.

error
);
void std.stdio.writefln!("codename: %s", string)(string __param_0) @safe

Equivalent to writef(fmt, args, '\n').

writefln
!"codename: %s"(
(local variable) expected.Expected!(string, string, Abort) name
name
.
inout(string) expected.Expected!(string, string, expected.Abort).value!()() inout pure nothrow @nogc @property ref @safe

Returns the expected value if there is one.

With default Abort hook, it asserts when there is no value. It calls hook's onAccessEmptyValue otherwise.

It returns T.init when hook doesn't provide onAccessEmptyValue.

value
);
}