Skip to content

Conversation

@jdx
Copy link
Owner

@jdx jdx commented Jan 26, 2026

Summary

  • Adds a Parser struct that allows customizing parsing behavior
  • Particularly useful for providing a custom environment variable map instead of using the process environment

This is needed for tools like mise where monorepo tasks may have env vars defined in child config files that aren't in the current process environment.

Example usage

use std::collections::HashMap;
use usage::parse::Parser;

let env: HashMap<String, String> = [("NAME".into(), "john".into())].into();
let result = Parser::new(&spec)
    .with_env(env)
    .parse(&args)?;

The existing parse() function is unchanged and continues to work as before (it now uses Parser internally with default options).

API Design

The Parser struct uses #[non_exhaustive] to allow adding new options in the future without breaking changes.

🤖 Generated with Claude Code


Note

Introduce Parser for customizable parsing

  • Export new parse::Parser with with_env to supply a custom HashMap<String, String> for env lookups; parse() now delegates to Parser
  • Refactor parse_partial into internal parse_partial_with_env and update required arg/flag validation to consider the custom env map before std::env
  • Preserve existing behavior by default (process env) while enabling monorepo/task workflows needing non-process env vars
  • Add tests covering custom env for required args/flags, precedence, and error cases

Public API: Parser exported via lib.rs

Written by Cursor Bugbot for commit 6294833. This will update automatically on new commits. Configure here.

Copilot AI review requested due to automatic review settings January 26, 2026 15:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a Parser builder pattern to enable custom environment variable handling during command-line parsing. The primary motivation is to support tools like mise where monorepo tasks may define environment variables in child config files rather than the process environment.

Changes:

  • Added a Parser struct with a builder pattern for configurable parsing options
  • Modified the existing parse() function to use Parser internally while maintaining backward compatibility
  • Exported the new Parser type from the library's public API

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
lib/src/parse.rs Implements the Parser builder struct with with_env() method and refactors environment variable lookups to use either custom or process environment
lib/src/lib.rs Exports the new Parser type alongside the existing parse function

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +96 to +102
let get_env = |key: &str| -> Option<String> {
if let Some(ref env_map) = self.env {
env_map.get(key).cloned()
} else {
// For var=false, return the first default value as String
out.args.insert(
Arc::new(arg.clone()),
ParseValue::String(arg.default[0].clone()),
);
std::env::var(key).ok()
}
}
}
};
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_env closure is defined inside the parse method but could be extracted as a private method on Parser. This would improve readability and make the logic easier to test independently. Consider adding a method like fn get_env_var(&self, key: &str) -> Option<String>.

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Jan 26, 2026

Codecov Report

❌ Patch coverage is 42.92035% with 129 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.43%. Comparing base (6125f1f) to head (6294833).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/src/parse.rs 42.92% 66 Missing and 63 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #464      +/-   ##
==========================================
- Coverage   76.50%   71.43%   -5.08%     
==========================================
  Files          47       47              
  Lines        6253     6480     +227     
  Branches     6253     6480     +227     
==========================================
- Hits         4784     4629     -155     
- Misses       1110     1238     +128     
- Partials      359      613     +254     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

