Language Page

kcli for Swift

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

6 markdown sections
QM-Code/ktools-swift primary repo
HTML static output

Karma CLI Parsing SDK

ktools-swift/kcli/README.md

kcli is the Swift implementation of the ktools CLI parsing layer.

It is designed around the same two CLI shapes as the C++ implementation:

  • top-level options such as --verbose and --output
  • inline roots such as --trace-*, --config-*, and --build-*

The library exposes two main parse entry points:

  • parseOrExit(_:) for normal executable startup
  • parseOrThrow(_:) when callers want to intercept CliError

Documentation

Quick Start

import Kcli

func handleVerbose(_ context: HandlerContext) throws {
}

func handleProfile(_ context: HandlerContext, _ value: String) throws {
}

let parser = Parser()
var build = try InlineParser("--build")

try build.setHandler("-profile",
                     handler: handleProfile,
                     description: "Set build profile.")

try parser.addInlineParser(build)
try parser.addAlias("-v", target: "--verbose")
try parser.setHandler("--verbose",
                      handler: handleVerbose,
                      description: "Enable verbose logging.")

parser.parseOrExit()

Behavior Highlights

  • The full command line is validated before any registered handler runs.
  • parseOrExit() reports invalid CLI input to stderr and exits with code 2.
  • parseOrThrow() preserves the input arguments and throws CliError.
  • Bare inline roots such as --build print inline help unless a root value is provided.
  • setHandler(..., handler: ValueHandler, ...) registers a required-value option.
  • setOptionalValueHandler(...) registers an optional-value option.
  • Required values may consume a first token that begins with -.
  • Literal -- is rejected as an unknown option; it is not treated as an option terminator.

For the full parsing rules, see docs/behavior.md.

Build SDK

Workspace-style build:

kbuild --build-latest

Direct SwiftPM flow:

cd src
swift test
swift run kcli-demo-core --alpha-message hello

Demos

Demo directories mirror the C++ shape even though the executable products live in the SwiftPM package:

Useful demo commands:

cd src
swift run kcli-demo-bootstrap
swift run kcli-demo-core --alpha
swift run kcli-demo-core --alpha-message hello
swift run kcli-demo-core --output stdout
swift run kcli-demo-omega --beta-workers 8
swift run kcli-demo-omega --newgamma-tag prod
swift run kcli-demo-omega --build

Repository Layout

  • Public API: src/Sources/Kcli/Kcli.swift
  • Demo assembly: src/Sources/KcliDemoSupport/
  • Parser and demo coverage: src/Tests/
  • Additional docs: docs/
  • Demo directory map: demo/

Coding Agents

If you are using a coding agent, paste the following prompt:

Read AGENTS.md and README.md, then inspect src/Package.swift, src/Sources/, and src/Tests/ before editing code.

Kcli Swift Documentation

ktools-swift/kcli/docs/index.md

kcli is a compact Swift SDK for executable startup and command-line parsing. It keeps the same behavior model as the C++ implementation:

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

Start Here

Typical Flow

import Kcli

let parser = Parser()
var build = try InlineParser("--build")

try build.setHandler("-profile",
                     handler: handleProfile,
                     description: "Set build profile.")

try parser.addInlineParser(build)
try parser.addAlias("-v", target: "--verbose")
try parser.setHandler("--verbose",
                      handler: handleVerbose,
                      description: "Enable verbose logging.")

try parser.parseOrThrow(CommandLine.arguments)

Core Concepts

Parser

  • Owns top-level handlers, aliases, inline parser registrations, and the parse pass.

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

  • Used by parseOrThrow() to surface invalid CLI input and handler failures.

Which Entry Point Should I Use?

Use parseOrExit() when:

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

Use parseOrThrow() when:

  • you want custom error formatting
  • you want custom exit codes
  • you want to intercept and test parse failures directly

Build And Explore

cd src
swift test
swift run kcli-demo-core --alpha-message hello
swift run kcli-demo-omega --build

Working References

If you want complete compiling examples, start with:

The public API contract lives in ../src/Sources/Kcli/Kcli.swift.

API Guide

ktools-swift/kcli/docs/api.md

The public Swift API lives in ../src/Sources/Kcli/Kcli.swift.

Core Types

Parser

  • Registers top-level handlers, aliases, positionals, and inline parsers.
  • Provides parseOrExit() and parseOrThrow(_:).

InlineParser

  • Registers one inline root such as --build or --trace.
  • Supports bare-root value handlers through setRootValueHandler(...).
  • Supports flag, required-value, and optional-value handlers.

HandlerContext

  • root: active inline root without leading dashes, or empty for top-level handlers and positionals
  • option: effective option token such as --verbose or --build-profile
  • command: normalized command token such as verbose or profile
  • valueTokens: consumed value tokens after alias preset tokens are applied

CliError

  • Returned by parseOrThrow(_:) on invalid CLI input
  • Exposes the effective option token through option()

CliConfigurationError

  • Thrown when handlers, aliases, roots, or descriptions are registered incorrectly

InlineParser

Construction

var build = try InlineParser("--build")

The root may be provided as either:

  • "build"
  • "--build"

Root Value Handler

