aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/win_config.c
diff options
context:
space:
mode:
authorSean Dewar <seandewar@users.noreply.github.com>2024-02-04 02:59:26 +0000
committerSean Dewar <6256228+seandewar@users.noreply.github.com>2024-03-08 23:23:55 +0000
commita873f33993ef84e3f954127038e559e1ac1cac43 (patch)
tree732e38f3a4db9af8403ee9633bbc88f53e16d570 /src/nvim/api/win_config.c
parent233649bc757743f7677b2ae414779192a94aa2ae (diff)
downloadrneovim-a873f33993ef84e3f954127038e559e1ac1cac43.tar.gz
rneovim-a873f33993ef84e3f954127038e559e1ac1cac43.tar.bz2
rneovim-a873f33993ef84e3f954127038e559e1ac1cac43.zip
fix(api): open_win fire BufWinEnter for other buffer when !enter && !noautocmd
Problem: BufWinEnter is not fired when not entering a new window, even when a different buffer is specified and buffer-related autocommands are unblocked (!noautocmd). Solution: fire it in the context of the new window and buffer. Do not do it if the buffer is unchanged, like :{s}buffer. Be wary of autocommands! For example, it's possible for nvim_win_set_config to be used in an autocommand to move a window to a different tabpage (in contrast, things like wincmd T actually create a *new* window, so it may not have been possible before, meaning other parts of Nvim could assume windows can't do this... I'd be especially cautious of logic that restores curwin and curtab without checking if curwin is still valid in curtab, if any such logic exists). Also, bail early from win_set_buf if setting the temp curwin fails; this shouldn't be possible, as the callers check that wp is valid, but in case that's not true, win_set_buf will no longer continue setting a buffer for the wrong window. Note that pum_create_float_preview also uses win_set_buf, but from a glance, doesn't look like it properly checks for autocmds screwing things up (win_enter, nvim_create_buf...). I haven't addressed that here. Also adds some test coverage for nvim_open_win autocommands. Closes #27121.
Diffstat (limited to 'src/nvim/api/win_config.c')
-rw-r--r--src/nvim/api/win_config.c39
1 files changed, 31 insertions, 8 deletions
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index e53e13e2a3..9d63a1997c 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -261,8 +261,8 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
switchwin_T switchwin;
// `parent` is valid in `tp`, so switch_win should not fail.
const int result = switch_win(&switchwin, parent, tp, true);
- (void)result;
assert(result == OK);
+ (void)result;
wp = win_split_ins(0, flags, NULL, 0);
restore_win(&switchwin, true);
}
@@ -276,18 +276,41 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err
api_set_error(err, kErrorTypeException, "Failed to create window");
return 0;
}
+
+ // Autocommands may close `wp` or move it to another tabpage, so update and check `tp` after each
+ // event. In each case, `wp` should already be valid in `tp`, so switch_win should not fail.
switchwin_T switchwin;
- if (switch_win_noblock(&switchwin, wp, tp, true) == OK) {
- apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
+ {
+ const int result = switch_win_noblock(&switchwin, wp, tp, true);
+ assert(result == OK);
+ (void)result;
+ if (apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf)) {
+ tp = win_find_tabpage(wp);
+ }
+ restore_win_noblock(&switchwin, true);
}
- restore_win_noblock(&switchwin, true);
- if (enter) {
+ if (tp && enter) {
goto_tabpage_win(tp, wp);
+ tp = win_find_tabpage(wp);
}
- if (win_valid_any_tab(wp) && buf != wp->w_buffer) {
- win_set_buf(wp, buf, !enter || fconfig.noautocmd, err);
+ if (tp && buf != wp->w_buffer) {
+ const bool noautocmd = !enter || fconfig.noautocmd;
+ win_set_buf(wp, buf, noautocmd, err);
+ if (!noautocmd) {
+ tp = win_find_tabpage(wp);
+ }
+ // win_set_buf autocommands were blocked if we didn't enter, but we still want BufWinEnter.
+ if (noautocmd && !fconfig.noautocmd && wp->w_buffer == buf) {
+ const int result = switch_win_noblock(&switchwin, wp, tp, true);
+ assert(result == OK);
+ (void)result;
+ if (apply_autocmds(EVENT_BUFWINENTER, NULL, NULL, false, buf)) {
+ tp = win_find_tabpage(wp);
+ }
+ restore_win_noblock(&switchwin, true);
+ }
}
- if (!win_valid_any_tab(wp)) {
+ if (!tp) {
api_set_error(err, kErrorTypeException, "Window was closed immediately");
return 0;
}