Skip to content

Latest commit

 

History

History
266 lines (220 loc) · 9.63 KB

File metadata and controls

266 lines (220 loc) · 9.63 KB

Implementation Summary

Overview

zig-cli is a comprehensive CLI library for Zig 0.16+, inspired by the clapp TypeScript framework. It provides a type-safe CLI framework, an interactive prompt system, and a configuration loader - all using modern Zig APIs.

Architecture

Three-Layer System

  1. CLI Framework (src/cli/)

    • Type-safe command building via Command(T) (compile-time validated)
    • Low-level BaseCommand for manual control
    • Argument parsing with type validation
    • Option handling (short/long flags)
    • Automatic help generation
    • Middleware system
  2. Prompt System (src/prompt/)

    • Interactive terminal UI
    • State machine (5 states: initial -> active <-> error -> submit/cancel)
    • Event-driven architecture
    • 10 prompt types + UI components
    • Terminal feature detection
  3. Configuration (src/config/)

    • Type-safe config loading via cli.config.load(T, ...)
    • TOML, JSONC, JSON5 parsers
    • Auto-discovery of config files
    • Untyped access via Config type

File Structure

zig-cli/
├── build.zig                       # Build configuration (tests, examples, library)
├── build.zig.zon                   # Package metadata
├── src/
│   ├── root.zig                    # Main entry - exports Command, Context, Action, etc.
│   ├── cli/
│   │   ├── Command.zig             # Base command definition & ParseContext
│   │   ├── CommandBuilder.zig      # TypedCommand(T), TypedContext(T), TypedAction(T)
│   │   ├── Option.zig              # Option (flag) handling
│   │   ├── Argument.zig            # Positional argument handling
│   │   ├── Parser.zig              # Argument parser with validation
│   │   ├── Help.zig                # Help text generation
│   │   └── Middleware.zig          # Middleware system (chain, context, built-ins)
│   ├── prompt/
│   │   ├── root.zig                # Prompt module entry
│   │   ├── Terminal.zig            # Low-level terminal I/O
│   │   ├── Ansi.zig                # ANSI colors and symbols
│   │   ├── PromptCore.zig          # Core prompt logic (buffer, cursor, events)
│   │   ├── PromptState.zig         # State machine and events
│   │   ├── TextPrompt.zig          # Text input prompt
│   │   ├── ConfirmPrompt.zig       # Yes/No confirmation
│   │   ├── SelectPrompt.zig        # Single selection list
│   │   ├── MultiSelectPrompt.zig   # Multiple selection list
│   │   ├── PasswordPrompt.zig      # Masked password input
│   │   ├── NumberPrompt.zig        # Number input (integer/float, range)
│   │   ├── PathPrompt.zig          # Path input with Tab autocomplete
│   │   ├── GroupPrompt.zig         # Sequential prompt groups
│   │   ├── SpinnerPrompt.zig       # Spinner/loading animation
│   │   ├── ProgressBar.zig         # Progress bar (4 styles)
│   │   ├── Message.zig             # Message prompts (intro/outro/note/log)
│   │   ├── Box.zig                 # Box rendering (4 styles)
│   │   ├── Table.zig               # Table rendering (4 styles, alignment)
│   │   └── Style.zig               # Style chaining API
│   └── config/
│       ├── root.zig                # Config exports: load(), discover(), loadFromString()
│       ├── Config.zig              # Config manager (untyped)
│       ├── ConfigLoader.zig        # TypedConfig(T) - compile-time schema validation
│       ├── TomlParser.zig          # TOML parser
│       ├── JsoncParser.zig         # JSONC parser
│       └── Json5Parser.zig         # JSON5 parser
├── examples/
│   ├── simple.zig                  # Minimal typed CLI example
│   ├── basic.zig                   # Basic CLI with subcommands
│   ├── typed.zig                   # Type-safe API demo
│   ├── advanced.zig                # Complex CLI with multiple commands
│   ├── prompts.zig                 # All prompt types
│   ├── showcase.zig                # Comprehensive feature demo
│   ├── config.zig                  # Config file examples
│   └── configs/
│       ├── example.toml
│       ├── example.jsonc
│       └── example.json5
└── docs/
    ├── README.md
    ├── FEATURE_PARITY.md
    ├── CONFIG_FEATURES.md
    ├── IMPLEMENTATION.md
    └── FINAL_SUMMARY.md

Key Features Implemented

