]> granicus.if.org Git - vim/commitdiff
patch 8.2.4018: ml_get error when win_execute redraws with Visual selection v8.2.4018
authorBram Moolenaar <Bram@vim.org>
Thu, 6 Jan 2022 13:24:51 +0000 (13:24 +0000)
committerBram Moolenaar <Bram@vim.org>
Thu, 6 Jan 2022 13:24:51 +0000 (13:24 +0000)
Problem:    ml_get error when win_execute redraws with Visual selection.
Solution:   Disable Visual area temporarily. (closes #9479)

src/evalbuffer.c
src/evalfunc.c
src/evalvars.c
src/evalwindow.c
src/if_py_both.h
src/proto/evalbuffer.pro
src/proto/evalwindow.pro
src/structs.h
src/testdir/test_execute_func.vim
src/version.c

index 58834785aa7eff6649cb264859e1a132d0542c46..b6bd67bce5d335327ae05f3474ee4c4e725eda35 100644 (file)
@@ -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);
 }
index 27f8d46667f822b16b1ec45de907a1b8f168d8de..fc2fd07064412c4d874057cf1781254e2ca0ecf9 100644 (file)
@@ -6864,8 +6864,7 @@ f_line(typval_T *argvars, typval_T *rettv)
     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 *rettv)
        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
index 11770aa532ebb2eba82aa5c2d68c3d607118c857..055d49f5efd413ba7b8bd8732eeaedf7554aaed8 100644 (file)
@@ -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, typval_T *varp)
 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 *rettv)
     {
        // 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 *rettv)
        }
 
        // restore previous notion of curwin
-       restore_win(oldcurwin, oldtabpage, TRUE);
+       restore_win(&switchwin, TRUE);
     }
 
     if (!done && argvars[2].v_type != VAR_UNKNOWN)
index 0fc62d1cc270b3aed28108d07f84e258f4789a6a..d29f3e4baa3fafdf0bb50ef8358c5f958e4d3ab7 100644 (file)
@@ -689,8 +689,7 @@ f_win_execute(typval_T *argvars, typval_T *rettv)
     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_T *rettv)
        }
 #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 *rettv)
  */
     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
index 128d12e87cfbbf4e209c1bd75c4fdeea7e0b49c4..5364f6b2f5a81816280dcf1df2a4fcf6a792d891 100644 (file)
@@ -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, linenr_T extra)
 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, PyObject *line, PyInt *len_change)
     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, PyObject *line, PyInt *len_change)
            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, PyObject *line, PyInt *len_change)
                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, PyObject *line, PyInt *len_change)
 
        // 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, PyObject *line, PyInt *len_change)
        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, PyObject *lines, PyInt *len_change)
 
        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, PyObject *lines, PyInt *len_change)
            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, PyObject *lines, PyInt *len_change)
 
        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, PyObject *lines, PyInt *len_change)
        // 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);
 
index b59c5f5e9b1d1dfc3561e6e41bce67a58d1a5a2a..41616e705ce57a3ac1a4b390aba570cd14e8652e 100644 (file)
@@ -21,6 +21,6 @@ void f_setbufline(typval_T *argvars, typval_T *rettv);
 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 : */
index 4eb1ced8bc8df8b26890d526aa2f9fd87520f0f8..eba167678a9e2123e4af88d607235433b525a59f 100644 (file)
@@ -32,8 +32,8 @@ void f_winrestcmd(typval_T *argvars, typval_T *rettv);
 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 : */
index 2da16bf6eefbda025b14bec2482cbde83d48045f..1a764e170cd34b0cd2d7a6ccfb5d1c0963a1dc7e 100644 (file)
@@ -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;
index 9146504e5e27611212f89c6d8c4b24a341ebc07d..0ca31cb6c6f9df10edc9451a5b9549f3cf315689 100644 (file)
@@ -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\<C-V>", 'txn')
+  call win_execute(winnr('#')->win_getid(), 'redraw')
+  bwipe!
+  bwipe!
+endfunc
+
 func Test_win_execute_on_startup()
   CheckRunVimInTerminal
 
index 5776f3df18fdf24547f64d69d09ea4c540c8caaa..20def0bb80674838cd6e49361f9986b5f7ad25b5 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4018,
 /**/
     4017,
 /**/