Skip to content

fix(stack): Make popup close, visibility and restore lifecycle consistent - #53

Merged
mhiro2 merged 8 commits into
mainfrom
fix/popup-lifecycle
Oct 4, 2026
Merged

mhiro2 merged 8 commits into
mainfrom
fix/popup-lifecycle

Conversation

@mhiro2

@mhiro2 mhiro2 commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Close every popup (close, close-all, WinClosed, BufWipeout, cleanup, quick peek) through one path that detaches the model first, releases decorations and keymaps, and records the close and history entry exactly once
  • Keep child popups alive when the periodic cleanup sees their parent popup's buffer gone
  • Show a hidden stack before restoring or focusing a popup so no untracked float is left behind
  • Link parents in restore-all after every popup is open, regardless of close order
  • Track popup activity from the first display, so popups in use are not auto-closed
  • Make a popup follow :buffer / :edit inside its window as a source popup at the final cursor position
  • Add lifecycle integration tests that run through the real autocmds

Changes

  • e07281e : fix(stack): close every popup through one detach-then-release path
    • close-all no longer reports each popup twice through WinClosed; three popups now emit three PeekstackClose events and three history entries
    • A quick peek closed from outside releases its diagnostic extmarks; popups closed with :q / <C-w>c can be restored with undo close
    • Bulk removals collect targets and re-check membership, so nested BufWipeout removals cannot break the loop
  • b0579dd : fix(cleanup): keep child popups when their parent popup closes
    • The periodic scan and the BufWipeout handler share one rule: only popups opened from a regular buffer close with it
  • 58bd2a8 : chore: ignore the test state directory
    • Test runs no longer leave an untracked .tmp/ in the working tree
  • bfd67c5 : fix(stack): show a hidden stack before restoring or focusing a popup
    • restore_last / restore_all / restore_from_history / focus / push share one show path that reopens only popups without a live window
    • reopen_by_id returns a popup that is already shown instead of opening a second window
  • f9c86cc : fix(history): link restored parents after every popup is open
    • A parent closed before its child is linked again after restore-all, also when another entry fails to restore
    • Push events fire once the restored tree is complete
  • 05b2c66 : fix(events): track popup activity from the first display
    • CursorMoved tracking is global instead of being attached on a WinEnter that fires before the popup is registered
  • 96c08f3 : fix(popup): follow a buffer switched into the popup window
    • Provider context, keymaps, title, location and history follow the new buffer; copy popups are no longer dropped into an untracked float
    • The final cursor position (:edit +N, last position) is captured after the command, or at close if that comes first
  • f9efaa9 : docs: describe close history, hidden stack and buffer switch behavior
    • README and help describe undo close for external closes, restore-all parent links, hidden stack auto-show and buffer switching

mhiro2 added 8 commits October 3, 2026 22:21
close_all closed each window while its popup was still in the stack, so
the WinClosed autocmd reported the popup a second time and three popups
produced six PeekstackClose events. A quick peek closed from outside
dropped its model without releasing it, leaving diagnostic extmarks in
the source buffer. Every close route now detaches the model first, then
releases decorations and keymaps, closes the window, and records the
close and history entry once; an externally closed popup can now be
restored with undo close as well.
Closing a popup wipes its copy buffer, and the periodic cleanup treated
that as a lost origin and closed every popup opened from it, even pinned
ones or ones with unsaved source edits. The BufWipeout handler already
kept such children. Both now share one rule: only popups opened from a
regular buffer close together with it.
The test init points XDG_STATE_HOME at .tmp/state, so every test run
left an untracked .tmp/ directory in the working tree.
Restoring from history or focusing a popup while the stack was hidden
opened a window without showing the stack, and the next toggle opened
every popup again, leaving the earlier window as an untracked float
that close-all could not reach. These operations and push now show the
stack first through one path, which reopens only popups without a live
window; reopen_by_id also returns a popup that is already shown as is.
restore_all reopened entries newest first and resolved each parent on
the spot, so a parent closed before its child was not open yet and the
child lost its parent. Popups are now opened first and their parents
linked in a second pass through the ids they were restored under, and
the push events follow once the tree is complete. Single restores keep
using the same id mapping.
Cursor tracking was attached to a popup buffer on WinEnter, but the
first WinEnter fires while the window is opened, before the popup is
registered. A popup that was never left and re-entered kept its
creation time as last activity and was auto-closed while in use. The
CursorMoved hook is now global and touches whichever popup window the
cursor moves in.
After :buffer or :edit inside a popup, the popup still described the
previous buffer, so provider requests used the new cursor position in
the old file and the stack view, title and history kept the old place.
For copy popups the wiped copy buffer even dropped the popup and left
its window as an untracked float. The popup now follows the new buffer
as a source-mode popup at the cursor, moving its keymaps, title and
location along and releasing what it placed on the old buffer.
Document that undo close also covers popups closed outside peekstack,
that restore-all keeps parent links, that focusing or restoring a popup
shows a hidden stack, and that a popup follows a buffer switched into
its window.
@mhiro2
mhiro2 force-pushed the fix/popup-lifecycle branch from ed41313 to f9efaa9 Compare October 3, 2026 13:26
@mhiro2 mhiro2 self-assigned this Oct 4, 2026
@mhiro2 mhiro2 added the bug Something isn't working label Oct 4, 2026
@mhiro2
mhiro2 merged commit d214a37 into main Oct 4, 2026
3 checks passed
@mhiro2
mhiro2 deleted the fix/popup-lifecycle branch October 4, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant