fix(parse): handle variadic ellipsis inside brackets like [args...] - #481
Conversation
The spec parser was not recognizing `[args...]` or `<args...>` as variadic arguments. The ellipsis check only ran before bracket stripping, so `[args...]` (ending with `]` not `...`) was missed. Add a second ellipsis check after brackets are stripped so both `[args]...` and `[args...]` correctly set var=true. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes the spec parser to correctly recognize variadic arguments when the ellipsis appears inside brackets (e.g., [args...] or <args...>). Previously, only the syntax with ellipsis outside brackets (e.g., [args]...) was supported, causing unknown flags to fail parsing instead of being captured by variadic arguments.
Changes:
- Added a second ellipsis check in
SpecArg::From<&str>that runs after bracket stripping - Added comprehensive test coverage for the new syntax variants
- Updated an existing test case that now correctly parses
<-- shell...>as variadic
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| lib/src/spec/arg.rs | Added logic to detect and strip ellipsis from inside brackets after initial bracket processing |
| lib/tests/parse.rs | Added integration tests verifying unknown flags are captured by variadic args with [args...] syntax |
| lib/tests/dump.rs | Updated test to reflect correct parsing of <-- shell...> as variadic with explicit var=#true |
| lib/src/parse.rs | Added unit tests for end-to-end spec parsing and variadic argument behavior |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary of ChangesHello @jdx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request resolves a critical parsing bug that prevented command-line argument specifications from correctly identifying variadic arguments when the ellipsis was placed inside brackets. The fix enhances the argument parsing logic to accurately detect these patterns, ensuring that subsequent command-line inputs, such as unknown flags, are correctly captured by the variadic argument instead of causing parsing errors. This improves the robustness and flexibility of command-line interface definitions. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #481 +/- ##
==========================================
+ Coverage 70.57% 70.71% +0.13%
==========================================
Files 47 47
Lines 6597 6716 +119
Branches 6597 6716 +119
==========================================
+ Hits 4656 4749 +93
- Misses 1264 1277 +13
- Partials 677 690 +13 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Code Review
This pull request correctly implements support for variadic arguments with the ellipsis inside the brackets (e.g., [args...]). The changes are well-structured, and the addition of unit and integration tests ensures the new syntax is parsed correctly and doesn't introduce regressions. I've added a couple of suggestions to make the new tests even more robust by asserting all parsed values. Overall, this is a great improvement to the parser's flexibility.
| assert_eq!(parsed.args.len(), 2); | ||
| let args_val = parsed | ||
| .args | ||
| .iter() | ||
| .find(|(a, _)| a.name == "args") | ||
| .unwrap() | ||
| .1; | ||
| match args_val { | ||
| ParseValue::MultiString(v) => { | ||
| assert_eq!(v, &vec!["--host".to_string(), "localhost".to_string()]); | ||
| } | ||
| _ => panic!("Expected MultiString, got {:?}", args_val), | ||
| } |
There was a problem hiding this comment.
This test is great for verifying that unknown flags are captured by the variadic argument. To make it more robust and readable, you could assert the values of both database and args arguments. Converting the parsed arguments into a HashMap can simplify the assertions.
assert_eq!(parsed.args.len(), 2);
let args: std::collections::HashMap<_, _> = parsed.args.iter().map(|(k, v)| (k.name.as_str(), v)).collect();
assert_eq!(args["database"].to_string(), "mydb");
match args["args"] {
ParseValue::MultiString(v) => {
assert_eq!(v, &vec!["--host".to_string(), "localhost".to_string()]);
}
other => panic!("Expected MultiString for 'args', got {:?}", other),
}| assert_eq!(parsed.args.len(), 2); | ||
| let args_val = parsed | ||
| .args | ||
| .iter() | ||
| .find(|(a, _)| a.name == "args") | ||
| .unwrap() | ||
| .1; | ||
| match args_val { | ||
| ParseValue::MultiString(v) => { | ||
| assert_eq!(v, &vec!["--host".to_string(), "localhost".to_string()]); | ||
| } | ||
| _ => panic!("Expected MultiString, got {:?}", args_val), | ||
| } |
There was a problem hiding this comment.
Similar to the previous test, this one could be made more robust by asserting the value of the database argument in addition to the args argument. Using a HashMap can make the assertions cleaner and more comprehensive.
assert_eq!(parsed.args.len(), 2);
let args: std::collections::HashMap<_, _> = parsed.args.iter().map(|(k, v)| (k.name.as_str(), v)).collect();
assert_eq!(args["database"].to_string(), "mydb");
match args["args"] {
ParseValue::MultiString(v) => {
assert_eq!(v, &vec!["--host".to_string(), "localhost".to_string()]);
}
other => panic!("Expected MultiString for 'args', got {:?}", other),
}This MR contains the following updates: | Package | Update | Change | |---|---|---| | [usage](https://github.com/jdx/usage) | minor | `2.15.1` → `2.16.1` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>jdx/usage (usage)</summary> ### [`v2.16.1`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2161---2026-01-31) [Compare Source](jdx/usage@v2.16.0...v2.16.1) ##### 🐛 Bug Fixes - **(docs)** increase gap between feature grid and action buttons on landing page by [@​jdx](https://github.com/jdx) in [#​482](jdx/usage#482) - **(parse)** handle variadic ellipsis inside brackets like \[args...] by [@​jdx](https://github.com/jdx) in [#​481](jdx/usage#481) ##### 📚 Documentation - add bash array pattern for variadic args by [@​jdx](https://github.com/jdx) in [#​480](jdx/usage#480) ##### 📦️ Dependency Updates - update rust crate clap to v4.5.56 by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​474](jdx/usage#474) - update apple-actions/import-codesign-certs action to v6 by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​477](jdx/usage#477) - update dependency node to v24 by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​478](jdx/usage#478) - update rust crate criterion to 0.8 by [@​renovate\[bot\]](https://github.com/renovate\[bot]) in [#​475](jdx/usage#475) ### [`v2.16.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2160---2026-01-29) [Compare Source](jdx/usage@v2.15.1...v2.16.0) ##### 🚀 Features - **(windows)** add Windows binaries and fix completion support by [@​jdx](https://github.com/jdx) in [#​472](jdx/usage#472) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0Mi45NC42IiwidXBkYXRlZEluVmVyIjoiNDIuOTUuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
Summary
[args...]and<args...>as variadic arguments[args]...and<args>...(ellipsis outside brackets) were recognized as variadic[args...](ending with]) was missedProblem
When a usage spec defines
arg "[args...]", the...inside brackets was not parsed as making the arg variadic (var=true). This caused unknown flags like--host localhostto fail with "unexpected word: localhost" instead of being captured into the variadic arg.Example failing spec:
mydb --host localhostwould error instead of settingdatabase="mydb"andargs=["--host", "localhost"].Fix
Add a second ellipsis check after bracket stripping in
From<&str> for SpecArg, so both[args]...and[args...]correctly setvar=true.Test plan
[args...],<args...>, and[args…]syntax inarg.rs<-- shell...>which is now correctly parsed as variadic🤖 Generated with Claude Code
Note
Low Risk
Low risk: small, targeted change to spec-string parsing for variadic args plus added coverage; main risk is minor behavior change for specs that previously treated
[args...]as a literal name.Overview
Fixes spec parsing so variadic positional args can be declared as
[args...]/<args...>(including unicode…) by detecting ellipses after stripping the surrounding brackets.Adds regression tests covering end-to-end parsing where unknown flags/words are captured into the variadic arg, and updates the dump round-trip expectation for a
double_dashvariadic arg representation.Written by Cursor Bugbot for commit 600edf5. This will update automatically on new commits. Configure here.