Language Page

kcli for Rust

This page is assembled from markdown in ktools-rust. GitHub links point to the workspace repo and the relevant source files or directories.

5 markdown sections
QM-Code/ktools-rust primary repo
HTML static output

kcli-rust

ktools-rust/kcli/README.md

ktools-rust/kcli/ is the Rust implementation of kcli.

It follows the same parsing model as the C++ SDK:

  • top-level options such as --verbose
  • inline roots such as --alpha-*, --trace-*, and --build-*
  • aliases, required values, optional values, and positional dispatch
  • full CLI validation before any handler runs

Documentation

Quick Start

use kcli::{InlineParser, Parser};

let mut parser = Parser::new();
let mut build = InlineParser::new("--build")?;

build.set_value_handler(
    "-profile",
    |_context, _value| Ok(()),
    "Set build profile.",
)?;

parser.add_inline_parser(build)?;
parser.add_alias("-v", "--verbose", &[] as &[&str])?;
parser.set_flag_handler("--verbose", |_context| Ok(()), "Enable verbose logging.")?;

let argv = vec!["app", "--verbose"];
parser.parse(&argv)?;
# Ok::<(), Box<dyn std::error::Error>>(())

Behavior Highlights

  • parse() returns kcli::CliError for invalid CLI input and handler failures
  • parse_or_exit() reports [error] [cli] ... and exits with code 2
  • bare inline roots such as --build print inline help unless a root value is provided
  • required-value handlers may consume a first value token that begins with -
  • literal -- is rejected as an unknown option; it is not treated as an option terminator

Build

From this repo root:

kbuild --build-latest

If kbuild is not on PATH, use the shared workspace copy:

python3 ../../kbuild/kbuild.py --build-latest

Direct Cargo workflow:

cd src
cargo test

SDK staging after kbuild --build-latest:

  • build/latest/sdk/Cargo.toml
  • build/latest/sdk/src/
  • build/latest/sdk/tests/

Demos

  • Bootstrap compile/link check: demo/bootstrap/
  • SDK demos: demo/sdk/{alpha,beta,gamma}
  • Executable demos: demo/exe/{core,omega}

After kbuild --build-latest, staged demo outputs appear under:

  • demo/bootstrap/build/latest/
  • demo/sdk/alpha/build/latest/
  • demo/sdk/beta/build/latest/
  • demo/sdk/gamma/build/latest/
  • demo/exe/core/build/latest/
  • demo/exe/omega/build/latest/

Useful demo commands:

./demo/bootstrap/build/latest/bootstrap
./demo/sdk/alpha/build/latest/sdk_alpha --alpha-message "hello"
./demo/sdk/beta/build/latest/sdk_beta --beta-workers 8
./demo/sdk/gamma/build/latest/sdk_gamma --gamma-tag "prod"
./demo/exe/core/build/latest/core --alpha
./demo/exe/core/build/latest/core --output stdout
./demo/exe/omega/build/latest/omega --build
./demo/exe/omega/build/latest/omega --newgamma-tag "prod"

Repository Layout

  • Public API: src/src/lib.rs
  • Parser implementation: src/src/{backend,model,normalize,process}.rs
  • Demo binaries: src/src/bin/
  • Shared demo helpers: src/src/demo/
  • Behavior coverage: src/tests/

Kcli Rust Documentation

ktools-rust/kcli/docs/index.md

kcli is the Rust command-line parsing layer for the ktools stack.

It is intentionally opinionated about normal CLI behavior:

  • parse first
  • fail early on invalid input
  • do not run handlers until the full command line validates
  • preserve the caller's input token list
  • support grouped inline roots such as --trace-* and --build-*

Start Here

Typical Flow

use kcli::{InlineParser, Parser};

let mut parser = Parser::new();
let mut build = InlineParser::new("--build")?;

build.set_value_handler(
    "-profile",
    |_context, _value| Ok(()),
    "Set build profile.",
)?;

parser.add_inline_parser(build)?;
parser.add_alias("-v", "--verbose", &[] as &[&str])?;
parser.set_flag_handler("--verbose", |_context| Ok(()), "Enable verbose logging.")?;

let argv = vec!["app", "--verbose"];
parser.parse(&argv)?;
# Ok::<(), Box<dyn std::error::Error>>(())

Core Concepts

Parser

  • Owns top-level handlers, aliases, positional handling, and inline parser registration.

InlineParser

  • Defines one inline root namespace such as --alpha, --trace, or --build.

HandlerContext

  • Exposes the effective option, command, root, and value tokens seen by the handler after alias expansion.

CliError

  • Returned from Parser::parse() when the CLI is invalid or a handler returns an error string.

Which Entry Point Should I Use?

