fix(restore): preserve live buffer and cursor across close/restore - #15
Merged
Conversation
popup.opts.target_bufnr / lnum / col are captured once by the adapter at
peek time and never refreshed. If the user navigates inside a popup (gd
/ gf / :edit / direct cursor moves), the popup's window state diverges
from opts: the window shows a different buffer or has the cursor at a
different position. close_all + restore then reopens what was *originally*
peeked, not what the user was last viewing -- losing their navigation.
Snapshot the popup's live state into opts at two points:
1. Popup:snapshot_state() reads nvim_win_get_buf + nvim_win_get_cursor
and writes back to self.opts. Idempotent; rerunning is a no-op if
the popup hasn't moved since the last snapshot.
2. Two callers cover the close paths:
- Popup:close (the programmatic close_all path; close_all suppresses
WinLeave via eventignore so the autocmd below cannot catch it here).
- A new WinLeave autocmd in init.lua (the focus-leaves and external
`:close` paths; Popup:close is not invoked when the popup closes via
nvim's own WinClosed -> on_popup_closed dispatch).
Every close path is covered by at least one snapshot point.
The autocmd reads `is_overlook_popup` via nvim_win_get_var rather than
vim.w because tests reassign `vim.w = {}` for isolation, which detaches
the proxy from real window-locals.
opts.col is 1-indexed (the adapters use vim.fn.getpos);
nvim_win_get_cursor returns 0-indexed col, so snapshot_state adds 1 for
the round-trip with set_cursor_position's `math.max(0, col - 1)` on
restore.
Adds two regression tests: one for the WinLeave path (user switches
focus before close_all), one for the Popup:close path (user is still
inside the popup at close_all time).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.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.
popup.opts.target_bufnr / lnum / col are captured once by the adapter at
peek time and never refreshed. If the user navigates inside a popup (gd
/ gf / :edit / direct cursor moves), the popup's window state diverges
from opts: the window shows a different buffer or has the cursor at a
different position. close_all + restore then reopens what was originally
peeked, not what the user was last viewing -- losing their navigation.
Snapshot the popup's live state into opts at two points:
Popup:snapshot_state() reads nvim_win_get_buf + nvim_win_get_cursor
and writes back to self.opts. Idempotent; rerunning is a no-op if
the popup hasn't moved since the last snapshot.
Two callers cover the close paths:
WinLeave via eventignore so the autocmd below cannot catch it here).
:closepaths; Popup:close is not invoked when the popup closes vianvim's own WinClosed -> on_popup_closed dispatch).
Every close path is covered by at least one snapshot point.
The autocmd reads
is_overlook_popupvia nvim_win_get_var rather thanvim.w because tests reassign
vim.w = {}for isolation, which detachesthe proxy from real window-locals.
opts.col is 1-indexed (the adapters use vim.fn.getpos);
nvim_win_get_cursor returns 0-indexed col, so snapshot_state adds 1 for
the round-trip with set_cursor_position's
math.max(0, col - 1)onrestore.
Adds two regression tests: one for the WinLeave path (user switches
focus before close_all), one for the Popup:close path (user is still
inside the popup at close_all time).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com