Skip to content

Fix multi-token command aliases; shorter README; 0.4.1#3

Merged
voidreamer merged 3 commits into
mainfrom
fix/multi-token-command-aliases
Apr 16, 2026
Merged

Fix multi-token command aliases; shorter README; 0.4.1#3
voidreamer merged 3 commits into
mainfrom
fix/multi-token-command-aliases

Conversation

@voidreamer
Copy link
Copy Markdown
Owner

Summary

  • Tokenise multi-token commands: aliases before exec so values like nukex: \${NUKE}/Nuke --nukex and usdview: python3.14 ~/USD/bin/usdview work. Previously the whole string went to Command::new() as a single filename.
  • Tilde expand every split token so ~/foo after whitespace resolves against $HOME rather than being looked up as a relative path.
  • README rewrite: 681 to 404 lines, every 0.4 command covered, multi-token alias behavior documented.
  • Version bumped to 0.4.1. Already published to crates.io.

Test plan

  • New integration tests: run_multi_token_command_alias, run_quoted_tokens_in_alias, run_tilde_expands_in_each_token
  • Full suite: cargo test --release (36 passing)
  • Verified end to end in a real pipeline: anvil run usd -- usdresolve myasset://assets/... now resolves a python3.14 ~/USD/bin/usdresolve alias and returns the expected path.
  • cargo publish --dry-run clean
  • Published to crates.io as anvil-env 0.4.1

🤖 Generated with Claude Code

claude and others added 3 commits April 16, 2026 15:31
`commands:` values have always been passed to `Command::new()` as a
single filename, which breaks any alias that contains whitespace, e.g.:

    commands:
      nukex: ${NUKE_HOME}/Nuke --nukex
      usdview: python3.14 ~/USD/bin/usdview

The expected behavior (and what the walkthrough documents) is that the
first token is the program and the rest are prepended to the user's
args.  This change tokenizes the resolved alias value with POSIX shell
rules via `shell-words`, then executes `Command::new(program)` with
`baked_args ++ user_args`.

Also surfaces a clear error if an alias resolves to an empty string
(previously produced an opaque ENOENT from `Command::new("")`).

Two regression tests added:
  - run_multi_token_command_alias: unquoted tokens
  - run_quoted_tokens_in_alias: quoted strings stay as a single argv entry

Cargo.toml: adds `shell-words = "1.1"` (35 kB, zero deps).

All 35 CLI integration tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Package::expand_env_value only expands a leading ~/, so an alias like
`usdview: python3.14 ~/USD/bin/usdview` had its second token left
literal and execve saw the string `~/USD/bin/usdview` as a relative
path under $PWD.

After shell-words splits the alias into tokens, pipe each through
shellexpand::tilde (already a transitive dep of shellexpand). Only the
leading ~ of each token is expanded, matching POSIX shell behavior.

Regression: run_tilde_expands_in_each_token — creates a fake $HOME with
a script at ~/bin/ping.sh, registers an alias `ping: /bin/bash ~/bin/ping.sh`,
and checks the script runs and prints PONG.

All 36 CLI tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bugfixes:
  - Split multi-token command aliases before exec so values like
    `nukex: ${NUKE}/Nuke --nukex` and `usdview: python3.14 ~/USD/bin/usdview`
    run correctly instead of failing with ENOENT.
  - Tilde expand every token of a split alias so `~/foo` after a space
    resolves against $HOME rather than being looked up as a relative path.

Three regression tests added; full suite now 36 CLI integration tests.

Docs:
  - README shortened from 681 to 404 lines.
  - Every 0.4 command is covered in the Commands section.
  - Multi-token alias behavior documented under Command aliases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@voidreamer voidreamer merged commit 01fdfe2 into main Apr 16, 2026
2 checks passed
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