Skip to content

Commit 3006be7

Browse files
committed
Update argmojo to v0.2.0
1 parent f6d1fef commit 3006be7

File tree

2 files changed

+112
-153
lines changed

2 files changed

+112
-153
lines changed

recipes/argmojo/README.md

Lines changed: 110 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ ArgMojo provides a builder-pattern API for defining and parsing command-line arg
2222
- **Positional arguments**: matched by position
2323
- **Default values**: fallback when an argument is not provided
2424
- **Required arguments**: validation that mandatory args are present
25-
- **Auto-generated help**: `--help` / `-h` (no need to implement manually)
25+
- **Auto-generated help**: `--help` / `-h` / `-?` with dynamic column alignment, pixi-style ANSI colours, and customisable header/arg colours
26+
- **Help on no args**: optionally show help when invoked with no arguments
2627
- **Version display**: `--version` / `-V` (also auto-generated)
2728
- **`--` stop marker**: everything after `--` is treated as positional
2829
- **Short flag merging**: `-abc` expands to `-a -b -c`
@@ -35,209 +36,159 @@ ArgMojo provides a builder-pattern API for defining and parsing command-line arg
3536
- **Negatable flags**: `--color` / `--no-color` paired flags with `.negatable()`
3637
- **Mutually exclusive groups**: prevent conflicting flags (e.g., `--json` vs `--yaml`)
3738
- **Required-together groups**: enforce that related flags are provided together (e.g., `--username` + `--password`)
38-
- **Long option prefix matching**: allow abbreviated options (e.g., `--verb``--verbose`). If the prefix is ambiguous (e.g., `--ver` could match both `--verbose` and `--version`), an error is raised.
39+
- **Long option prefix matching**: allow abbreviated options (e.g., `--verb``--verbose`). If the prefix is ambiguous (e.g., `--ver` could match both `--verbose` and `--version-info`), an error is raised.
40+
- **Append / collect action**: `--tag x --tag y` collects repeated options into a list with `.append()`
41+
- **One-required groups**: require at least one argument from a group (e.g., must provide `--json` or `--yaml`)
42+
- **Value delimiter**: `--env dev,staging,prod` splits by delimiter into a list with `.delimiter(",")`
43+
- **Multi-value options (nargs)**: `--point 10 20` consumes N consecutive values with `.nargs(N)`
3944

4045
---
4146

42-
I created this project to support my experiments with a CLI-based Chinese character search engine in Mojo, as well as a CLI-based calculator for [DeciMojo](https://github.com/forfudan/decimojo). It is inspired by Python's `argparse`, Rust's `clap`, Go's `cobra`, and other popular argument parsing libraries, but designed to fit Mojo's unique features and constraints.
47+
I created this project to support my experiments with a CLI-based Chinese character search engine in Mojo, as well as a CLI-based calculator for [Decimo](https://github.com/forfudan/decimo). It is inspired by Python's `argparse`, Rust's `clap`, Go's `cobra`, and other popular argument parsing libraries, but designed to fit Mojo's unique features and constraints.
4348

4449
My goal is to provide a Mojo-idiomatic argument parsing library that can be easily adopted by the growing Mojo community for their CLI applications. **Before Mojo v1.0** (which means it gets stable), my focus is on building core features and ensuring correctness. "Core features" refer to those who appear in `argparse`/`clap`/`cobra` and are commonly used in CLI apps. "Correctness" means that the library should handle edge cases properly, provide clear error messages, and have good test coverage. Some fancy features will depend on my time and interest.
4550

4651
## Installation
4752

48-
ArgMojo requires Mojo == 0.26.1 and uses [pixi](https://pixi.sh) for environment management.
53+
ArgMojo is available in the modular-community `https://repo.prefix.dev/modular-community` package repository. To access this repository, add it to your `channels` list in your `pixi.toml` file:
4954

50-
```bash
51-
git clone https://github.com/forfudan/argmojo.git
52-
cd argmojo
53-
pixi install
55+
```toml
56+
channels = ["https://conda.modular.com/max", "https://repo.prefix.dev/modular-community", "conda-forge"]
5457
```
5558

56-
I make the Mojo version strictly 0.26.1 because that's the version I developed and tested on, and Mojo is rapidly evolving. Based on my experience, the library will not work every time there's a new Mojo release.
59+
Then, you can install ArgMojo using any of these methods:
60+
61+
1. From the `pixi` CLI, run the command `pixi add argmojo`. This fetches the latest version and makes it immediately available for import.
62+
63+
1. In the `mojoproject.toml` file of your project, add the following dependency:
64+
65+
```toml
66+
argmojo = "==0.2.0"
67+
```
68+
69+
Then run `pixi install` to download and install the package.
70+
71+
The following table summarizes the package versions and their corresponding Mojo versions:
72+
73+
| `argmojo` version | `mojo` version | package manager |
74+
| ----------------- | -------------- | --------------- |
75+
| 0.1.0 | ==0.26.1 | pixi |
76+
| 0.2.0 | ==0.26.1 | pixi |
5777

5878
## Quick Start
5979

60-
Here is a simple example of how to use ArgMojo in a Mojo program. The full example can be found in `examples/demo.mojo`.
80+
Here is a simple example of how to use ArgMojo in a Mojo program. See `examples/grep.mojo` for the full version.
6181

6282
```mojo
63-
from argmojo import Arg, Command
83+
from argmojo import Argument, Command
6484

6585

6686
fn main() raises:
67-
var cmd = Command("demo", "A CJK-aware text search tool that supports Pinyin and Yuhao Input Methods (宇浩系列輸入法).", version="0.1.0")
87+
var app = Command("grep", "Search for PATTERN in each FILE.", version="1.0.0")
6888

6989
# Positional arguments
70-
cmd.add_arg(Arg("pattern", help="Search pattern").positional().required())
71-
cmd.add_arg(Arg("path", help="Search path").positional().default("."))
90+
app.add_argument(Argument("pattern", help="Search pattern").positional().required())
91+
app.add_argument(Argument("path", help="Search path").positional().default("."))
7292

7393
# Boolean flags
74-
cmd.add_arg(
75-
Arg("ling", help="Use Lingming IME for encoding")
76-
.long("ling").short("l").flag()
94+
app.add_argument(
95+
Argument("ignore-case", help="Ignore case distinctions")
96+
.long("ignore-case").short("i").flag()
97+
)
98+
app.add_argument(
99+
Argument("recursive", help="Search directories recursively")
100+
.long("recursive").short("r").flag()
77101
)
78102

79103
# Count flag (verbosity)
80-
cmd.add_arg(
81-
Arg("verbose", help="Increase verbosity (-v, -vv, -vvv)")
104+
app.add_argument(
105+
Argument("verbose", help="Increase verbosity (-v, -vv, -vvv)")
82106
.long("verbose").short("v").count()
83107
)
84108

85-
# Key-value option with choices and metavar
86-
var formats: List[String] = ["json", "csv", "table"]
87-
cmd.add_arg(
88-
Arg("format", help="Output format")
89-
.long("format").short("f").choices(formats^).default("table")
109+
# Key-value option with choices
110+
var formats: List[String] = ["text", "json", "csv"]
111+
app.add_argument(
112+
Argument("format", help="Output format")
113+
.long("format").short("f").choices(formats^).default("text")
90114
)
91115

92116
# Negatable flag — --color enables, --no-color disables
93-
cmd.add_arg(
94-
Arg("color", help="Enable colored output")
117+
app.add_argument(
118+
Argument("color", help="Highlight matching text")
95119
.long("color").flag().negatable()
96120
)
97121

98122
# Parse and use
99-
var result = cmd.parse()
123+
var result = app.parse()
100124
print("pattern:", result.get_string("pattern"))
101-
print("verbose:", result.get_count("verbose"))
125+
print("path: ", result.get_string("path"))
102126
print("format: ", result.get_string("format"))
103127
print("color: ", result.get_flag("color"))
104128
```
105129

106130
## Usage Examples
107131

108-
For detailed explanations and more examples of every feature, see the **[User Manual](docs/user_manual.md)**.
109-
110-
Build the demo binary first, then try the examples below:
132+
For detailed explanations and more examples of every feature, see the User Manual.
111133

112-
```bash
113-
pixi run build_demo
114-
```
115-
116-
### Basic usage — positional args and flags
117-
118-
```bash
119-
./demo "nihao" ./src --ling
120-
```
134+
ArgMojo ships with two complete example CLIs:
121135

122-
### Short options and default values
136+
| Example | File | Features |
137+
| ----------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
138+
| `grep` — simulated grep | `examples/grep.mojo` | Positional args, flags, count flags, negatable flags, choices, metavar, append/collect, value delimiter, nargs, mutually exclusive groups, required-together groups, conditional requirements, numeric range, key-value map, aliases, deprecated args, hidden args, negative-number passthrough, `--` stop marker, custom tips |
139+
| `git` — simulated git | `examples/git.mojo` | Subcommands (clone/init/add/commit/push/pull/log/remote/branch/diff/tag/stash), nested subcommands (remote add/remove/rename/show), persistent (global) flags, per-command args, mutually exclusive groups, choices, aliases, deprecated args, custom tips |
123140

124-
The second positional arg (`path`) defaults to `"."` when omitted:
141+
Build both example binaries:
125142

126143
```bash
127-
./demo "zhongguo" -l
144+
pixi run build
128145
```
129146

130-
### Help and version
147+
### `grep` (no subcommands)
131148

132149
```bash
133-
./demo --help
134-
./demo --version
135-
```
150+
# Help and version
151+
./grep --help
152+
./grep --version
136153

137-
### Merged short flags
154+
# Basic search
155+
./grep "fn main" ./src
138156

139-
Multiple short flags can be combined in a single `-` token. For example, `-liv` is equivalent to `-l -i -v`:
157+
# Combined short flags + options
158+
./grep -rnic "TODO" ./src --max-depth 5
140159

141-
```bash
142-
./demo "pattern" ./src -liv
143-
```
160+
# Choices, append, negatable
161+
./grep "pattern" --format json --tag fixme --tag urgent --color
144162

145-
### Attached short values
163+
# -- stops option parsing
164+
./grep -- "-pattern-with-dashes" ./src
146165

147-
A short option can receive its value without a space:
148-
149-
```bash
150-
./demo "pattern" -d3 # same as -d 3
151-
./demo "pattern" -ftable # same as -f table
166+
# Prefix matching (--exc matches --exclude-dir)
167+
./grep "fn" --exc .git,node_modules
152168
```
153169

154-
### Count flags — verbosity
155-
156-
Use `-v` multiple times (merged or repeated) to increase verbosity:
170+
### `git` (with subcommands)
157171

158172
```bash
159-
./demo "pattern" -v # verbose = 1
160-
./demo "pattern" -vvv # verbose = 3
161-
./demo "pattern" -v --verbose # verbose = 2 (short + long)
162-
```
163-
164-
### Choices validation
173+
# Root help — shows Commands section + Global Options
174+
./git --help
165175

166-
The `--format` option only accepts `json`, `csv`, or `table`:
176+
# Child help — shows full command path
177+
./git clone --help
167178

168-
```bash
169-
./demo "pattern" --format json # OK
170-
./demo "pattern" --format xml # Error: Invalid value 'xml' for 'format'. Valid choices: json, csv, table
171-
```
179+
# Subcommand dispatch
180+
./git clone https://example.com/repo.git my-project --depth 1
181+
./git commit -am "initial commit"
182+
./git log --oneline -n 20 --author "Alice"
183+
./git -v push origin main --force --tags
172184

173-
### Negatable flags
185+
# Nested subcommands (remote → add/remove/rename/show)
186+
./git remote add origin https://example.com/repo.git
187+
./git remote show origin
174188

175-
A negatable flag pairs `--X` (sets `True`) with `--no-X` (sets `False`) automatically:
176-
177-
```bash
178-
./demo "pattern" --color # color = True
179-
./demo "pattern" --no-color # color = False
180-
./demo "pattern" # color = False (default)
181-
```
182-
183-
### Mutually exclusive groups
184-
185-
`--json` and `--yaml` are mutually exclusive — using both is an error:
186-
187-
```bash
188-
./demo "pattern" --json # OK
189-
./demo "pattern" --yaml # OK
190-
./demo "pattern" --json --yaml # Error: Arguments are mutually exclusive: '--json', '--yaml'
191-
```
192-
193-
### `--` stop marker
194-
195-
Everything after `--` is treated as a positional argument, even if it starts with `-`:
196-
197-
```bash
198-
./demo --ling -- "--pattern-with-dashes" ./src
199-
```
200-
201-
### Hidden arguments
202-
203-
Some arguments are excluded from `--help` but still work at the command line (useful for debug flags):
204-
205-
```bash
206-
./demo "pattern" --debug-index # Works, but not shown in --help
207-
```
208-
209-
### Required-together groups
210-
211-
`--username` and `--password` must be provided together — using one without the other is an error:
212-
213-
```bash
214-
./demo "pattern" --username admin --password secret # OK
215-
./demo "pattern" # OK (neither is provided)
216-
./demo "pattern" --username admin # Error: '--password' required when '--username' is provided
217-
```
218-
219-
### A mock example showing how features work together
220-
221-
```bash
222-
./demo yes ./src --verbo --color -li -d 3 --no-color --usern zhu --pas 12345
223-
```
224-
225-
This will be parsed as:
226-
227-
```bash
228-
=== Parsed Arguments ===
229-
pattern: yes
230-
path: ./src
231-
-l, --ling True
232-
-i, --ignore-case True
233-
-v, --verbose 1
234-
-d, --max-depth 3
235-
-f, --format table
236-
--color False
237-
--json False
238-
--yaml False
239-
-u, --username zhu
240-
-p, --password 12345
189+
# Unknown subcommand → clear error
190+
./git foo
191+
# error: git: Unknown command 'foo'. Available commands: clone, init, ...
241192
```
242193

243194
## Development
@@ -260,19 +211,27 @@ pixi run clean
260211

261212
```txt
262213
argmojo/
263-
├── docs/ # Documentation
264-
│ ├── user_manual.md # User manual with detailed examples
265-
│ └── argmojo_overall_planning.md
214+
├── docs/ # Documentation
215+
│ └── user_manual.md # User manual with detailed examples
216+
├── examples/
217+
│ ├── grep.mojo # grep-like CLI (no subcommands)
218+
│ └── git.mojo # git-like CLI (with subcommands)
266219
├── src/
267-
│ └── argmojo/ # Main package
268-
│ ├── __init__.mojo # Package exports
269-
│ ├── arg.mojo # Arg struct (argument definition)
270-
│ ├── command.mojo # Command struct (parsing logic)
271-
│ └── result.mojo # ParseResult struct (parsed values)
272-
├── tests/
273-
│ └── test_argmojo.mojo # Tests
274-
├── pixi.toml # pixi configuration
275-
├── .gitignore
220+
│ └── argmojo/ # Main package
221+
│ ├── __init__.mojo # Package exports
222+
│ ├── argument.mojo # Argument struct (argument definition)
223+
│ ├── command.mojo # Command struct (parsing logic)
224+
│ └── parse_result.mojo # ParseResult struct (parsed values)
225+
├── tests/ # Test suites (241 tests)
226+
│ ├── test_parse.mojo
227+
│ ├── test_groups.mojo
228+
│ ├── test_collect.mojo
229+
│ ├── test_help.mojo
230+
│ ├── test_extras.mojo
231+
│ ├── test_subcommands.mojo
232+
│ ├── test_negative_numbers.mojo
233+
│ └── test_persistent.mojo
234+
├── pixi.toml # pixi configuration
276235
├── LICENSE
277236
└── README.md
278237
```

recipes/argmojo/recipe.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
context:
2-
version: "0.1.0"
2+
version: "0.2.0"
33
mojo_version: "=0.26.1"
44

55
package:
@@ -8,7 +8,7 @@ package:
88

99
source:
1010
- git: https://github.com/forfudan/argmojo.git
11-
rev: 6db272c433171f1bf5e158d24628581f248aefcc
11+
rev: e9f39bf9d4ddd4e8c7e6ea1cf352a9c82e0dfc7b
1212

1313
build:
1414
number: 0

0 commit comments

Comments
 (0)