CLI Framework

  1. Type-Safe Commands (Primary API)

    const GreetOptions = struct {
        name: []const u8,
        verbose: bool = false,
    };
    
    fn greet(ctx: *cli.Context(GreetOptions)) !void {
        const name = ctx.get(.name);  // Compile-time validated!
        std.debug.print("Hello, {s}!\n", .{name});
    }
    
    var cmd = try cli.Command(GreetOptions).init(allocator, "greet", "Greet someone");
    _ = cmd.setAction(greet);
  2. Low-Level API (BaseCommand)

    const cmd = try cli.BaseCommand.init(allocator, "myapp", "Description");
    _ = try cmd.addOption(cli.Option.init("name", "name", "Your name", .string));
    _ = cmd.setAction(myAction);
  3. Type-safe Options

    • String, int, float, boolean types
    • Short and long flags (-n, --name)
    • Required vs optional
    • Default values
  4. Argument Parsing

    • Positional arguments
    • Variadic arguments
    • Type validation
    • Error handling with helpful messages
  5. Subcommand Support

    • Nested commands with aliases
    • Per-command options and arguments
    • Command-specific actions
  6. Auto-generated Help

    • Usage instructions
    • Option descriptions
    • Command listings
    • Formatting with proper alignment
  7. Middleware System

    • Pre/post command hooks
    • Chainable middleware
    • Built-in: logging, timing, validation, environment checks

Prompt System

  1. State Machine

    • Clean 5-state design
    • Validated state transitions
    • Error recovery
  2. Prompt Types

    • TextPrompt: Free text input with validation
    • ConfirmPrompt: Yes/No questions
    • SelectPrompt: Single choice from list
    • MultiSelectPrompt: Multiple choices from list
    • PasswordPrompt: Masked input
    • NumberPrompt: Integer/float with min/max range
    • PathPrompt: File/directory with Tab autocomplete
    • GroupPrompt: Sequential prompts with shared state
    • SpinnerPrompt: Animated loading indicator
  3. UI Components

    • ProgressBar: 4 styles (bar, blocks, dots, ASCII)
    • Box: 4 border styles
    • Table: 4 styles, column alignment, auto-width
    • Messages: intro, outro, note, log, cancel
  4. Terminal Features

    • Raw mode for key capture
    • ANSI color support
    • Unicode/ASCII fallback
    • Cursor control
    • Style chaining API

Configuration System

  1. Type-Safe Loading

    const MyConfig = struct {
        host: []const u8,
        port: u16 = 8080,
    };
    
    var config = try cli.config.load(MyConfig, allocator, "config.toml");
    defer config.deinit();
    // config.value.host, config.value.port - direct access
  2. Three Format Parsers

    • TOML, JSONC, JSON5
  3. Auto-Discovery

    • Searches standard config locations
    • Format auto-detection by extension

Zig 0.16 API Usage

This codebase uses modern Zig 0.16.0-dev APIs:

  • I/O: std.Io, std.Io.File.stdout(), .writerStreaming(io, &buf), .interface.print()/.flush()
  • ArrayList: Unmanaged - all methods take allocator parameter (.append(alloc, val), .deinit(alloc))
  • Sleep: std.c.nanosleep(&.{ .sec = N, .nsec = N }, null) (no std.time.sleep)
  • Process Args: pub fn main(init: std.process.Init) !void with std.process.Args.Iterator
  • Env Vars: std.c.getenv(name) (no std.posix.getenv)
  • Build System: b.createModule(...), b.addTest(.{ .root_module = module })
  • Terminal: winsize.col/.row (not .ws_col/.ws_row)

Design Patterns Used

  1. Builder Pattern

    • Fluent API for CLI construction
    • Method chaining for configuration
  2. State Machine

    • Explicit state transitions
    • Terminal states (submit/cancel)
    • Error state with recovery
  3. Comptime Generics

    • Command(T) generates options from struct fields
    • Context(T) provides typed field access
    • ConfigLoader(T) validates config against struct schema
  4. Strategy Pattern

    • Pluggable validators
    • Custom action handlers
  5. Full-Frame Rendering

    • Simple clear-and-redraw approach for prompts
    • Works across all terminals

Examples Provided

  1. simple.zig - Minimal typed CLI
  2. basic.zig - CLI with options and subcommands
  3. typed.zig - Type-safe API with config integration
  4. advanced.zig - Complex CLI with multiple commands
  5. prompts.zig - All prompt types with validation
  6. showcase.zig - Comprehensive feature demonstration
  7. config.zig - Configuration file loading

Building & Testing

zig build              # Build the library
zig build test         # Run all tests
zig build examples     # Build all 7 examples
zig build run-simple   # Run a specific example

Conclusion

zig-cli successfully replicates the core features and developer experience of clapp while leveraging Zig's strengths:

  • Memory safety with explicit allocators
  • Compile-time type checking via generics
  • Zero-cost abstractions
  • Cross-platform support
  • No runtime dependencies

The library is ready for building sophisticated CLI applications with type-safe argument parsing, interactive prompts, and configuration management.