fix(api): patch some cmdwin/textlock holes

Problem: there are new ways to escape textlock or break the cmdwin in
nvim_win_set_config and nvim_tabpage_set_win.

Solution: fix them. Use win_goto to check it in nvim_tabpage_set_win and use the
try_start/end pattern like with similar functions such as nvim_set_current_win
(which uses the existing msg_list, if set).

Careful not to use `wp->handle` when printing the window ID in the error message
for nvim_tabpage_set_win, as win_goto autocommands may have freed the window.

On a related note, I have a feeling some API functions ought to be checking
curbuf_locked...
This commit is contained in:
Sean Dewar
2024-02-27 13:25:44 +00:00
parent d942c2b943
commit e7c262f555
5 changed files with 109 additions and 7 deletions

View File

@@ -146,7 +146,11 @@ void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err)
}
if (tp == curtab) {
win_enter(wp, true);
try_start();
win_goto(wp);
if (!try_end(err) && curwin != wp) {
api_set_error(err, kErrorTypeException, "Failed to switch to window %d", win);
}
} else if (tp->tp_curwin != wp) {
tp->tp_prevwin = tp->tp_curwin;
tp->tp_curwin = wp;

View File

@@ -451,6 +451,12 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err)
if (!check_split_disallowed_err(win, err)) {
return; // error already set
}
// Can't move the cmdwin or its old curwin to a different tabpage.
if ((win == cmdwin_win || win == cmdwin_old_curwin) && parent != NULL
&& win_find_tabpage(parent) != win_tp) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return;
}
bool to_split_ok = false;
// If we are moving curwin to another tabpage, switch windows *before* we remove it from the

View File

@@ -55,6 +55,19 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err)
api_set_error(err, kErrorTypeException,
"Cannot change window from different tabpage into float");
return NULL;
} else if (cmdwin_win != NULL && !cmdwin_win->w_floating) {
// cmdwin can't become the only non-float. Check for others.
bool other_nonfloat = false;
for (win_T *wp2 = firstwin; wp2 != NULL && !wp2->w_floating; wp2 = wp2->w_next) {
if (wp2 != wp && wp2 != cmdwin_win) {
other_nonfloat = true;
break;
}
}
if (!other_nonfloat) {
api_set_error(err, kErrorTypeException, "%s", e_cmdwin);
return NULL;
}
}
int dir;
winframe_remove(wp, &dir, NULL, NULL);