fix(shell): resolve function/alias shadowing for zsh and bash#98
Merged
Conversation
…r templates
The previous approach wrapped every alias in a shell function, which caused
infinite recursion for same-name aliases like `ls = "ls -la"` (zsh/bash
detect self-reference in native aliases but not in functions).
- simple aliases → `alias name="command"` (safe, idiomatic)
- parameterized aliases with {{N}}/{{@}} → shell function (required)
- unalias → `unalias ... 2>/dev/null; unset -f ... 2>/dev/null` to handle
both old function-style and new native aliases during migration
Mirrors the fine-grained approach fish already uses. Closes #97.
Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
- native aliases silently ignored when a same-named function exists in the shell (aliases beat functions in zsh/bash) — fix by scanning `typeset +f` / `declare -F` and emitting `unset -f` only for confirmed conflicts - functions silently ignored when a same-named alias exists — fix by scanning `alias` output and emitting `unalias` only for confirmed conflicts - both scans set `_AM_DETECTING_ALIASES` to prevent recursive `am` invocations from the shell startup files sourced during the scan - adds `env_vars` module to centralise all shell-env-var string constants - zsh and bash each own their rendering logic (Zsh/Bash structs); NixShell remains the shared fallback for brush Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
Clippy `collapsible_match` lint fired in CI (--all-features) for two patterns in am-tui that were pre-existing but not caught locally without the feature flag. Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
- seed ~/.zshrc with `la='ls -lAh'` on non-Windows runners - ensures the zsh alias scan integration test passes in CI where runners have a bare shell config Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
- add apt-get install zsh step for Linux runners - zsh is pre-installed on macOS but absent on ubuntu-latest Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
- extract zsh binary/env tests into tests/e2e.rs, all marked #[ignore] - keep pure parser unit test in zsh_alias_scan.rs - run e2e suite explicitly in CI: cargo test --test e2e -- --ignored - add apt-get update before zsh install on Linux runners Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #98 +/- ##
==========================================
+ Coverage 73.99% 74.19% +0.20%
==========================================
Files 45 45
Lines 11510 11779 +269
Branches 11510 11779 +269
==========================================
+ Hits 8517 8740 +223
- Misses 2811 2859 +48
+ Partials 182 180 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- collapse match guard onto one line (transfer.rs) - convert doc comments to inner module doc style (zsh_alias_scan.rs) Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
- CI runners have a bare zsh with only 2-3 built-in aliases - the meaningful assertion is that `la` was sourced from ~/.zshrc - removed the `keys.len() > 5` guard that assumed a rich plugin env Signed-off-by: Sven Kanoldt <sven@d34dl0ck.me>
Merged
sassman
pushed a commit
that referenced
this pull request
Apr 18, 2026
## 🤖 New release
* `amoxide`: 0.6.1 -> 0.7.0 (⚠ API breaking changes)
* `amoxide-tui`: 0.6.1 -> 0.7.0
### ⚠ `amoxide` breaking changes
```text
--- failure constructible_struct_adds_field: externally-constructible struct adds field ---
Description:
A pub struct constructible with a struct literal has a new pub field. Existing struct literals must be updated to include the new field.
ref: https://doc.rust-lang.org/reference/expressions/struct-expr.html
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/constructible_struct_adds_field.ron
Failed in:
field ShellContext.external_functions in /tmp/.tmpnR09NE/amoxide-rs/crates/am/src/shell/shell.rs:41
field ShellContext.external_aliases in /tmp/.tmpnR09NE/amoxide-rs/crates/am/src/shell/shell.rs:43
--- failure enum_missing: pub enum removed or renamed ---
Description:
A publicly-visible enum cannot be imported by its prior path. A `pub use` may have been removed, or the enum itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_missing.ron
Failed in:
enum amoxide::shell::Shells, previously in file /tmp/.tmpgcZOTb/amoxide/src/shell/shell.rs:28
--- failure enum_struct_variant_field_added: pub enum struct variant field added ---
Description:
An enum's exhaustive struct variant has a new field, which has to be included when constructing or matching on this variant.
ref: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_struct_variant_field_added.ron
Failed in:
field force of variant Commands::Init in /tmp/.tmpnR09NE/amoxide-rs/crates/am/src/cli.rs:85
--- failure enum_tuple_variant_field_added: pub enum tuple variant field added ---
Description:
An enum's exhaustive tuple variant has a new field, which has to be included when constructing or matching on this variant.
ref: https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/enum_tuple_variant_field_added.ron
Failed in:
field 1 of variant Message::InitShell in /tmp/.tmpnR09NE/amoxide-rs/crates/am/src/messages.rs:37
field 1 of variant Message::InitShell in /tmp/.tmpnR09NE/amoxide-rs/crates/am/src/messages.rs:37
--- failure struct_missing: pub struct removed or renamed ---
Description:
A publicly-visible struct cannot be imported by its prior path. A `pub use` may have been removed, or the struct itself may have been renamed or removed entirely.
ref: https://doc.rust-lang.org/cargo/reference/semver.html#item-remove
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/struct_missing.ron
Failed in:
struct amoxide::shell::Zsh, previously in file /tmp/.tmpgcZOTb/amoxide/src/shell/zsh.rs:5
struct amoxide::shell::Bash, previously in file /tmp/.tmpgcZOTb/amoxide/src/shell/bash.rs:5
--- failure trait_changed_kind: pub trait changed kind ---
Description:
A public trait was replaced by a struct, enum, or union at the same import path.
impl: https://github.com/obi1kenobi/cargo-semver-checks/tree/v0.46.0/src/lints/trait_changed_kind.ron
Failed in:
trait amoxide::shell::Shell became enum in /tmp/.tmpnR09NE/amoxide-rs/crates/am/src/shell/shell_enum.rs:2
```
<details><summary><i><b>Changelog</b></i></summary><p>
## `amoxide`
<blockquote>
##
[0.7.0](v0.6.1...v0.7.0) -
2026-04-18
### Bug Fixes
- Resolve function/alias shadowing for zsh and bash
([#98](#98))
### Features
- Add --force flag to reinitialise shell aliases
([#101](#101))
</blockquote>
## `amoxide-tui`
<blockquote>
##
[0.7.0](v0.6.1...v0.7.0) -
2026-04-18
### Bug Fixes
- Resolve function/alias shadowing for zsh and bash
([#98](#98))
### Features
- Add --force flag to reinitialise shell aliases
([#101](#101))
</blockquote>
</p></details>
---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #97 — native aliases were silently ignored when a same-named shell function existed, and vice-versa.
gs()exists whenalias gs='git status'is defined, both coexist but only the alias is reachable — and if a function was defined after the alias, the alias would be unreachable instead. Neither side should silently win.typeset +f/declare -F) and aliases (alias) atam inittime, then emit cleanup only for confirmed conflicts:unset -f <name>before a native alias when a same-named function existsunalias <name>before a function when a same-named alias existszsh -i -c '…'/bash -i -c '…', which sources startup files and would triggeram hookagain. A new_AM_DETECTING_ALIASESenv var causesamto exit immediately (no-opeval) when set during those subprocesses.env_varsmodule: centralises all_AM_*env var string constants.ZshandBashnow own their own rendering structs with the conditional cleanup logic;NixShellstays as the shared fallback forbrush.Test plan
parse_zsh_function_names,parse_zsh_alias_names,parse_bash_function_names,parse_bash_alias_namesunset -f/unaliasemission inZshandBasham hookproduces no output when_AM_DETECTING_ALIASESis set (recursion guard)cargo clippy --locked --all-targets -- -D warningsclean