try build.setRootValueHandler(handler)
try build.setRootValueHandler(handler,
                              valuePlaceholder: "<selector>",
                              description: "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

try build.setHandler("-flag", handler: flagHandler, description: "Enable build flag.")
try build.setHandler("-profile", handler: valueHandler, description: "Set build profile.")
try build.setOptionalValueHandler("-enable",
                                  handler: optionalHandler,
                                  description: "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

Top-level flags:

try parser.setHandler("--verbose",
                      handler: { context in
                      },
                      description: "Enable verbose logging.")

Top-level required values:

try parser.setHandler("--output",
                      handler: { context, value in
                      },
                      description: "Set app output target.")

Top-level optional values:

try parser.setOptionalValueHandler("--color",
                                   handler: { context, value in
                                   },
                                   description: "Set or auto-detect color output.")

Top-level handler options may be written as either:

  • "verbose"
  • "--verbose"

Aliases

try parser.addAlias("-v", target: "--verbose")
try parser.addAlias("-c", target: "--config-load", presetTokens: ["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 valueTokens

Positional Handler

try parser.setPositionalHandler { context in
    for token in context.valueTokens {
        usePositional(token)
    }
}

Inline Parser Registration

try parser.addInlineParser(build)

Duplicate inline roots are rejected.

Parse Entry Points

parser.parseOrExit()
try parser.parseOrThrow(CommandLine.arguments)

parseOrExit()

  • reports invalid CLI input to stderr as [error] [cli] ...
  • exits with code 2

parseOrThrow()

  • throws CliError
  • preserves the caller's argument list
  • does not run handlers until the full command line validates

Registration Styles

Inline roots:

var build = try InlineParser("--build")
try build.setHandler("-profile",
                     handler: { context, value in
                     },
                     description: "Set build profile.")

Bare-root value handlers:

var config = try InlineParser("--config")
try config.setRootValueHandler({ context, value in
}, valuePlaceholder: "<assignment>", description: "Store a config assignment.")

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

  • setHandler(option, handler: FlagHandler, description: ...) for flag-style options
  • setHandler(option, handler: ValueHandler, description: ...) for required values
  • setOptionalValueHandler(option, handler: ValueHandler, description: ...) for optional values
  • setRootValueHandler(...) for bare inline roots such as --build release

Parsing Behavior

ktools-swift/kcli/docs/behavior.md

This page collects the Swift parsing rules that matter in practice.

Parse Lifecycle

kcli processes arguments in three stages:

  1. Read the caller's arguments into an internal token list.
  2. Validate and schedule handler invocations in a single 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 arguments are never rewritten or compacted

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 valueTokens with spaces

Examples:

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

Alias Behavior

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

Examples:

try parser.addAlias("-v", target: "--verbose")
try parser.addAlias("-c", target: "--config-load", presetTokens: ["user-file"])

Rules:

  • consumed value tokens are not alias-expanded
  • preset tokens are prepended to effective valueTokens
  • 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 a single 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

parseOrExit()

  • prints [error] [cli] ... to stderr
  • exits with code 2

parseOrThrow()

  • throws CliError
  • preserves the human-facing error message
  • surfaces handler exceptions as CliError

Behavior Coverage

The Swift behavior is covered by:

Examples

ktools-swift/kcli/docs/examples.md

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

Minimal Executable

import Kcli

let parser = Parser()

try parser.addAlias("-v", target: "--verbose")
try parser.setHandler("--verbose",
                      handler: { context in
                      },
                      description: "Enable verbose logging.")

try parser.parseOrThrow(CommandLine.arguments)

Inline Root With Subcommands-Like Options

let parser = Parser()
var build = try InlineParser("--build")

try build.setHandler("-profile",
                     handler: { context, value in
                     },
                     description: "Set build profile.")
try build.setHandler("-clean",
                     handler: { context in
                     },
                     description: "Enable clean build.")

try parser.addInlineParser(build)
try parser.parseOrThrow(CommandLine.arguments)

This enables:

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

Bare Root Value Handler

var config = try InlineParser("--config")

try config.setRootValueHandler({ context, value in
}, valuePlaceholder: "<assignment>", description: "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 parser = Parser()

try parser.addAlias("-c", target: "--config-load", presetTokens: ["user-file"])
try parser.setHandler("--config-load",
                      handler: { context, value in
                      },
                      description: "Load config.")

This makes:

-c settings.json

behave like:

--config-load user-file settings.json

Inside the handler:

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

Optional Values

try parser.setOptionalValueHandler("--color",
                                   handler: { context, value in
                                   },
                                   description: "Set or auto-detect color output.")

This enables both:

--color
--color always

Positionals

try parser.setPositionalHandler { context in
    for token in context.valueTokens {
        usePositional(token)
    }
}

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

Custom Error Handling

If you want your own formatting or exit policy, use parseOrThrow():

do {
    try parser.parseOrThrow(CommandLine.arguments)
} catch let error as CliError {
    FileHandle.standardError.write(Data("custom cli error: \(error.message)\n".utf8))
    exit(2)
}

Swift Demos

ktools-swift/kcli/demo/README.md

The Swift demos are implemented as SwiftPM products under src/, while the demo/ directory keeps the same layout used by the C++ repo.

Executable demo products:

  • kcli-demo-bootstrap
  • kcli-demo-core
  • kcli-demo-omega

SDK demo products:

  • KcliDemoAlpha
  • KcliDemoBeta
  • KcliDemoGamma

Useful commands:

cd src
swift run kcli-demo-bootstrap
swift run kcli-demo-core --alpha-message hello
swift run kcli-demo-core --output stdout
swift run kcli-demo-omega --beta-workers 8
swift run kcli-demo-omega --newgamma-tag prod
swift run kcli-demo-omega --build
swift run kcli-demo-omega -a
swift run kcli-demo-omega -b release