An open API service indexing awesome lists of open source software.

https://github.com/kingrashy12/ziglet

A concise and powerful CLI builder for Zig.
https://github.com/kingrashy12/ziglet

cli-builder zig-package

Last synced: 25 days ago
JSON representation

A concise and powerful CLI builder for Zig.

Awesome Lists containing this project

README

          

# Ziglet

A concise and powerful CLI builder for Zig.

## ✨ Features

- Add and organize custom commands with ease
- Execute commands with `parse` built into Ziglet
- Minimal dependencies, maximum speed
- Built in Zig for clarity, performance, and control

## πŸ“š How to Use

1. Fetch the package:

```bash
zig fetch --save git+https://github.com/Kingrashy12/ziglet
```

2. Add the module to your `build.zig`:

```zig
// Add the ziglet dependency
const ziglet = b.dependency("ziglet", .{});

// Add the ziglet module to the executable
exe.root_module.addImport("ziglet", ziglet.module("ziglet"));
```

3. Import and use in your code:

### Basic Usage

```zig
const std = @import("std");
const ziglet = @import("ziglet");
const CommandContext = ziglet.BuilderTypes.CommandContext;
const CLIBuilder = ziglet.CLIBuilder;

pub fn main(init: std.process.Init) !void {
const arena = init.arena;
const allocator = init.gpa;
const args = try init.minimal.args.toSlice(arena.allocator());

var cli = CLIBuilder.init(allocator, init, "my-cli", "0.1.0", "A simple CLI example");
defer cli.deinit();

// Add a command with options
cli.addCommand(.{
.name = "greet",
.description = "Greet someone",
.action = greet,
.options = cli.defOptions(&.{.{
.name = "name",
.alias = "n",
.type = .string,
.required = true,
.description = "Name to greet",
}}),
});

try cli.parse(args, null);
}

fn greet(ctx: CommandContext) !void {
const name = ctx.options.get("name");

if (name) |n| {
std.debug.print("Hello, {s}!\n", .{n.string});
}
}
```

### Global Options

Ziglet supports global options that apply to all commands:

```zig
// ... (same setup as above)

var cli = CLIBuilder.init(allocator, init, "example-cli", "1.0.0", "A CLI with global options");
defer cli.deinit();

// Enable global options (adds --help and --version automatically)
cli.setGlobalOptions();

// Add a global option
cli.option(.{
.alias = "v",
.name = "verbose",
.type = .bool,
.description = "Enable verbose output",
});

// Add commands that can access global options
cli.addCommand(.{
.name = "greet",
.description = "Greet someone",
.action = greet,
.options = cli.defOptions(&.{.{
.name = "name",
.alias = "n",
.type = .string,
.required = true,
.description = "Name to greet",
}}),
});

try cli.parse(args, null);

// In your action function, access both global and command options
fn greet(ctx: CommandContext) !void {
const verbose = ctx.options.get("verbose");
const name = ctx.options.get("name");

if (verbose) |v| if (v.bool) {
std.debug.print("Verbose mode enabled.\n", .{});
}

if (name) |n| {
std.debug.print("Hello, {s}!\n", .{n.string});
}
}
```

### Factory Pattern (Fluent API)

For a more fluent and readable way to build commands:

```zig
// ... (same setup as above)

var cli = CLIBuilder.init(allocator, init,"my-cli", "0.1.0", "Factory builder example");
defer cli.deinit();

cli.setGlobalOptions();

// Global option
_ = cli.option(.{
.alias = "v",
.name = "verbose",
.type = .bool,
.description = "Enable verbose output",
});

// Build commands using fluent API
const greet_cmd = cli.command("greet", "Greet someone")
.option(.{
.alias = "n",
.name = "name",
.required = true,
.type = .string,
.description = "Name to greet",
})
.action(greet)
.finalize();

const calc_cmd = cli.command("calc", "Calculate sum of two numbers")
.option(.{
.alias = "a",
.name = "a",
.required = true,
.type = .number,
.description = "First number",
})
.option(.{
.alias = "b",
.name = "b",
.required = true,
.type = .number,
.description = "Second number",
})
.action(calc)
.finalize();

// Command without options
_ = cli.command("status", "Show status")
.action(status)
.finalize();

// Parse with factory commands
try cli.parse(args, &.{ greet_cmd, calc_cmd });

fn greet(ctx: CommandContext) !void {
const name = ctx.options.get("name");
std.debug.print("Greeting someone from '{s}'.\n", .{ctx.name});

if (name) |n| {
std.debug.print("Hello, {s}!\n", .{n.string});
}
}

fn calc(ctx: CommandContext) !void {
const a_opt = ctx.options.get("a");
const b_opt = ctx.options.get("b");

if (a_opt) |a| if (b_opt) |b| {
const sum = a.number + b.number;
std.debug.print("Sum: {d}\n", .{sum});
}
}

fn status(ctx: CommandContext) !void {
_ = ctx;
std.debug.print("System status: All good!\n", .{});
}
```

## πŸ“– Examples

For runnable examples, see the [examples/](examples/) directory:

- [`examples/plain.zig`](examples/plain.zig) - Comprehensive example with multiple commands, global options, and different option types
- [`examples/factory.zig`](examples/factory.zig) - Demonstrates the fluent factory pattern for building commands

## 🀝 Contributing

Want to make Ziglet even snappier? Feel free to open issues, suggest features, or submit pull requests. Let’s build something sharp together.

## πŸ“„ License

MIT – free to use, modify, and share.