# HG changeset patch # User Bram Moolenaar # Date 1641475805 -3600 # Node ID aa613a3084b9a4c3fa295a232c9d5645a338b2cb # Parent b96cf64806247e2ad1ab4b8c4663d92f2a1f3336 patch 8.2.4018: ml_get error when win_execute redraws with Visual selection Commit: https://github.com/vim/vim/commit/18f4740f043b353abe47b7a00131317052457686 Author: Bram Moolenaar Date: Thu Jan 6 13:24:51 2022 +0000 patch 8.2.4018: ml_get error when win_execute redraws with Visual selection Problem: ml_get error when win_execute redraws with Visual selection. Solution: Disable Visual area temporarily. (closes https://github.com/vim/vim/issues/9479) diff --git a/src/evalbuffer.c b/src/evalbuffer.c --- a/src/evalbuffer.c +++ b/src/evalbuffer.c @@ -930,31 +930,29 @@ find_win_for_buf( */ void switch_to_win_for_buf( - buf_T *buf, - win_T **save_curwinp, - tabpage_T **save_curtabp, - bufref_T *save_curbuf) + buf_T *buf, + switchwin_T *switchwin, + bufref_T *save_curbuf) { win_T *wp; tabpage_T *tp; if (find_win_for_buf(buf, &wp, &tp) == FAIL) switch_buffer(save_curbuf, buf); - else if (switch_win(save_curwinp, save_curtabp, wp, tp, TRUE) == FAIL) + else if (switch_win(switchwin, wp, tp, TRUE) == FAIL) { - restore_win(*save_curwinp, *save_curtabp, TRUE); + restore_win(switchwin, TRUE); switch_buffer(save_curbuf, buf); } } void restore_win_for_buf( - win_T *save_curwin, - tabpage_T *save_curtab, - bufref_T *save_curbuf) + switchwin_T *switchwin, + bufref_T *save_curbuf) { if (save_curbuf->br_buf == NULL) - restore_win(save_curwin, save_curtab, TRUE); + restore_win(switchwin, TRUE); else restore_buffer(save_curbuf); } diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6864,8 +6864,7 @@ f_line(typval_T *argvars, typval_T *rett int id; tabpage_T *tp; win_T *wp; - win_T *save_curwin; - tabpage_T *save_curtab; + switchwin_T switchwin; if (in_vim9script() && (check_for_string_arg(argvars, 0) == FAIL @@ -6879,13 +6878,12 @@ f_line(typval_T *argvars, typval_T *rett wp = win_id2wp_tp(id, &tp); if (wp != NULL && tp != NULL) { - if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) - == OK) + if (switch_win_noblock(&switchwin, wp, tp, TRUE) == OK) { check_cursor(); fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE); } - restore_win_noblock(save_curwin, save_curtab, TRUE); + restore_win_noblock(&switchwin, TRUE); } } else diff --git a/src/evalvars.c b/src/evalvars.c --- a/src/evalvars.c +++ b/src/evalvars.c @@ -3769,8 +3769,7 @@ getwinvar( dictitem_T *v; tabpage_T *tp = NULL; int done = FALSE; - win_T *oldcurwin; - tabpage_T *oldtabpage; + switchwin_T switchwin; int need_switch_win; if (off == 1) @@ -3791,7 +3790,7 @@ getwinvar( // autocommands get blocked. need_switch_win = !(tp == curtab && win == curwin); if (!need_switch_win - || switch_win(&oldcurwin, &oldtabpage, win, tp, TRUE) == OK) + || switch_win(&switchwin, win, tp, TRUE) == OK) { if (*varname == '&') { @@ -3826,7 +3825,7 @@ getwinvar( if (need_switch_win) // restore previous notion of curwin - restore_win(oldcurwin, oldtabpage, TRUE); + restore_win(&switchwin, TRUE); } if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) @@ -3869,8 +3868,7 @@ set_option_from_tv(char_u *varname, typv setwinvar(typval_T *argvars, int off) { win_T *win; - win_T *save_curwin; - tabpage_T *save_curtab; + switchwin_T switchwin; int need_switch_win; char_u *varname, *winvarname; typval_T *varp; @@ -3891,7 +3889,7 @@ setwinvar(typval_T *argvars, int off) { need_switch_win = !(tp == curtab && win == curwin); if (!need_switch_win - || switch_win(&save_curwin, &save_curtab, win, tp, TRUE) == OK) + || switch_win(&switchwin, win, tp, TRUE) == OK) { if (*varname == '&') set_option_from_tv(varname + 1, varp); @@ -3908,7 +3906,7 @@ setwinvar(typval_T *argvars, int off) } } if (need_switch_win) - restore_win(save_curwin, save_curtab, TRUE); + restore_win(&switchwin, TRUE); } } @@ -4165,8 +4163,8 @@ get_clear_redir_ga(void) void f_gettabvar(typval_T *argvars, typval_T *rettv) { - win_T *oldcurwin; - tabpage_T *tp, *oldtabpage; + switchwin_T switchwin; + tabpage_T *tp; dictitem_T *v; char_u *varname; int done = FALSE; @@ -4185,7 +4183,7 @@ f_gettabvar(typval_T *argvars, typval_T { // Set tp to be our tabpage, temporarily. Also set the window to the // first window in the tabpage, otherwise the window is not valid. - if (switch_win(&oldcurwin, &oldtabpage, + if (switch_win(&switchwin, tp == curtab || tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin, tp, TRUE) == OK) { @@ -4200,7 +4198,7 @@ f_gettabvar(typval_T *argvars, typval_T } // restore previous notion of curwin - restore_win(oldcurwin, oldtabpage, TRUE); + restore_win(&switchwin, TRUE); } if (!done && argvars[2].v_type != VAR_UNKNOWN) diff --git a/src/evalwindow.c b/src/evalwindow.c --- a/src/evalwindow.c +++ b/src/evalwindow.c @@ -689,8 +689,7 @@ f_win_execute(typval_T *argvars, typval_ int id; tabpage_T *tp; win_T *wp; - win_T *save_curwin; - tabpage_T *save_curtab; + switchwin_T switchwin; // Return an empty string if something fails. rettv->v_type = VAR_STRING; @@ -727,12 +726,12 @@ f_win_execute(typval_T *argvars, typval_ } #endif - if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK) + if (switch_win_noblock(&switchwin, wp, tp, TRUE) == OK) { check_cursor(); execute_common(argvars, rettv, 1); } - restore_win_noblock(save_curwin, save_curtab, TRUE); + restore_win_noblock(&switchwin, TRUE); #ifdef FEAT_AUTOCHDIR if (apply_acd) do_autochdir(); @@ -1247,14 +1246,13 @@ f_winwidth(typval_T *argvars, typval_T * */ int switch_win( - win_T **save_curwin, - tabpage_T **save_curtab, - win_T *win, - tabpage_T *tp, - int no_display) + switchwin_T *switchwin, + win_T *win, + tabpage_T *tp, + int no_display) { block_autocmds(); - return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display); + return switch_win_noblock(switchwin, win, tp, no_display); } /* @@ -1262,16 +1260,25 @@ switch_win( */ int switch_win_noblock( - win_T **save_curwin, - tabpage_T **save_curtab, - win_T *win, - tabpage_T *tp, - int no_display) + switchwin_T *switchwin, + win_T *win, + tabpage_T *tp, + int no_display) { - *save_curwin = curwin; + CLEAR_POINTER(switchwin); + switchwin->sw_curwin = curwin; + if (win == curwin) + switchwin->sw_same_win = TRUE; + else + { + // Disable Visual selection, because redrawing may fail. + switchwin->sw_visual_active = VIsual_active; + VIsual_active = FALSE; + } + if (tp != NULL) { - *save_curtab = curtab; + switchwin->sw_curtab = curtab; if (no_display) { curtab->tp_firstwin = firstwin; @@ -1299,11 +1306,10 @@ switch_win_noblock( */ void restore_win( - win_T *save_curwin, - tabpage_T *save_curtab, - int no_display) + switchwin_T *switchwin, + int no_display) { - restore_win_noblock(save_curwin, save_curtab, no_display); + restore_win_noblock(switchwin, no_display); unblock_autocmds(); } @@ -1312,28 +1318,31 @@ restore_win( */ void restore_win_noblock( - win_T *save_curwin, - tabpage_T *save_curtab, - int no_display) + switchwin_T *switchwin, + int no_display) { - if (save_curtab != NULL && valid_tabpage(save_curtab)) + if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) { if (no_display) { curtab->tp_firstwin = firstwin; curtab->tp_lastwin = lastwin; curtab->tp_topframe = topframe; - curtab = save_curtab; + curtab = switchwin->sw_curtab; firstwin = curtab->tp_firstwin; lastwin = curtab->tp_lastwin; topframe = curtab->tp_topframe; } else - goto_tabpage_tp(save_curtab, FALSE, FALSE); + goto_tabpage_tp(switchwin->sw_curtab, FALSE, FALSE); } - if (win_valid(save_curwin)) + + if (!switchwin->sw_same_win) + VIsual_active = switchwin->sw_visual_active; + + if (win_valid(switchwin->sw_curwin)) { - curwin = save_curwin; + curwin = switchwin->sw_curwin; curbuf = curwin->w_buffer; } # ifdef FEAT_PROP_POPUP diff --git a/src/if_py_both.h b/src/if_py_both.h --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -3529,8 +3529,7 @@ set_option_value_for( int opt_type, void *from) { - win_T *save_curwin = NULL; - tabpage_T *save_curtab = NULL; + switchwin_T switchwin; bufref_T save_curbuf; int set_ret = 0; @@ -3538,17 +3537,17 @@ set_option_value_for( switch (opt_type) { case SREQ_WIN: - if (switch_win(&save_curwin, &save_curtab, (win_T *)from, + if (switch_win(&switchwin, (win_T *)from, win_find_tabpage((win_T *)from), FALSE) == FAIL) { - restore_win(save_curwin, save_curtab, TRUE); + restore_win(&switchwin, TRUE); if (VimTryEnd()) return -1; PyErr_SET_VIM(N_("problem while switching windows")); return -1; } set_ret = set_option_value_err(key, numval, stringval, opt_flags); - restore_win(save_curwin, save_curtab, TRUE); + restore_win(&switchwin, TRUE); break; case SREQ_BUF: switch_buffer(&save_curbuf, (buf_T *)from); @@ -4410,8 +4409,7 @@ py_fix_cursor(linenr_T lo, linenr_T hi, SetBufferLine(buf_T *buf, PyInt n, PyObject *line, PyInt *len_change) { bufref_T save_curbuf = {NULL, 0, 0}; - win_T *save_curwin = NULL; - tabpage_T *save_curtab = NULL; + switchwin_T switchwin; // First of all, we check the type of the supplied Python object. // There are three cases: @@ -4421,7 +4419,8 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj if (line == Py_None || line == NULL) { PyErr_Clear(); - switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf); + switchwin.sw_curwin = NULL; + switch_to_win_for_buf(buf, &switchwin, &save_curbuf); VimTryStart(); @@ -4431,7 +4430,7 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj RAISE_DELETE_LINE_FAIL; else { - if (buf == curbuf && (save_curwin != NULL + if (buf == curbuf && (switchwin.sw_curwin != NULL || save_curbuf.br_buf == NULL)) // Using an existing window for the buffer, adjust the cursor // position. @@ -4442,7 +4441,7 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj deleted_lines_mark((linenr_T)n, 1L); } - restore_win_for_buf(save_curwin, save_curtab, &save_curbuf); + restore_win_for_buf(&switchwin, &save_curbuf); if (VimTryEnd()) return FAIL; @@ -4463,7 +4462,7 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj // We do not need to free "save" if ml_replace() consumes it. PyErr_Clear(); - switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf); + switch_to_win_for_buf(buf, &switchwin, &save_curbuf); if (u_savesub((linenr_T)n) == FAIL) { @@ -4478,7 +4477,7 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj else changed_bytes((linenr_T)n, 0); - restore_win_for_buf(save_curwin, save_curtab, &save_curbuf); + restore_win_for_buf(&switchwin, &save_curbuf); // Check that the cursor is not beyond the end of the line now. if (buf == curbuf) @@ -4517,8 +4516,7 @@ SetBufferLineList( PyInt *len_change) { bufref_T save_curbuf = {NULL, 0, 0}; - win_T *save_curwin = NULL; - tabpage_T *save_curtab = NULL; + switchwin_T switchwin; // First of all, we check the type of the supplied Python object. // There are three cases: @@ -4532,7 +4530,8 @@ SetBufferLineList( PyErr_Clear(); VimTryStart(); - switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf); + switchwin.sw_curwin = NULL; + switch_to_win_for_buf(buf, &switchwin, &save_curbuf); if (u_savedel((linenr_T)lo, (long)n) == FAIL) RAISE_UNDO_FAIL; @@ -4546,7 +4545,7 @@ SetBufferLineList( break; } } - if (buf == curbuf && (save_curwin != NULL + if (buf == curbuf && (switchwin.sw_curwin != NULL || save_curbuf.br_buf == NULL)) // Using an existing window for the buffer, adjust the cursor // position. @@ -4557,7 +4556,7 @@ SetBufferLineList( deleted_lines_mark((linenr_T)lo, (long)i); } - restore_win_for_buf(save_curwin, save_curtab, &save_curbuf); + restore_win_for_buf(&switchwin, &save_curbuf); if (VimTryEnd()) return FAIL; @@ -4605,7 +4604,8 @@ SetBufferLineList( PyErr_Clear(); // START of region without "return". Must call restore_buffer()! - switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf); + switchwin.sw_curwin = NULL; + switch_to_win_for_buf(buf, &switchwin, &save_curbuf); if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL) RAISE_UNDO_FAIL; @@ -4680,14 +4680,14 @@ SetBufferLineList( (long)MAXLNUM, (long)extra); changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra); - if (buf == curbuf && (save_curwin != NULL + if (buf == curbuf && (switchwin.sw_curwin != NULL || save_curbuf.br_buf == NULL)) // Using an existing window for the buffer, adjust the cursor // position. py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)extra); // END of region without "return". - restore_win_for_buf(save_curwin, save_curtab, &save_curbuf); + restore_win_for_buf(&switchwin, &save_curbuf); if (VimTryEnd()) return FAIL; @@ -4717,8 +4717,7 @@ SetBufferLineList( InsertBufferLines(buf_T *buf, PyInt n, PyObject *lines, PyInt *len_change) { bufref_T save_curbuf = {NULL, 0, 0}; - win_T *save_curwin = NULL; - tabpage_T *save_curtab = NULL; + switchwin_T switchwin; // First of all, we check the type of the supplied Python object. // It must be a string or a list, or the call is in error. @@ -4731,7 +4730,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P PyErr_Clear(); VimTryStart(); - switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf); + switch_to_win_for_buf(buf, &switchwin, &save_curbuf); if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) RAISE_UNDO_FAIL; @@ -4743,7 +4742,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P appended_lines_mark((linenr_T)n, 1L); vim_free(str); - restore_win_for_buf(save_curwin, save_curtab, &save_curbuf); + restore_win_for_buf(&switchwin, &save_curbuf); update_screen(VALID); if (VimTryEnd()) @@ -4783,7 +4782,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P PyErr_Clear(); VimTryStart(); - switch_to_win_for_buf(buf, &save_curwin, &save_curtab, &save_curbuf); + switch_to_win_for_buf(buf, &switchwin, &save_curbuf); if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) RAISE_UNDO_FAIL; @@ -4813,7 +4812,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P // Free the array of lines. All of its contents have now // been freed. PyMem_Free(array); - restore_win_for_buf(save_curwin, save_curtab, &save_curbuf); + restore_win_for_buf(&switchwin, &save_curbuf); update_screen(VALID); diff --git a/src/proto/evalbuffer.pro b/src/proto/evalbuffer.pro --- a/src/proto/evalbuffer.pro +++ b/src/proto/evalbuffer.pro @@ -21,6 +21,6 @@ void f_setbufline(typval_T *argvars, typ void f_setline(typval_T *argvars, typval_T *rettv); void switch_buffer(bufref_T *save_curbuf, buf_T *buf); void restore_buffer(bufref_T *save_curbuf); -void switch_to_win_for_buf(buf_T *buf, win_T **save_curwinp, tabpage_T **save_curtabp, bufref_T *save_curbuf); -void restore_win_for_buf(win_T *save_curwin, tabpage_T *save_curtab, bufref_T *save_curbuf); +void switch_to_win_for_buf(buf_T *buf, switchwin_T *switchwin, bufref_T *save_curbuf); +void restore_win_for_buf(switchwin_T *switchwin, bufref_T *save_curbuf); /* vim: set ft=c : */ diff --git a/src/proto/evalwindow.pro b/src/proto/evalwindow.pro --- a/src/proto/evalwindow.pro +++ b/src/proto/evalwindow.pro @@ -32,8 +32,8 @@ void f_winrestcmd(typval_T *argvars, typ void f_winrestview(typval_T *argvars, typval_T *rettv); void f_winsaveview(typval_T *argvars, typval_T *rettv); void f_winwidth(typval_T *argvars, typval_T *rettv); -int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, int no_display); -int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, int no_display); -void restore_win(win_T *save_curwin, tabpage_T *save_curtab, int no_display); -void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab, int no_display); +int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, int no_display); +int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, int no_display); +void restore_win(switchwin_T *switchwin, int no_display); +void restore_win_noblock(switchwin_T *switchwin, int no_display); /* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -4507,3 +4507,10 @@ typedef enum { FILTERMAP_MAPNEW } filtermap_T; +// Structure used by switch_win() to pass values to restore_win() +typedef struct { + win_T *sw_curwin; + tabpage_T *sw_curtab; + int sw_same_win; // VIsual_active was not reset + int sw_visual_active; +} switchwin_T; diff --git a/src/testdir/test_execute_func.vim b/src/testdir/test_execute_func.vim --- a/src/testdir/test_execute_func.vim +++ b/src/testdir/test_execute_func.vim @@ -149,6 +149,16 @@ func Test_win_execute_other_tab() unlet xyz endfunc +func Test_win_execute_visual_redraw() + call setline(1, ['a', 'b', 'c']) + new + wincmd p + call feedkeys("G\", 'txn') + call win_execute(winnr('#')->win_getid(), 'redraw') + bwipe! + bwipe! +endfunc + func Test_win_execute_on_startup() CheckRunVimInTerminal diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4018, +/**/ 4017, /**/ 4016,