diff options
author | Sean Dewar <seandewar@users.noreply.github.com> | 2022-01-06 13:48:37 +0000 |
---|---|---|
committer | Sean Dewar <seandewar@users.noreply.github.com> | 2022-02-03 15:02:57 +0000 |
commit | f326c9a77da3aef052ce6af0f851344f2479c844 (patch) | |
tree | cbfedb742e02d31852fed6c20a54fd78aaf289f0 | |
parent | f5c4c1d7684d9d39dd469e10322ce6a5df5c3281 (diff) | |
download | rneovim-f326c9a77da3aef052ce6af0f851344f2479c844.tar.gz rneovim-f326c9a77da3aef052ce6af0f851344f2479c844.tar.bz2 rneovim-f326c9a77da3aef052ce6af0f851344f2479c844.zip |
vim-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 vim/vim#9479)
https://github.com/vim/vim/commit/18f4740f043b353abe47b7a00131317052457686
{switch_to/restore}_win_for_buf is N/A (marked as such in v8.0.0860; currently
only used in Vim's if_py).
Add a modeline to test_execute_func.vim.
-rw-r--r-- | src/nvim/api/private/helpers.c | 10 | ||||
-rw-r--r-- | src/nvim/api/window.c | 9 | ||||
-rw-r--r-- | src/nvim/eval.c | 17 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 23 | ||||
-rw-r--r-- | src/nvim/move.c | 6 | ||||
-rw-r--r-- | src/nvim/testdir/test_execute_func.vim | 12 | ||||
-rw-r--r-- | src/nvim/window.c | 53 | ||||
-rw-r--r-- | src/nvim/window.h | 8 |
8 files changed, 79 insertions, 59 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 4ddd90f3c9..ddcfff0097 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -989,18 +989,16 @@ Object copy_object(Object obj) static void set_option_value_for(char *key, int numval, char *stringval, int opt_flags, int opt_type, void *from, Error *err) { - win_T *save_curwin = NULL; - tabpage_T *save_curtab = NULL; + switchwin_T switchwin; aco_save_T aco; try_start(); switch (opt_type) { case SREQ_WIN: - if (switch_win_noblock(&save_curwin, &save_curtab, (win_T *)from, - win_find_tabpage((win_T *)from), true) + if (switch_win_noblock(&switchwin, (win_T *)from, win_find_tabpage((win_T *)from), true) == FAIL) { - restore_win_noblock(save_curwin, save_curtab, true); + restore_win_noblock(&switchwin, true); if (try_end(err)) { return; } @@ -1010,7 +1008,7 @@ static void set_option_value_for(char *key, int numval, char *stringval, int opt return; } set_option_value_err(key, numval, stringval, opt_flags, err); - restore_win_noblock(save_curwin, save_curtab, true); + restore_win_noblock(&switchwin, true); break; case SREQ_BUF: aucmd_prepbuf(&aco, (buf_T *)from); diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 907306da7b..a762673fbf 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -455,17 +455,14 @@ Object nvim_win_call(Window window, LuaRef fun, Error *err) } tabpage_T *tabpage = win_find_tabpage(win); - win_T *save_curwin; - tabpage_T *save_curtab; - try_start(); Object res = OBJECT_INIT; - if (switch_win_noblock(&save_curwin, &save_curtab, win, tabpage, true) == - OK) { + switchwin_T switchwin; + if (switch_win_noblock(&switchwin, win, tabpage, true) == OK) { Array args = ARRAY_DICT_INIT; res = nlua_call_ref(fun, NULL, args, true, err); } - restore_win_noblock(save_curwin, save_curtab, true); + restore_win_noblock(&switchwin, true); try_end(err); return res; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b8e9f41551..5d9326eb24 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6963,10 +6963,9 @@ win_T *find_tabwin(typval_T *wvp, typval_T *tvp) /// @param off 1 for gettabwinvar() void getwinvar(typval_T *argvars, typval_T *rettv, int off) { - win_T *win, *oldcurwin; + win_T *win; dictitem_T *v; tabpage_T *tp = NULL; - tabpage_T *oldtabpage = NULL; bool done = false; if (off == 1) { @@ -6986,8 +6985,8 @@ void getwinvar(typval_T *argvars, typval_T *rettv, int off) // otherwise the window is not valid. Only do this when needed, // autocommands get blocked. bool need_switch_win = tp != curtab || win != curwin; - if (!need_switch_win - || switch_win(&oldcurwin, &oldtabpage, win, tp, true) == OK) { + switchwin_T switchwin; + if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) { if (*varname == '&') { if (varname[1] == NUL) { // get all window-local options in a dict @@ -7015,7 +7014,7 @@ void getwinvar(typval_T *argvars, typval_T *rettv, int off) if (need_switch_win) { // restore previous notion of curwin - restore_win(oldcurwin, oldtabpage, true); + restore_win(&switchwin, true); } } emsg_off--; @@ -7517,11 +7516,9 @@ void setwinvar(typval_T *argvars, typval_T *rettv, int off) typval_T *varp = &argvars[off + 2]; if (win != NULL && varname != NULL && varp != NULL) { - win_T *save_curwin; - tabpage_T *save_curtab; bool need_switch_win = tp != curtab || win != curwin; - if (!need_switch_win - || switch_win(&save_curwin, &save_curtab, win, tp, true) == OK) { + switchwin_T switchwin; + if (!need_switch_win || switch_win(&switchwin, win, tp, true) == OK) { if (*varname == '&') { long numval; bool error = false; @@ -7543,7 +7540,7 @@ void setwinvar(typval_T *argvars, typval_T *rettv, int off) } } if (need_switch_win) { - restore_win(save_curwin, save_curtab, true); + restore_win(&switchwin, true); } } } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 29619f62e9..3cfc00fea2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2176,20 +2176,18 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) { tabpage_T *tp; win_T *wp = win_id2wp_tp(argvars, &tp); - win_T *save_curwin; - tabpage_T *save_curtab; // Return an empty string if something fails. rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; if (wp != NULL && tp != NULL) { pos_T curpos = wp->w_cursor; - if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) == - OK) { + switchwin_T switchwin; + if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { check_cursor(); execute_common(argvars, rettv, fptr, 1); } - restore_win_noblock(save_curwin, save_curtab, true); + restore_win_noblock(&switchwin, true); // Update the status line if the cursor moved. if (win_valid(wp) && !equalpos(curpos, wp->w_cursor)) { @@ -4031,8 +4029,6 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - win_T *oldcurwin; - tabpage_T *oldtabpage; bool done = false; rettv->v_type = VAR_STRING; @@ -4046,7 +4042,8 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) win_T *const window = tp == curtab || tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin; - if (switch_win(&oldcurwin, &oldtabpage, window, tp, true) == OK) { + switchwin_T switchwin; + if (switch_win(&switchwin, window, tp, true) == OK) { // look up the variable // Let gettabvar({nr}, "") return the "t:" dictionary. const dictitem_T *const v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', @@ -4059,7 +4056,7 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) } // restore previous notion of curwin - restore_win(oldcurwin, oldtabpage, true); + restore_win(&switchwin, true); } if (!done && argvars[2].v_type != VAR_UNKNOWN) { @@ -5881,18 +5878,16 @@ static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (argvars[1].v_type != VAR_UNKNOWN) { tabpage_T *tp; - win_T *save_curwin; - tabpage_T *save_curtab; // use window specified in the second argument win_T *wp = win_id2wp_tp(&argvars[1], &tp); if (wp != NULL && tp != NULL) { - if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) - == OK) { + switchwin_T switchwin; + if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { check_cursor(); fp = var2fpos(&argvars[0], true, &fnum); } - restore_win_noblock(save_curwin, save_curtab, true); + restore_win_noblock(&switchwin, true); } } else { // use current window diff --git a/src/nvim/move.c b/src/nvim/move.c index 67ec19903f..27cc2b341c 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -346,10 +346,10 @@ void update_topline(win_T *wp) */ void update_topline_win(win_T *win) { - win_T *save_curwin; - switch_win(&save_curwin, NULL, win, NULL, true); + switchwin_T switchwin; + switch_win(&switchwin, win, NULL, true); update_topline(curwin); - restore_win(save_curwin, NULL, true); + restore_win(&switchwin, true); } /* diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim index 2cb6d73407..bb601e19ac 100644 --- a/src/nvim/testdir/test_execute_func.vim +++ b/src/nvim/testdir/test_execute_func.vim @@ -147,3 +147,15 @@ func Test_win_execute_other_tab() tabclose 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 + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/window.c b/src/nvim/window.c index 8e44fd5014..6996a93928 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -577,18 +577,19 @@ static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, int64_t Pren void win_set_buf(Window window, Buffer buffer, bool noautocmd, Error *err) { - win_T *win = find_window_by_handle(window, err), *save_curwin = curwin; + win_T *win = find_window_by_handle(window, err); buf_T *buf = find_buffer_by_handle(buffer, err); - tabpage_T *tab = win_find_tabpage(win), *save_curtab = curtab; + tabpage_T *tab = win_find_tabpage(win); if (!win || !buf) { return; } - if (noautocmd) { block_autocmds(); } - if (switch_win_noblock(&save_curwin, &save_curtab, win, tab, false) == FAIL) { + + switchwin_T switchwin; + if (switch_win_noblock(&switchwin, win, tab, false) == FAIL) { api_set_error(err, kErrorTypeException, "Failed to switch to window %d", @@ -608,7 +609,7 @@ void win_set_buf(Window window, Buffer buffer, bool noautocmd, Error *err) // So do it now. validate_cursor(); - restore_win_noblock(save_curwin, save_curtab, false); + restore_win_noblock(&switchwin, false); if (noautocmd) { unblock_autocmds(); } @@ -6631,20 +6632,27 @@ static win_T *get_snapshot_focus(int idx) /// triggered, another tabpage access is limited. /// /// @return FAIL if switching to "win" failed. -int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, - bool no_display) +int switch_win(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool 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); } // As switch_win() but without blocking autocommands. -int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, - bool no_display) +int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool no_display) { - *save_curwin = curwin; + memset(switchwin, 0, sizeof(switchwin_T)); + 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; curtab->tp_lastwin = lastwin; @@ -6666,28 +6674,33 @@ int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, // Restore current tabpage and window saved by switch_win(), if still valid. // When "no_display" is true the display won't be affected, no redraw is // triggered. -void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display) +void restore_win(switchwin_T *switchwin, bool no_display) { - restore_win_noblock(save_curwin, save_curtab, no_display); + restore_win_noblock(switchwin, no_display); unblock_autocmds(); } // As restore_win() but without unblocking autocommands. -void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab, bool no_display) +void restore_win_noblock(switchwin_T *switchwin, bool 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 = save_curtab; + curtab = switchwin->sw_curtab; firstwin = curtab->tp_firstwin; lastwin = curtab->tp_lastwin; } else { - goto_tabpage_tp(save_curtab, false, false); + goto_tabpage_tp(switchwin->sw_curtab, false, false); } } - if (win_valid(save_curwin)) { - curwin = save_curwin; + + if (!switchwin->sw_same_win) { + VIsual_active = switchwin->sw_visual_active; + } + + if (win_valid(switchwin->sw_curwin)) { + curwin = switchwin->sw_curwin; curbuf = curwin->w_buffer; } // If called by win_execute() and executing the command changed the diff --git a/src/nvim/window.h b/src/nvim/window.h index 7e465a9f08..925cc68b60 100644 --- a/src/nvim/window.h +++ b/src/nvim/window.h @@ -32,6 +32,14 @@ #define MIN_COLUMNS 12 // minimal columns for screen #define MIN_LINES 2 // minimal lines for screen +/// Structure used by switch_win() to pass values to restore_win() +typedef struct { + win_T *sw_curwin; + tabpage_T *sw_curtab; + bool sw_same_win; ///< VIsual_active was not reset + bool sw_visual_active; +} switchwin_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "window.h.generated.h" #endif |