Skip to content

fix(unload): repeated-load takeover misses linked keymaps and duplicates keymap records #583

Description

@ss-o

Environment

Zsh 5.9.2, Linux; zi next plus #582 at 2832076. Found by the third independent review of that pull request (#582 (review)).

Minimal reproduction

Each case runs in a clean zsh -f with an isolated HOME, XDG_* and ZDOTDIR. p, tv, te, r and n are local plugin directories.

  1. Linked main keymap. p runs bindkey '^X^P' zi-repeat-widget, and tv runs bindkey -M viins '^X^P' end-of-line:
bindkey -v                     # main is now linked to viins
zi load "$p"; zi load "$tv"; zi load "$p"
zi unload "$p"
bindkey -M viins '^X^P'        # tv is still loaded

The same happens with bindkey -e and a plugin that binds the key with -M emacs. An EDITOR containing vi links main to viins at startup, so case 1 also applies without an explicit bindkey -v.

  1. Duplicate keymap records. n runs bindkey -N nmap emacs and bindkey -M nmap '^X^P' end-of-line:
zi load "$n"; zi load "$n"
zi unload "$n"
  1. A change made without zi records. p defines shared_fn, and r defines the same function:
zi load "$p"; unfunction shared_fn
zi light-mode for "$r"
zi load "$p"; zi unload "$p"
(( ${+functions[shared_fn]} ))   # r is still loaded

Actual behavior

  1. Both main and viins end up with "^X^P" undefined-key while tv is still loaded. On next (75d722c), both keep end-of-line. With a single load of p, the result is the same on both branches.
  2. The end state is correct, but unload prints .zi-unload:bindkey:90: no such keymap 'nmap' and .zi-unload:bindkey:113: no such keymap 'nmap', and repeats the Deleting lines. The repeated load keeps the -N record twice. On next, each line appears once and there are no errors.
  3. shared_fn is removed (0); on next it stays (1). A single load of p gives 0 on both branches. The pull request's Known limits section names only a user rebinding a key or redefining a widget, not functions or plugins loaded in light mode.

Expected behavior

  1. A binding through the keymap main is linked to counts as a change of the same binding. The takeover check resolves the link when it builds the identity, so a repeated load keeps next's behaviour. A linked-taken scenario in tests/repeated-load-ownership.zsh pins this.
  2. A repeated load does not append a record whose text it already holds, so unload replays each record once.
  3. The Known limits text says the limit covers any change made without zi records (by the user, or by a plugin loaded in light mode), functions included. Whether to detect these changes stays with fix(unload): preserve runtime ownership across repeated plugin loads #113.

Refs #113.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:ziZi core behavior, APIs, or documentation.type:bugSomething is broken or behaving incorrectly.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions