CLI
Command-line interface module for building CLI tools with dependency injection support.
run()
tk.cli.run(injector: *Injector, allocator: std.mem.Allocator, commands: []const Command) !voidExecutes CLI command parsing and routing. Blocks until command completes.
var injector = tk.Injector.init(&.{ .ref(&db) }, null);
try tk.cli.run(&injector, allocator, commands);Output flags:
--json- JSON output format--yaml- YAML output format- Default: Auto (strings as-is, structs as YAML)
Command
tk.cli.Command.cmd0(name: []const u8, description: []const u8, handler: fn) Command
tk.cli.Command.cmd1(name: []const u8, description: []const u8, handler: fn) Command
tk.cli.Command.cmd2(name: []const u8, description: []const u8, handler: fn) Command
tk.cli.Command.cmd3(name: []const u8, description: []const u8, handler: fn) Command
tk.cli.Command.cmd(name: []const u8, description: []const u8, handler: fn, n_args: usize) CommandCreates command definitions for different argument counts.
const commands = &[_]tk.cli.Command{
.cmd0("version", "Show version", getVersion),
.cmd1("hello", "Greet user", hello),
.cmd2("add-user", "Create user", addUser),
};Built-in Command
tk.cli.Command.usageDisplays help information. Automatically included.
Handler Functions
Handlers can inject dependencies and accept command arguments:
// No dependencies, no arguments
fn version() []const u8
// With dependencies, no arguments
fn migrate(db: *Database) !void
// With dependencies and arguments
fn findUser(db: *Database, id: []const u8) !User
// With allocator
fn hello(arena: std.mem.Allocator, name: []const u8) ![]const u8Argument order:
- Injected dependencies (from DI container)
- Command arguments (from CLI args)
Optional arguments:
fn greet(name: []const u8, title: ?[]const u8) ![]const u8Context
tk.cli.ContextAvailable as injectable dependency for advanced control.
Fields:
arena: std.mem.Allocator- Request-scoped allocatorbin: []const u8- Binary namecommand: *const Command- Current commandargs: []const []const u8- Remaining argumentsin: *std.io.Reader- stdinout: *std.io.Writer- stdouterr: *std.io.Writer- stderrinjector: *Injector- DI containerformat: OutputFormat- Output format (.auto, .json, .yaml)
Methods:
ctx.parse(T: type, s: []const u8) !TParses string to type T.
ctx.output(value: anytype) !voidOutputs value according to format setting.
Output Format
Strings: Printed as-is
fn handler() []const u8 { return "Hello"; }$ myapp handler
HelloStructs: Serialized to JSON or YAML
fn handler() User { return user; }$ myapp handler
id: 123
name: John
$ myapp --json handler
{"id": 123, "name": "John"}Errors: Formatted as error objects
fn handler() !void { return error.Failed; }$ myapp handler
error: Failed
$ myapp --json handler
{"error": "Failed"}void: No output
Usage Information
Automatic help display when no command provided or invalid command:
Usage: myapp [--json|--yaml] <command> [args...]
Options:
--json Output in JSON format
--yaml Output in YAML format
Commands:
version Show version
hello Greet user
Syntax:
myapp version
myapp hello <string>Module Reuse
CLI tools can share DI modules with server applications:
// Shared module
const AppModule = struct {
db: Database,
config: Config,
};
// CLI main
pub fn main() !void {
const ct = try tk.Container.init(allocator, &.{AppModule});
defer ct.deinit();
try tk.cli.run(&ct.injector, allocator, commands);
}Commands automatically have access to all module dependencies.