Use parse_or_exit() when:

  • you are in a normal executable main()
  • invalid CLI input should print a standardized error and exit with code 2
  • you do not need custom formatting or recovery

Use parse() when:

  • you want to test parse failures directly
  • you want custom error formatting or exit codes
  • you need to intercept handler failures

Build And Explore

kbuild --build-latest
./demo/sdk/alpha/build/latest/sdk_alpha --alpha-message "hello"
./demo/exe/core/build/latest/core --alpha
./demo/exe/omega/build/latest/omega --build

Working References

If you want complete, compiling examples, start with:

The public API contract lives in ../src/src/lib.rs.

API Guide

ktools-rust/kcli/docs/api.md

This page summarizes the public types in ../src/src/lib.rs.

Core Types

Type Purpose
kcli::Parser Owns aliases, top-level handlers, positional handling, and inline parser registration.
kcli::InlineParser Defines one inline root namespace such as --build plus its --build-* handlers.
kcli::HandlerContext Metadata delivered to flag, value, and positional handlers.
kcli::CliError Error returned by parse() for invalid CLI input and handler failures.
kcli::ConfigError Error returned while registering invalid roots, options, aliases, or help text.

HandlerContext

HandlerContext is passed to every handler.

Field Meaning
root Inline root name without leading dashes, such as build. Empty for top-level handlers and positional dispatch.
option Effective option token after alias expansion, such as --verbose or --build-profile. Empty for positional dispatch.
command Normalized command name without leading dashes. Empty for positional dispatch and inline root value handlers.
value_tokens Effective value tokens after alias expansion. Tokens from the shell are preserved verbatim; alias preset tokens are prepended.

InlineParser

Construction

let parser = kcli::InlineParser::new("--build")?;

The root may be provided as either:

  • "build"
  • "--build"

Root Value Handler

parser.set_root_value_handler(|_context, _value| Ok(()))?;
parser.set_root_value_handler_with_help(
    |_context, _value| Ok(()),
    "<selector>",
    "Select build targets.",
)?;

The root value handler processes the bare root form, for example:

  • --build release
  • --config user.json

If the bare root is used without a value, kcli prints inline help for that root instead.

Inline Handlers

parser.set_flag_handler("-clean", |_context| Ok(()), "Enable clean build.")?;
parser.set_value_handler("-profile", |_context, _value| Ok(()), "Set build profile.")?;
parser.set_optional_value_handler("-enable", |_context, _value| Ok(()), "Enable build mode.")?;

Inline handler options may be written in either form:

  • short inline form: -profile
  • fully-qualified form: --build-profile

Parser

Top-Level Handlers

parser.set_flag_handler("--verbose", |_context| Ok(()), "Enable verbose logging.")?;
parser.set_value_handler("--output", |_context, _value| Ok(()), "Set output target.")?;
parser.set_optional_value_handler("--color", |_context, _value| Ok(()), "Set or auto-detect color output.")?;

Top-level handler options may be written as either:

  • "verbose"
  • "--verbose"

Aliases

parser.add_alias("-v", "--verbose", &[] as &[&str])?;
parser.add_alias("-c", "--config-load", &["user-file"])?;

Rules:

  • aliases use single-dash form such as -v
  • alias targets use double-dash form such as --verbose
  • preset tokens are prepended to the handler's effective value_tokens

Positional Handler

parser.set_positional_handler(|context| {
    for token in &context.value_tokens {
        println!("{token}");
    }
    Ok(())
})?;

The positional handler receives remaining non-option tokens in HandlerContext::value_tokens.

Inline Parser Registration

parser.add_inline_parser(build_parser)?;

Duplicate inline roots are rejected.

Parse Entry Points

parser.parse(&argv)?;
parser.parse_or_exit(&argv);

parse()

  • preserves the caller's input token list
  • returns CliError
  • does not run handlers until the full command line validates

parse_or_exit()

  • preserves the caller's input token list
  • reports invalid CLI input to stderr as [error] [cli] ...
  • exits with code 2

Value Handler Registration

Use the registration form that matches the CLI contract you want:

  • set_flag_handler(option, handler, description) for flag-style options
  • set_value_handler(option, handler, description) for required values
  • set_optional_value_handler(option, handler, description) for optional values
  • set_root_value_handler* for bare inline roots such as --build release

Parsing Behavior

ktools-rust/kcli/docs/behavior.md

This page collects the parsing rules that matter in practice.

Parse Lifecycle

kcli processes the command line in three stages:

  1. Read the caller's tokens into an internal vector.
  2. Validate and schedule handler invocations in one pass.
  3. Execute scheduled handlers only after the full command line validates.

This means:

  • handlers do not run on partially-valid command lines
  • unknown options fail the parse before any handler side effects occur
  • the caller's input tokens are never rewritten

Option Naming Rules

Top-level handlers:

  • accepted forms: "name" or "--name"
  • effective option token at runtime: --name

Inline roots:

  • accepted forms: "build" or "--build"
  • effective bare root token at runtime: --build

Inline handlers:

  • accepted forms: "-flag" or "--build-flag"
  • effective option token at runtime: --build-flag

Aliases:

  • alias form must be single-dash, such as -v
  • target form must be double-dash, such as --verbose

Inline Root Behavior

Bare inline roots behave specially.

--build

  • prints a help listing for the --build-* handlers

--build release

  • invokes the root value handler if one is registered
  • fails if no root value handler is registered

If a root value handler is registered with a placeholder and description, the bare-root help view includes a row such as:

--build <selector>  Select build targets.

Value Consumption Rules

kcli supports three public registration styles:

  • flag handlers consume no trailing value tokens
  • required-value handlers consume at least one value token
  • optional-value handlers consume values only when the next token looks like a value

Additional details:

  • once value collection starts, kcli keeps consuming subsequent non-option-like tokens for that handler
  • explicit empty tokens are preserved
  • joined handler values are produced by joining value_tokens with spaces

Examples:

--name "Joe"            -> value_tokens = ["Joe"]
--name "Joe" "Smith"    -> value_tokens = ["Joe", "Smith"]
--name ""               -> value_tokens = [""]
--profile -debug        -> value_tokens = ["-debug"]

Alias Behavior

Aliases are only expanded when a token is parsed as an option.

Examples:

parser.add_alias("-v", "--verbose", &[] as &[&str])?;
parser.add_alias("-c", "--config-load", &["user-file"])?;

Rules:

  • consumed value tokens are not alias-expanded
  • preset tokens are prepended to effective value_tokens
  • preset tokens can satisfy required-value handlers
  • aliases with preset tokens cannot target flag handlers

Positionals

The positional handler receives all remaining non-option tokens in one invocation.

Important details:

  • explicit empty positional tokens are preserved
  • positionals are dispatched only after option parsing succeeds

Failure Behavior

Unknown option-like tokens fail the parse.

Notable cases:

  • unknown top-level option: --bogus
  • unknown inline option: --build-unknown
  • literal --

kcli does not treat -- as an option terminator. It is reported as an unknown option.

Error Surface

parse_or_exit()

  • prints [error] [cli] ... to stderr
  • colors error red and cli blue on terminals
  • exits with code 2

parse()

  • returns kcli::CliError
  • preserves the human-facing error message
  • surfaces handler failures returned as Err(String)

Behavior Coverage

The executable behavior is covered by:

The demo programs under ../demo/ show complete, compiling usage.

Examples

ktools-rust/kcli/docs/examples.md

This page shows a few common kcli patterns. For complete compiling examples, also see:

Minimal Executable

use kcli::Parser;

fn main() {
    let argv = std::env::args().collect::<Vec<_>>();
    let mut parser = Parser::new();

    parser
        .add_alias("-v", "--verbose", &[] as &[&str])
        .expect("alias should register");
    parser
        .set_flag_handler("--verbose", |_context| Ok(()), "Enable verbose logging.")
        .expect("handler should register");

    parser.parse_or_exit(&argv);
}

Inline Root With Subcommands-Like Options

let mut parser = kcli::Parser::new();
let mut build = kcli::InlineParser::new("--build")?;

build.set_value_handler("-profile", |_context, _value| Ok(()), "Set build profile.")?;
build.set_flag_handler("-clean", |_context| Ok(()), "Enable clean build.")?;

parser.add_inline_parser(build)?;

This enables:

--build
--build-profile release
--build-clean

Bare Root Value Handler

let mut config = kcli::InlineParser::new("--config")?;

config.set_root_value_handler_with_help(
    |_context, _value| Ok(()),
    "<assignment>",
    "Store a config assignment.",
)?;

This enables:

--config
--config user=alice

Behavior:

  • --config prints inline help
  • --config user=alice invokes the root value handler

Alias Preset Tokens

let mut parser = kcli::Parser::new();

parser.add_alias("-c", "--config-load", &["user-file"])?;
parser.set_value_handler("--config-load", |_context, _value| Ok(()), "Load config.")?;

This makes:

-c settings.json

behave like:

--config-load user-file settings.json

Inside the handler:

  • context.option is --config-load
  • context.value_tokens is ["user-file", "settings.json"]

Optional Values

parser.set_optional_value_handler(
    "--color",
    |_context, _value| Ok(()),
    "Set or auto-detect color output.",
)?;

This enables both:

--color
--color always

Positionals

parser.set_positional_handler(|context| {
    for token in &context.value_tokens {
        println!("{token}");
    }
    Ok(())
})?;

The positional handler receives all remaining non-option tokens after option parsing succeeds.