mirror of
https://github.com/neovim/neovim.git
synced 2026-07-14 13:20:35 +00:00
refactor(ctx): ctx_restore_curwin #40667
unify context-switching logic. 1. `prevwin` is now restored for all targets (was buf-only). - add a `nvim_win_call` test. 2. The buf-found "restore the shown buffer" dance no longer depends on the origin window: it runs even if the callback closed the origin.
This commit is contained in:
@@ -564,6 +564,20 @@ bool ctx_switch(CtxSwitch *cs, win_T *wp, tabpage_T *tp, buf_T *buf, CtxSwitchFl
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Restores curwin/curbuf and prevwin. If the saved window no longer exists, enters `fallback`.
|
||||
static void ctx_restore_curwin(CtxSwitch *cs, win_T *fallback)
|
||||
{
|
||||
win_T *save_curwin = win_find_by_handle(cs->cs_curwin);
|
||||
if (save_curwin == NULL) {
|
||||
save_curwin = fallback; // Hmm, original window disappeared.
|
||||
}
|
||||
if (save_curwin != NULL) {
|
||||
curwin = save_curwin;
|
||||
curbuf = curwin->w_buffer;
|
||||
}
|
||||
prevwin = win_find_by_handle(cs->cs_prevwin);
|
||||
}
|
||||
|
||||
/// Undoes ctx_switch(): restores the previous location (if possible) and the kept state.
|
||||
///
|
||||
/// No-op if `cs` was zero-initialized, even if ctx_switch() was not called on it:
|
||||
@@ -597,31 +611,18 @@ void ctx_restore(CtxSwitch *cs)
|
||||
}
|
||||
}
|
||||
|
||||
// Look up the window by handle: the user code may have closed it, and
|
||||
// its memory been reused for another window.
|
||||
win_T *const save_curwin = win_find_by_handle(cs->cs_curwin);
|
||||
if (save_curwin != NULL) {
|
||||
curwin = save_curwin;
|
||||
curbuf = curwin->w_buffer;
|
||||
}
|
||||
ctx_restore_curwin(cs, NULL);
|
||||
} else if (cs->cs_ctxwin_idx >= 0) {
|
||||
win_T *cwp = ctx_win_rest(cs);
|
||||
|
||||
win_T *const save_curwin = win_find_by_handle(cs->cs_curwin);
|
||||
if (save_curwin != NULL) {
|
||||
curwin = save_curwin;
|
||||
} else {
|
||||
// Hmm, original window disappeared. Just use the first one.
|
||||
curwin = firstwin;
|
||||
}
|
||||
curbuf = curwin->w_buffer;
|
||||
// May need to restore insert mode for a prompt buffer.
|
||||
ctx_restore_curwin(cs, firstwin);
|
||||
// May need to restore insert-mode for a prompt buffer.
|
||||
// Pairs with the win_enter()..leaving_window() from ctx_win_prep().
|
||||
entering_window(curwin);
|
||||
if (bt_prompt(curbuf)) {
|
||||
curbuf->b_prompt_insert = cs->cs_prompt_insert;
|
||||
}
|
||||
|
||||
prevwin = win_find_by_handle(cs->cs_prevwin);
|
||||
vars_clear(&cwp->w_vars->dv_hashtab); // free all w: variables
|
||||
hash_init(&cwp->w_vars->dv_hashtab); // re-use the hashtab
|
||||
|
||||
@@ -641,29 +642,21 @@ void ctx_restore(CtxSwitch *cs)
|
||||
curwin->w_topfill = 0;
|
||||
}
|
||||
} else {
|
||||
// Restore curwin. Use the window ID, a window may have been closed
|
||||
// and the memory re-used for another one.
|
||||
win_T *const save_curwin = win_find_by_handle(cs->cs_curwin);
|
||||
if (save_curwin != NULL) {
|
||||
// Restore the buffer which was previously edited by curwin, if it was
|
||||
// changed, we are still the same window and the buffer is valid.
|
||||
if (curwin->handle == cs->cs_new_curwin
|
||||
&& curbuf != cs->cs_new_curbuf.br_buf
|
||||
&& bufref_valid(&cs->cs_new_curbuf)
|
||||
&& cs->cs_new_curbuf.br_buf->b_ml.ml_mfp != NULL) {
|
||||
if (curwin->w_s == &curbuf->b_s) {
|
||||
curwin->w_s = &cs->cs_new_curbuf.br_buf->b_s;
|
||||
}
|
||||
curbuf->b_nwindows--;
|
||||
curbuf = cs->cs_new_curbuf.br_buf;
|
||||
curwin->w_buffer = curbuf;
|
||||
curbuf->b_nwindows++;
|
||||
// Restore the buffer previously edited by curwin.
|
||||
if (curwin->handle == cs->cs_new_curwin
|
||||
&& curbuf != cs->cs_new_curbuf.br_buf
|
||||
&& bufref_valid(&cs->cs_new_curbuf)
|
||||
&& cs->cs_new_curbuf.br_buf->b_ml.ml_mfp != NULL) {
|
||||
if (curwin->w_s == &curbuf->b_s) {
|
||||
curwin->w_s = &cs->cs_new_curbuf.br_buf->b_s;
|
||||
}
|
||||
|
||||
curwin = save_curwin;
|
||||
curbuf = curwin->w_buffer;
|
||||
prevwin = win_find_by_handle(cs->cs_prevwin);
|
||||
curbuf->b_nwindows--;
|
||||
curbuf = cs->cs_new_curbuf.br_buf;
|
||||
curwin->w_buffer = curbuf;
|
||||
curbuf->b_nwindows++;
|
||||
}
|
||||
|
||||
ctx_restore_curwin(cs, NULL);
|
||||
}
|
||||
|
||||
if (!cs->cs_same_win) {
|
||||
|
||||
@@ -2553,6 +2553,21 @@ describe('api/buf', function()
|
||||
end)
|
||||
|
||||
describe('nvim_buf_call', function()
|
||||
it('window keeps the buffer when the callback closes the original window', function()
|
||||
local origin = api.nvim_get_current_win()
|
||||
local other_buf = api.nvim_create_buf(true, false)
|
||||
local other_win = api.nvim_open_win(other_buf, false, { split = 'right' })
|
||||
exec_lua(function()
|
||||
vim.api.nvim_buf_call(other_buf, function()
|
||||
vim.api.nvim_win_close(origin, true)
|
||||
vim.cmd('enew') -- switch the context window away from other_buf
|
||||
end)
|
||||
end)
|
||||
-- Original window is gone: stay in the nvim_buf_call window, but buffer is restored.
|
||||
eq(other_win, api.nvim_get_current_win())
|
||||
eq(other_buf, api.nvim_win_get_buf(other_win))
|
||||
end)
|
||||
|
||||
it('preserves visual-mode, unless the callback ended it', function()
|
||||
-- Same-buffer: Visual survives untouched.
|
||||
command('normal! v')
|
||||
|
||||
@@ -3767,6 +3767,24 @@ describe('API/win', function()
|
||||
end)
|
||||
|
||||
describe('nvim_win_call', function()
|
||||
it('restores prevwin', function()
|
||||
local w1 = api.nvim_get_current_win()
|
||||
command('split')
|
||||
local w2 = api.nvim_get_current_win()
|
||||
command('split')
|
||||
local w3 = api.nvim_get_current_win()
|
||||
-- Entry state: curwin=w3, prevwin=w2.
|
||||
eq(w2, fn.win_getid(fn.winnr('#')))
|
||||
exec_lua(function()
|
||||
vim.api.nvim_win_call(w1, function()
|
||||
vim.api.nvim_set_current_win(w2) -- changes prevwin to w1
|
||||
end)
|
||||
end)
|
||||
-- No evidence of the context-switch; curwin/prevwin are restored.
|
||||
eq(w3, api.nvim_get_current_win())
|
||||
eq(w2, fn.win_getid(fn.winnr('#')))
|
||||
end)
|
||||
|
||||
it('supports multiple returns', function()
|
||||
local cur = api.nvim_get_current_win()
|
||||
local other = api.nvim_open_win(api.nvim_create_buf(false, true), false, { split = 'left' })
|
||||
|
||||
Reference in New Issue
Block a user