lib/src/parse.rs Outdated
///
/// Returns the parsed arguments and flags, with defaults and env vars applied.
pub fn parse(self, input: &[String]) -> Result<ParseOutput, miette::Error> {
let mut out = parse_partial(self.spec, input)?;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Custom env map ignored during required arg/flag validation

Medium Severity

When using Parser::with_env() with a custom environment map, required args/flags that have env vars defined will incorrectly fail validation if the env var exists in the custom map but not in the process environment. The parse_partial function validates required args/flags by checking std::env::var() directly (ignoring the custom env map), and adds MissingArg/MissingFlag errors before Parser::parse applies the custom env values. These errors then cause the parse to fail even though the env var would have been resolved correctly from the custom map.

Fix in Cursor Fix in Web

jdx and others added 2 commits January 26, 2026 09:24
Adds a Parser struct that allows customizing parsing behavior,
particularly for providing a custom environment variable map instead
of using the process environment.

This is useful for tools like mise where monorepo tasks may have
env vars defined in child config files that aren't in the current
process environment.

Example usage:
  let env: HashMap<String, String> = [...].into();
  let result = Parser::new(&spec)
      .with_env(env)
      .parse(&args)?;

The existing parse() function is now a thin wrapper that uses Parser
with default options.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When using Parser::with_env() with a custom environment map, required
args/flags that have env vars defined now correctly pass validation if
the env var exists in the custom map.

Previously, parse_partial validated required args/flags by checking
std::env::var() directly, ignoring the custom env map. This caused
validation to fail even though the env var would have been resolved
correctly from the custom map during value application.

This fix creates an internal parse_partial_with_env function that
accepts the custom env map and uses it during validation.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@jdx jdx force-pushed the feat/parser-builder branch from 6e3d078 to de2f437 Compare January 26, 2026 15:24
@jdx
Copy link
Owner Author

jdx commented Jan 26, 2026

bugbot run

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

@jdx jdx merged commit 1ba81c2 into main Jan 26, 2026
9 checks passed
@jdx jdx deleted the feat/parser-builder branch January 26, 2026 15:55
jdx pushed a commit that referenced this pull request Jan 26, 2026
### 🚀 Features

- **(parse)** add Parser builder for custom env var handling by
[@jdx](https://github.com/jdx) in
[#464](#464)

### 🧪 Testing

- **(cli)** use fish output format for cleaner assertions by
[@ilyagr](https://github.com/ilyagr) in
[#461](#461)

### 🔍 Other Changes

- add cargo-semver-checks to detect breaking changes by
[@jdx](https://github.com/jdx) in
[#463](#463)
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Jan 27, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [usage](https://github.com/jdx/usage) | minor | `2.13.1` → `2.15.0` |

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.15.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2150---2026-01-26)

[Compare Source](jdx/usage@v2.14.0...v2.15.0)

##### 🚀 Features

- **(parse)** add Parser builder for custom env var handling by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;464](jdx/usage#464)

##### 🧪 Testing

- **(cli)** use fish output format for cleaner assertions by [@&#8203;ilyagr](https://github.com/ilyagr) in [#&#8203;461](jdx/usage#461)

##### 🔍 Other Changes

- add cargo-semver-checks to detect breaking changes by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;463](jdx/usage#463)

### [`v2.14.0`](https://github.com/jdx/usage/blob/HEAD/CHANGELOG.md#2140---2026-01-26)

[Compare Source](jdx/usage@v2.13.1...v2.14.0)

##### 🚀 Features

- **(lint)** add more lint checks by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;446](jdx/usage#446)
- add logo to docs site by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;442](jdx/usage#442)
- add VT323 retro terminal font and --usage branding by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;443](jdx/usage#443)
- add missing builder methods by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;444](jdx/usage#444)

##### 🐛 Bug Fixes

- use pithy LLM-generated title for GitHub releases by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;441](jdx/usage#441)
- replace unwrap calls with proper error handling in fig.rs by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;454](jdx/usage#454)
- improve error messages with more context by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;449](jdx/usage#449)
- skip powershell test if pwsh is not installed by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;457](jdx/usage#457)
- match completion prefix against unescaped names by [@&#8203;ilyagr](https://github.com/ilyagr) in [#&#8203;460](jdx/usage#460)

##### 🚜 Refactor

- simplify Spec::merge with local macros by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;451](jdx/usage#451)

##### 📚 Documentation

- add CLAUDE.md for Claude Code guidance by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;452](jdx/usage#452)
- escape generic type parameters in macro doc comments by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;453](jdx/usage#453)
- add rustdoc for public API functions by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;450](jdx/usage#450)
- add documentation to public API structs by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;455](jdx/usage#455)
- add conventional commit guidance to CLAUDE.md by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;459](jdx/usage#459)

##### ⚡ Performance

- remove unnecessary clone in set\_subcommand\_ancestors by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;448](jdx/usage#448)

##### 🧪 Testing

- add test coverage for untested modules by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;447](jdx/usage#447)

##### 🔍 Other Changes

- remove commented-out trait implementations in mount.rs by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;445](jdx/usage#445)
- make codecov checks informational by [@&#8203;jdx](https://github.com/jdx) in [#&#8203;456](jdx/usage#456)

##### 📦️ Dependency Updates

- lock file maintenance by [@&#8203;renovate\[bot\]](https://github.com/renovate\[bot]) in [#&#8203;439](jdx/usage#439)

##### New Contributors

- [@&#8203;ilyagr](https://github.com/ilyagr) made their first contribution in [#&#8203;460](jdx/usage#460)

</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:eyJjcmVhdGVkSW5WZXIiOiI0Mi45MC4wIiwidXBkYXRlZEluVmVyIjoiNDIuOTIuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants