Conversation
…oads A repeated load of one plugin checks whether another plugin took one of its bindings over in between. `bindkey -v` and `bindkey -e` link main to viins or emacs, so a plugin binding a key with `-M viins` changes the binding of main as well; the check now resolves the keymap main is linked to when it builds a binding's identity, and the repeated load keeps the behaviour of next in that case. A repeated load also kept its earlier records and then appended the same `bindkey -N`, `bindkey -A` and zle hook records again, so unload replayed them twice and printed "no such keymap" and "no such widget" errors. Bindkey and widget-delete records are now appended only when the plugin does not already hold the same record. The comment on the repeated-load path and the test header now state the wider known limit: a change made without zi records, by the user or by a plugin loaded in light mode, to a function, widget or binding, is not detected. Refs #583 Refs #113
|
Review request record for head
The maintainer has elected the ADR-0026 fallback for this repository class. An independent read-only review of this head is running, and the fallback review of record will be posted on this head. |
ss-o
left a comment
There was a problem hiding this comment.
Fallback review under ADR-0026: Copilot request not registered on 51e702b
The Copilot request is recorded in #584 (comment). This review covers 51e702b against next at 8bbd62c. It ran the organization code-review skill against code-review-generic.instructions.md as an independent read-only review (separate session on a different model), and every probe it reported was rerun on the same head.
Verdict
Changes requested: one finding (inline). The rest of the change holds.
- Correctness: pass, with the inline finding. Link resolution was probed with
mainlinked to viins, emacs and a user keymap, withmainunlinked (bindkey -N main), with the plugin runningbindkey -vorbindkey -A x mainitself, and with the link changing between the two loads. In every case head matched or bettered8bbd62c. The record check never dropped a record unload needs: a key rebound with different previous widgets keeps distinct records,-Acopies keep their incrementing names, and dtrace records are untouched. - Public contract: pass.
.zi-add-record,.zi-repeat-*and theBINDKEYS__/WIDGETS_DELETE__keys are internal, and the record format and unload replay are unchanged. - Shell-state integrity: pass, with the inline finding. In the known-limit cases (link changed between loads, light mode) head equals or betters
8bbd62c. - Tests: pass. 16 of 16 scenarios pass on head, and with head's test on
8bbd62cexactly the four new scenarios fail. - Comments: pass. The known-limit comment and the test header match the behaviour.
Finding
- Option-dependent record check (
zi.zshline 1277). Inline.
Verification limits
- Zsh 5.9.x on Linux only.
- The probes covered
zi load,zi light,zi unloadand dtrace, not turbo (wait) loads orzi updatereloads. - Two pre-existing behaviours were seen identically on
8bbd62cand are not caused by this change: the<plugin>-main-Nbackup keymaps stay after unload, and a viins binding that existed before a repeated-M viinsload is not restored (#113).
`.zi-add-record` is called from the zle substitute, which keeps the plugin's options. With `ksh_arrays` set while a plugin runs `zle -N`, the `(Ie)` subscript returned 0 for the first record, so a repeated load still appended the hook record twice and unload printed "no such widget". The function now starts with `emulate -L zsh`, and a `hook-twice-ksh` scenario pins the case. Refs #583
|
Review request record for head
The round-1 fallback review on |
ss-o
left a comment
There was a problem hiding this comment.
Fallback review under ADR-0026: Copilot request not registered on e8a7a35
The Copilot request is recorded in #584 (comment). This review covers e8a7a35 against next at 8bbd62c, the whole change and not only the delta since round 1. It ran the organization code-review skill against code-review-generic.instructions.md as an independent read-only review (separate session on a different model). Its key probes were rerun on the same head with the same results.
Verdict
No findings. The round-1 finding (option-dependent record check, 51e702b) is fixed and its thread is resolved.
- Correctness: pass. The default map,
-M mainand the keymapmainis linked to share one identity, including a user keymap and a quoted keymap name. The record check drops only text-identical records and keeps the first, so reverse replay still ends at the first record's previous widget. - Public contract: pass. Only internal functions and
ZI[...]record keys change; thebindkeyandzlesubstitutes keep their signatures and return status. dtrace records are untouched, andbindkey -Acopies with incrementing names are all replayed. - Shell-state integrity: pass.
.zi-add-recordruns underemulate -L zsh. With each of 19 plugin-set options (among themksh_arrays,sh_word_split,no_multibyte,extended_glob,ksh_typeset,no_glob,no_unset,err_return,warn_create_global), head records each object once and unloads with no errors, where8bbd62cduplicates records and prints three errors. The plugin's own options are unchanged by the substitutes. Widget and keymap names containing] [ ( ) * $and spaces behave the same way. - Tests: pass. 17 of 17 scenarios pass on head; with head's test on
8bbd62cexactly the five new scenarios fail.zsh -f -nis clean onzi.zshand the test. CI is green on this head. - Comments: pass. The known-limit comment, the test header and the
$main_mapnote on.zi-repeat-object-keymatch the behaviour.
Probes (base 8bbd62c against head)
Unlinked main, main linked to a user keymap, the plugin running bindkey -v or bindkey -A x main itself, the link changing between loads, a key bound and rebound in one load, dtrace and light mode, a widget and hook created twice, -M viins and -N across three loads, a standalone main keymap, ksh_arrays around zle -N, the 19-option matrix, hostile names, option leakage and a quoted keymap link. In each, head matches 8bbd62c or fixes the reported defect; none is worse.
Verification limits
- Zsh 5.9.2 on Linux only.
- No turbo (
wait) loads orzi updatereloads, and no ZD integration run. - Two behaviours seen identically on
8bbd62care not caused by this change: the<plugin>-main-Nbackup keymaps stay after unload, and a viins binding that existed before a repeated-M viinsload is not restored (#113).
Description
Follow-up to #582, from its third independent review. Two defects in the repeated-load path, and the wider known limit.
bindkey -vlinksmaintoviinsandbindkey -elinks it toemacs(anEDITORcontainingvidoes the first at startup). A plugin that binds the key with-M viinsthen changesmain's binding too, but the takeover check comparedviinswith the default map and missed it, so p's repeated load kept its records and its unload left"^X^P" undefined-keyin both maps while the other plugin was still loaded..zi-repeat-taken-overnow reads the keymapmainis linked to (bindkey -lL main), and.zi-repeat-object-keygives the default map,-M mainand that keymap one identity. The result isnext's behaviour again.bindkey -N,bindkey -Aand zle hook records again, so unload replayed them twice:no such keymapfrombindkey -Nand-Arecords,no such widgetfrom a hook such aszle-line-init. The new.zi-add-recordappends a bindkey or widget-delete record only when the plugin does not already hold the same text, underemulate -L zshso a plugin's options (ksh_arrays) do not change the check. The hook case was not in the issue; it is the same record replay and was found while reproducing it.Related issues
Closes #583
Refs #113 (the interleaved case, per-load records and changes made without records stay open there).
Type of change
fix- bug fix (non-breaking)test- test addition or correctionChecklist
next; only same-repository hotfixes targetmainnexttomainpromotion uses a merge commit and records both parent SHAs (not a promotion)Co-authored-bytrailer credits a real human, never a bot, AI agent, or automation (none)zsh -n zi.zsh/ Trunk checks)Verification
Zsh 5.9.2, Linux, each in a scratch copy of the tree:
tests/repeated-load-ownership.zshgains 5 scenarios:linked-taken(main linked to viins),linked-taken-emacs,keymap-twice(abindkey -Nplugin loaded twice: the keymap is deleted exactly once, no errors),hook-twice(azle-line-initplugin loaded twice: nono such widget) andhook-twice-ksh(the same withksh_arraysset around the plugin'szle -N, from the first review). Onnext(8bbd62c) with the new test copied in, these 5 fail and the other 12 pass; on this branch 17 of 17 pass.hook-twice-kshalso failed on51e702band passes one8a7a35.linked-taken,linked-taken-emacsfail), link resolved only for the default map and not for-M main(main-taken), records appended without the check (keymap-twice,hook-twice), link lookup removed (linked-taken,linked-taken-emacs), widget-delete records appended without the check (hook-twice).e8a7a35, every test command inzsh-n.yml: 39 of 39 pass (version-reporting.zshandself-update-reload.zshfrom a committed snapshot, as they clone the checkout).zsh -nandzcompileon every file of the workflow matrix: clean.contracts/public-contract-v1.jsonnames none of the touched internal functions or keys.Known limits:
next. Detecting these changes stays with fix(unload): preserve runtime ownership across repeated plugin loads #113.bindkeyrecords with a key take part in the takeover check;bindkey -Aand-Nrecords do not.zi reportstill shows only the newest load's functions for a plugin.