NURLNURL registrynurl-lang.org →

← cli

cli 0.2.0 API

prompt.nu

cli/prompt.nu — interactive prompts over std/term + core/io.

All prompts write to stderr (so a command's stdout stays clean for pipes) and read a line from stdin. cli_password suppresses the echo when stdin is a real terminal, and degrades to a plain read otherwise.

API

@ cli_prompt s question → String

Ask a free-text question; returns the entered line (trailing newline stripped by read_line). Empty String on EOF.

@ cli_confirm s question b def → b

Yes/no confirmation. def is returned on a bare Enter or EOF. Only the first character is inspected (y/Y → true, n/N → false, else the default).

@ cli_password s question → String

Read a secret. When stdin is a TTY the terminal echo is disabled for the duration; otherwise this is a normal (echoed) line read. No in-line editing (backspace) in the no-echo path — kept intentionally minimal.


cli.nu

cli/cli.nu — the ergonomic command-line facade over the stdlib.

The stdlib ships a flat argument parser (std/args), terminal control (std/term: isatty + ANSI + a line editor), stdin/stdout (core/io) and the process environment (ext/env). What every CLI re-invents on top is the same glue: a subcommand dispatch cascade, typed flag accessors with env fallbacks and defaults, coloured --help / --version / usage, error → exit-code handling, and interactive prompts.

Cli collapses that into one object:

: *Cli c ( cli_new greet a tiny greeter 1.0.0 ) ( cli_flag_str c name 110 NAME who to greet world ` ) ( cli_flag_bool c loud 108 shout it ) ( cli_cmd c hello print a greeting \ CliCtx x → i { : String who ( ctx_str x name ) ( nurl_print hello, ) ( nurl_print ( string_data who ) ) ( nurl_print \n` ) ( string_free who ) ^ 0 } ) ^ ( cli_run c ) // parse argv, route, auto --help/--version → exit code

Scope: this facades the command-line surface (args + env + stdin + tty / colour / prompts + exit codes). It deliberately does NOT absorb terminal widgets (tables/spinners), config-file loading, or logging — those compose as their own packages.

Memory model: cli_new returns a heap *Cli, mutable across the builder calls; free it with cli_free. Flags and commands accumulate into its Vecs. cli_run owns the parse and frees everything it allocates.

API

: CliFlag

: CliFlag {
    String long
    i short  // short-option char code, 0 = none
    String metavar  // value placeholder in help (empty for bool)
    String help
    i kind
    String dflt  // default rendered as text (empty = none)
    String env  // environment-variable fallback (empty = none)
}

Flag kinds. 0 = string 1 = int 2 = bool (presence) 3 = float

: CliCmd

: CliCmd {
    String name
    String help
    ( @ i CliCtx ) handler
}

: Cli

: Cli {
    String prog
    String about
    String version
    ( Vec CliFlag ) globals
    ( Vec CliCmd ) cmds
}

: CliCtx

: CliCtx {
    ArgParser parser
    * Cli cli
    String cmdname
}

Passed to every command handler; wraps the parsed args plus a back-ref to the Cli so accessors can resolve env fallbacks and defaults.

: ~ b g_cli_color F

@ cli_new s prog s about s version → *Cli

@ cli_free * Cli c → v

@ cli_flag_bool * Cli c s long i short s help → v

@ cli_flag_str * Cli c s long i short s metavar s help s dflt s env → v

@ cli_flag_int * Cli c s long i short s metavar s help i dflt s env → v

@ cli_flag_float * Cli c s long i short s metavar s help f dflt s env → v

@ cli_cmd * Cli c s name s help ( @ i CliCtx ) handler → v

@ cli_default * Cli c ( @ i CliCtx ) handler → v

Default handler — the whole program IS the command (psql/redis-cli style: bare invocation acts, positionals like a connection URL are arguments, not subcommand names). Stored as the reserved empty-name command. When set: a first non-option token that matches no registered command routes here (and stays readable as ctx_arg 0), and a bare invocation runs it instead of printing usage. Registered subcommands still win when they match.

@ ctx_str CliCtx x s name → String

@ ctx_int CliCtx x s name → i

@ ctx_float CliCtx x s name → f

@ ctx_bool CliCtx x s name → b

@ ctx_nargs CliCtx x → i

Number of positional arguments after the command token. Under the default handler (empty cmdname) there is no command token to skip — every positional (e.g. a connection URL) is an argument.

@ ctx_arg CliCtx x i idx → String

The idx-th positional after the command (0-based); empty String if absent. args_positionals hands back a BORROW of the parser's own vector — read from it and copy out the one element; never free it here.

@ ctx_stdin CliCtx x → String

Slurp stdin to EOF (for pipe-friendly commands).

@ ctx_cmd CliCtx x → s

The command name that was invoked.

@ cli_run * Cli c → i

Parse the real argv, route to a subcommand, and return its exit code. Handles --help / --version, unknown commands, and parse errors.