Skip to content

Commit f58025f

Browse files
committed
added mdbook docs and updated docs/changelog
1 parent 39dde8f commit f58025f

21 files changed

Lines changed: 751 additions & 105 deletions

.github/workflows/deploy.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Sample workflow for building and deploying a mdBook site to GitHub Pages
2+
#
3+
# To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html
4+
#
5+
name: Deploy mdBook site to Pages
6+
on:
7+
# Runs on pushes targeting the default branch
8+
push:
9+
branches: ["main"]
10+
# Allows you to run this workflow manually from the Actions tab
11+
workflow_dispatch:
12+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13+
permissions:
14+
contents: read
15+
pages: write
16+
id-token: write
17+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
18+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
19+
concurrency:
20+
group: "pages"
21+
cancel-in-progress: false
22+
jobs:
23+
# Build job
24+
build:
25+
runs-on: ubuntu-latest
26+
env:
27+
MDBOOK_VERSION: 0.5.2
28+
steps:
29+
- uses: actions/checkout@v4
30+
- name: Install mdBook
31+
run: |
32+
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf -y | sh
33+
rustup update
34+
cargo install --version ${MDBOOK_VERSION} mdbook
35+
- name: Setup Pages
36+
id: pages
37+
uses: actions/configure-pages@v5
38+
- name: Build with mdBook
39+
run: mdbook build
40+
working-directory: docs
41+
- name: Upload artifact
42+
uses: actions/upload-pages-artifact@v3
43+
with:
44+
path: ./docs/book
45+
# Deployment job
46+
deploy:
47+
environment:
48+
name: github-pages
49+
url: ${{ steps.deployment.outputs.page_url }}
50+
runs-on: ubuntu-latest
51+
needs: build
52+
steps:
53+
- name: Deploy to GitHub Pages
54+
id: deployment
55+
uses: actions/deploy-pages@v4

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22

33
All notable changes to vecli will be documented here.
44

5+
## [0.3.0] - 10/03/2026
6+
7+
### Added
8+
- Subcommand chaining — commands can now nest arbitrarily deep (e.g. `app remote add`)
9+
- `Command::parent()` constructor for grouping commands with no handler of their own
10+
- `Command::subcommand()` builder method for attaching nested commands
11+
- `Command::print_help_if_no_args()` builder method for parent commands
12+
- `SUBCOMMANDS` section in command-level help output
13+
- `dispatch()` internal helper in `utils.rs` — recursive dispatch through the command tree
14+
- `prog` passed through dispatch for correct help output at any nesting depth
15+
16+
### Changed
17+
- `Command::handler` is now `Option<fn(&CommandContext)>` — parent commands carry no handler
18+
- `Command::new()` still sets a handler; use `Command::parent()` when no handler is needed
19+
- `ctx.subcommand` is always the deepest matched command name, not the full path
20+
- `ctx.positionals` contains only tokens after the deepest matched command
21+
- `dispatch` moved to `utils.rs` and imported into `app.rs`, replacing the inline dispatch block in `run()`
22+
- Positional collection in `dispatch` now correctly skips flag values (not just flag names)
23+
24+
### Fixed
25+
- Alias resolution now runs at each level of the command tree, not only at the app level
26+
- Parent commands with no handler and no `print_help_if_no_args` now print a clear error instead of silently returning
27+
28+
---
29+
530
## [0.2.0] - 09/03/2026
631

732
### Added

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "vecli"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
edition = "2024"
55
description = "A zero-dependency, minimal CLI framework that's genuinely readable."
66
license-file = "LICENSE.md"

GUIDE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
(this guide can also be found at the documentation)
2+
(this guide is deprecated. only trust docs.rs or the github pages site)
23

34
A zero-dependency, minimal CLI framework that's genuinely readable, the tool you've been looking for.
45

@@ -16,7 +17,7 @@ which is the same as including it in your `Cargo.toml` file:
1617

1718
```toml
1819
[dependencies]
19-
vecli = "0.2"
20+
vecli = "0.3"
2021
```
2122

2223
## Building Your First App

docs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
book

docs/book.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[book]
2+
title = "vecli"
3+
authors = ["razkar-studio"]
4+
language = "en"
5+
src = "src"
6+
7+
[output.html]
8+
site-url = "/vecli/"
9+
git-repository-url = "https://github.com/razkar-studio/vecli"

docs/src/SUMMARY.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Summary
2+
3+
[Introduction](README.md)
4+
5+
# Getting Started
6+
- [Installation](getting-started/installation.md)
7+
- [Your First App](getting-started/first-app.md)
8+
+ [Configuring Your App](getting-started/configuring-your-app.md)
9+
10+
# Core Concepts
11+
- [Commands](core-concepts/commands.md)
12+
+ [Subcommands](core-concepts/commands.md)
13+
- [Flags](core-concepts/flags.md)
14+
- [CommandContext](core-concepts/context.md)
15+
16+
## More Soon!

docs/src/core-concepts/commands.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Commands
2+
3+
Let's give your app some commands to run. Here's how you can define them:
4+
5+
```rust
6+
// use vecli::*;
7+
8+
let hello_command = Command::new("hello", function_that_runs_on_hello /* fn(&CommandContext) */);
9+
10+
// Adding this to the app:
11+
// App::new() ...
12+
.add_command(hello_command)
13+
// ... .run();
14+
```
15+
16+
The above is a simple command that runs when the user types the command `hello`, as in `my-app hello`.
17+
18+
To actually make the command run, you need to define the function `function_that_runs_on_hello` that will be called when the command is executed.
19+
20+
```rust
21+
fn function_that_runs_on_hello(_ctx: &CommandContext) {
22+
println!("Hello!");
23+
}
24+
```
25+
26+
Put two together, and you have a working app!
27+
28+
```sh
29+
cargo run hello
30+
```
31+
32+
That should print `Hello!` to the console.
33+
34+
A shorter way to do this is to just directly define `Command` inside `.add_command()`:
35+
36+
```rust
37+
App::new()
38+
.add_command(Command::new("hello", function_that_runs_on_hello))
39+
// ... .run();
40+
```
41+
42+
## Configuration
43+
44+
Just like with the app itself, you can configure how the command is displayed on the help screen and usage output.
45+
46+
For example, you can set the command's description and usage text:
47+
48+
```rust
49+
Command::new("hello", function_that_runs_on_hello)
50+
.description("Prints a friendly greeting")
51+
.usage("<none>"); // a suffix to `my-app hello`
52+
```
53+
54+
This will display the command's description and usage text when the user runs `my-app help` or `my-app hello --help`.
55+
56+
The full configuration options for commands:
57+
- **`.description("Prints hello and exit.")`**: The description of the command, what it does.
58+
- **`.usage("[none]")`**: The usage for the command, will print alongside `my-app hello`.
59+
- `.strict_flags(true)`: If toggled, unknown flags will abort the program. We'll get to flags in a moment.
60+
61+
*(Added in 0.3.0)*
62+
- `.print_help_if_no_args(true)`: If toggled, the help screen will be printed if no arguments (subcommands) are provided.
63+
64+
---
65+
66+
Okay, that was a lot to take in. Take a breather and let's continue. Say we want a `goodbye` subcommand that prints a farewell message. That's what we'll cover next on [Subcommands]().

docs/src/core-concepts/context.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# CommandContext
2+
3+
Every command handler receives a `&CommandContext` as its only argument. It contains everything
4+
vecli parsed from the command line for that invocation.
5+
6+
```rust
7+
fn my_command(ctx: &CommandContext) {
8+
// ctx is yours to use
9+
}
10+
```
11+
12+
## Fields
13+
14+
### `ctx.subcommand`
15+
16+
The name of the command as typed by the user, e.g. `"add"` or `"list"`.
17+
18+
```rust
19+
println!("Running: {}", ctx.subcommand);
20+
```
21+
22+
### `ctx.positionals`
23+
24+
A `Vec<String>` of all non-flag tokens that followed the subcommand, in order.
25+
26+
```sh
27+
mytool add "buy milk" groceries
28+
# ctx.positionals == ["buy milk", "groceries"]
29+
```
30+
31+
```rust
32+
let task = ctx.positionals.first().map(String::as_str).unwrap_or("unnamed");
33+
```
34+
35+
### `ctx.flags`
36+
37+
A `HashMap<String, String>` of all flags passed by the user, keyed by canonical name after alias
38+
resolution. Boolean flags (no explicit value) have the value `"true"`.
39+
40+
```sh
41+
mytool add "buy milk" --priority high -v
42+
# ctx.flags == { "priority": "high", "verbose": "true" }
43+
```
44+
45+
```rust
46+
if ctx.flags.contains_key("verbose") {
47+
println!("verbose mode");
48+
}
49+
50+
let priority = ctx.flags.get("priority").map(String::as_str).unwrap_or("medium");
51+
```
52+
53+
Global flags registered on the app are merged in automatically — no extra setup needed in the handler.
54+
55+
## Full Example
56+
57+
```rust
58+
fn add(ctx: &CommandContext) {
59+
let task = ctx.positionals.first().map(String::as_str).unwrap_or("unnamed");
60+
let priority = ctx.flags.get("priority").map(String::as_str).unwrap_or("medium");
61+
62+
if ctx.flags.contains_key("verbose") {
63+
println!(
64+
"[verbose] subcommand='{}', positionals={:?}, flags={:?}",
65+
ctx.subcommand, ctx.positionals, ctx.flags
66+
);
67+
}
68+
69+
println!("Added '{}' with priority {}.", task, priority);
70+
}
71+
```
72+
73+
---
74+
75+
If you've been this far from the beginning, congrats! This doc is under production and you've reached the end... for now. More guides will be added soon! For now, read the API reference at [docs.rs](https://docs.rs/vecli).

0 commit comments

Comments
 (0)