Skip to content

fix(unload): reach the Plugin Standard unload function - #502

Merged
ss-o merged 1 commit into
nextfrom
bug-482
Sep 3, 2026
Merged

fix(unload): reach the Plugin Standard unload function#502
ss-o merged 1 commit into
nextfrom
bug-482

Conversation

@ss-o

@ss-o ss-o commented Sep 3, 2026

Copy link
Copy Markdown
Member

Makes the Plugin Standard unload function reachable. Fixes the reported case and a second one found while building z-shell/zd#119.

The defect

(( ${+functions[${plugin}_plugin_unload]} )) && ${plugin}_plugin_unload

$plugin was used verbatim, so two kinds of plug-in could never be reached.

Hyphenated repositories, the reported case. ADR-0020's namespace rules require the shell prefix to use underscores, so zsh-eza can define zsh_eza_plugin_unload and satisfy the standard, or define zsh-eza_plugin_unload and be unloadable by Zi. Not both.

Path-loaded plug-ins, which were not in the report. Such a plug-in is identified as %<absolute path> and $plugin is the directory, so the derived name is /path/to/thing_plugin_unload, which names nothing. Demonstrated while adding unload coverage:

PLUGINS_LIST: %/tmp/.../ulprobe
UNLOADED: func=0 alias=0 fpath_restored=1     # ulprobe_plugin_unload never ran
Running plugin's provided unload code: print -r -- STD-HOOK-RAN   # this did

@zsh-plugin-run-on-unload worked in both cases, which is why the gap stayed invisible: plug-ins using the callback were fine, and only the named-hook contract was broken.

The fix

Try candidate names in order and call the first that exists:

  1. the literal name, so plug-ins already defining it keep working
  2. the underscore form, which is the only name ADR-0020 permits a hyphenated plug-in to define
  3. and 4. the same pair derived from the directory basename, the closest analogue of a repository name for a path-loaded plug-in

Duplicates collapse through (u), and exactly one function is called, since the Standard defines a single unload function per plug-in.

The change is additive. No name that resolved before stops resolving.

Test

tests/unload-hook-dispatch.zsh loads and unloads two plug-ins, one plainly named and one hyphenated, each defining only the name its own rules permit, then asserts both hooks ran. Against the previous dispatch:

the unload function of a path-loaded plug-in was not called: []
not ok - the Plugin Standard unload function was not called      exit=1

Registered in zsh-n.yml, both path filters and a job. Full suite 21/21.

Note on scope

This restores the hook's reachability. It does not change what the hook is expected to do, and it does not touch #113 or #483, which are separate unload defects. z-shell/zd#119 now asserts the four unload contracts that already worked, so a case for each of those can land with its fix.

Closes #482

.zi-unload resolved the Standard hook from $plugin verbatim:

    (( ${+functions[${plugin}_plugin_unload]} )) && ${plugin}_plugin_unload

Two kinds of plug-in could never be reached.

A hyphenated repository, because ADR-0020's namespace rules require the shell
prefix to use underscores. `zsh-eza' can define `zsh_eza_plugin_unload' and
satisfy the standard, or define `zsh-eza_plugin_unload' and be unloadable by Zi,
but not both. That is the reported case.

A plug-in loaded by path, because such a plug-in is identified as `%<absolute
path>' and $plugin is the directory, so `/path/to/thing_plugin_unload' names
nothing. Found while adding unload coverage in z-shell/zd#119, and not in the
original report.

Try candidate names in order and call the first that exists: the literal name,
so plug-ins already defining it keep working; the underscore form; then the same
pair derived from the directory basename, which is the closest analogue of a
repository name for a path-loaded plug-in. Duplicates collapse through (u), and
only one function is called, since the Standard defines a single unload function
per plug-in.

The fix is additive. No name that resolved before stops resolving.

tests/unload-hook-dispatch.zsh loads and unloads two plug-ins, one plainly named
and one hyphenated, each defining only the name its own rules permit, and
asserts both hooks ran. Against the previous dispatch it reports `the unload
function of a path-loaded plug-in was not called: []'.

Closes #482
@ss-o
ss-o requested a review from a team as a code owner September 3, 2026 02:04
@ss-o
ss-o merged commit 5bf7cf1 into next Sep 3, 2026
83 checks passed
@ss-o
ss-o deleted the bug-482 branch September 3, 2026 02:07
@ss-o ss-o mentioned this pull request Sep 3, 2026
13 tasks
@github-actions github-actions Bot mentioned this pull request Sep 3, 2026
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.

1 participant