# HG changeset patch # User Bram Moolenaar # Date 1368799437 -7200 # Node ID 7eafa576528e6921f337da5c1e3e2d0a9617993a # Parent f1ecf16fe9fc3c7ea0401147c8d0383cca653a7b updated for version 7.3.963 Problem: Setting curbuf without curwin causes trouble. Solution: Add switch_buffer() and restore_buffer(). Block autocommands to avoid trouble. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -11894,7 +11894,7 @@ getwinvar(argvars, rettv, off) win_T *win, *oldcurwin; char_u *varname; dictitem_T *v; - tabpage_T *tp; + tabpage_T *tp, *oldtabpage; int done = FALSE; #ifdef FEAT_WINDOWS @@ -11912,11 +11912,9 @@ getwinvar(argvars, rettv, off) if (win != NULL && varname != NULL) { - /* Set curwin to be our win, temporarily. Also set curbuf, so - * that we can get buffer-local options. */ - oldcurwin = curwin; - curwin = win; - curbuf = win->w_buffer; + /* Set curwin to be our win, temporarily. Also set the tabpage, + * otherwise the window is not valid. */ + switch_win(&oldcurwin, &oldtabpage, win, tp); if (*varname == '&') /* window-local-option */ { @@ -11936,8 +11934,7 @@ getwinvar(argvars, rettv, off) } /* restore previous notion of curwin */ - curwin = oldcurwin; - curbuf = curwin->w_buffer; + restore_win(oldcurwin, oldtabpage); } if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) @@ -16641,44 +16638,6 @@ f_setwinvar(argvars, rettv) setwinvar(argvars, rettv, 0); } - int -switch_win(save_curwin, save_curtab, win, tp) - win_T **save_curwin; - tabpage_T **save_curtab; - win_T *win; - tabpage_T *tp; -{ -#ifdef FEAT_WINDOWS - /* set curwin to be our win, temporarily */ - *save_curwin = curwin; - *save_curtab = curtab; - goto_tabpage_tp(tp, FALSE, FALSE); - if (!win_valid(win)) - return FAIL; - curwin = win; - curbuf = curwin->w_buffer; -#endif - return OK; -} - - void -restore_win(save_curwin, save_curtab) - win_T *save_curwin; - tabpage_T *save_curtab; -{ -#ifdef FEAT_WINDOWS - /* Restore current tabpage and window, if still valid (autocommands can - * make them invalid). */ - if (valid_tabpage(save_curtab)) - goto_tabpage_tp(save_curtab, FALSE, FALSE); - if (win_valid(save_curwin)) - { - curwin = save_curwin; - curbuf = curwin->w_buffer; - } -#endif -} - /* * "setwinvar()" and "settabwinvar()" functions */ 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 @@ -1413,14 +1413,14 @@ set_option_value_for(key, numval, string { win_T *save_curwin; tabpage_T *save_curtab; - aco_save_T aco; + buf_T *save_curbuf; int r = 0; switch (opt_type) { case SREQ_WIN: - if (switch_win(&save_curwin, &save_curtab, (win_T *) from, curtab) - == FAIL) + if (switch_win(&save_curwin, &save_curtab, (win_T *)from, + win_find_tabpage((win_T *)from)) == FAIL) { PyErr_SetVim("Problem while switching windows."); return -1; @@ -1429,9 +1429,9 @@ set_option_value_for(key, numval, string restore_win(save_curwin, save_curtab); break; case SREQ_BUF: - aucmd_prepbuf(&aco, (buf_T *) from); + switch_buffer(&save_curbuf, (buf_T *)from); set_option_value(key, numval, stringval, opt_flags); - aucmd_restbuf(&aco); + restore_buffer(save_curbuf); break; case SREQ_GLOBAL: set_option_value(key, numval, stringval, opt_flags); @@ -2240,10 +2240,10 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj */ if (line == Py_None || line == NULL) { - buf_T *savebuf = curbuf; + buf_T *savebuf; PyErr_Clear(); - curbuf = buf; + switch_buffer(&savebuf, buf); if (u_savedel((linenr_T)n, 1L) == FAIL) PyErr_SetVim(_("cannot save undo information")); @@ -2251,12 +2251,12 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj PyErr_SetVim(_("cannot delete line")); else { - if (buf == curwin->w_buffer) + if (buf == savebuf) py_fix_cursor((linenr_T)n, (linenr_T)n + 1, (linenr_T)-1); deleted_lines_mark((linenr_T)n, 1L); } - curbuf = savebuf; + restore_buffer(savebuf); if (PyErr_Occurred() || VimErrorCheck()) return FAIL; @@ -2269,14 +2269,14 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj else if (PyString_Check(line)) { char *save = StringToLine(line); - buf_T *savebuf = curbuf; + buf_T *savebuf; if (save == NULL) return FAIL; /* We do not need to free "save" if ml_replace() consumes it. */ PyErr_Clear(); - curbuf = buf; + switch_buffer(&savebuf, buf); if (u_savesub((linenr_T)n) == FAIL) { @@ -2291,10 +2291,10 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj else changed_bytes((linenr_T)n, 0); - curbuf = savebuf; + restore_buffer(savebuf); /* Check that the cursor is not beyond the end of the line now. */ - if (buf == curwin->w_buffer) + if (buf == savebuf) check_cursor_col(); if (PyErr_Occurred() || VimErrorCheck()) @@ -2333,10 +2333,10 @@ SetBufferLineList(buf_T *buf, PyInt lo, { PyInt i; PyInt n = (int)(hi - lo); - buf_T *savebuf = curbuf; + buf_T *savebuf; PyErr_Clear(); - curbuf = buf; + switch_buffer(&savebuf, buf); if (u_savedel((linenr_T)lo, (long)n) == FAIL) PyErr_SetVim(_("cannot save undo information")); @@ -2350,12 +2350,12 @@ SetBufferLineList(buf_T *buf, PyInt lo, break; } } - if (buf == curwin->w_buffer) + if (buf == savebuf) py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)-n); deleted_lines_mark((linenr_T)lo, (long)i); } - curbuf = savebuf; + restore_buffer(savebuf); if (PyErr_Occurred() || VimErrorCheck()) return FAIL; @@ -2400,10 +2400,10 @@ SetBufferLineList(buf_T *buf, PyInt lo, } } - savebuf = curbuf; - PyErr_Clear(); - curbuf = buf; + + // START of region without "return". Must call restore_buffer()! + switch_buffer(&savebuf, buf); if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL) PyErr_SetVim(_("cannot save undo information")); @@ -2480,10 +2480,11 @@ SetBufferLineList(buf_T *buf, PyInt lo, (long)MAXLNUM, (long)extra); changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra); - if (buf == curwin->w_buffer) + if (buf == savebuf) py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)extra); - curbuf = savebuf; + // END of region without "return". + restore_buffer(savebuf); if (PyErr_Occurred() || VimErrorCheck()) return FAIL; @@ -2522,10 +2523,8 @@ InsertBufferLines(buf_T *buf, PyInt n, P if (str == NULL) return FAIL; - savebuf = curbuf; - PyErr_Clear(); - curbuf = buf; + switch_buffer(&savebuf, buf); if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL) PyErr_SetVim(_("cannot save undo information")); @@ -2535,7 +2534,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P appended_lines_mark((linenr_T)n, 1L); vim_free(str); - curbuf = savebuf; + restore_buffer(savebuf); update_screen(VALID); if (PyErr_Occurred() || VimErrorCheck()) @@ -2574,10 +2573,8 @@ InsertBufferLines(buf_T *buf, PyInt n, P } } - savebuf = curbuf; - PyErr_Clear(); - curbuf = buf; + switch_buffer(&savebuf, buf); if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) PyErr_SetVim(_("cannot save undo information")); @@ -2607,7 +2604,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P */ vim_free(array); - curbuf = savebuf; + restore_buffer(savebuf); update_screen(VALID); if (PyErr_Occurred() || VimErrorCheck()) @@ -3023,7 +3020,7 @@ BufferMark(PyObject *self, PyObject *arg pos_T *posp; char *pmark; char mark; - buf_T *curbuf_save; + buf_T *savebuf; if (CheckBuffer((BufferObject *)(self))) return NULL; @@ -3032,10 +3029,9 @@ BufferMark(PyObject *self, PyObject *arg return NULL; mark = *pmark; - curbuf_save = curbuf; - curbuf = ((BufferObject *)(self))->buf; + switch_buffer(&savebuf, ((BufferObject *)(self))->buf); posp = getmark(mark, FALSE); - curbuf = curbuf_save; + restore_buffer(savebuf); if (posp == NULL) { diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -33,6 +33,8 @@ void prof_child_enter __ARGS((proftime_T void prof_child_exit __ARGS((proftime_T *tm)); int eval_foldexpr __ARGS((char_u *arg, int *cp)); void ex_let __ARGS((exarg_T *eap)); +void list_add_watch __ARGS((list_T *l, listwatch_T *lw)); +void list_rem_watch __ARGS((list_T *l, listwatch_T *lwrem)); void *eval_for_line __ARGS((char_u *arg, int *errp, char_u **nextcmdp, int skip)); int next_for_item __ARGS((void *fi_void, char_u *arg)); void free_for_info __ARGS((void *fi_void)); @@ -125,8 +127,4 @@ void last_set_msg __ARGS((scid_T scriptI void ex_oldfiles __ARGS((exarg_T *eap)); int modify_fname __ARGS((char_u *src, int *usedlen, char_u **fnamep, char_u **bufp, int *fnamelen)); char_u *do_string_sub __ARGS((char_u *str, char_u *pat, char_u *sub, char_u *flags)); -int switch_win __ARGS((win_T **, tabpage_T **, win_T *, tabpage_T *)); -void restore_win __ARGS((win_T *, tabpage_T *)); -void list_add_watch __ARGS((list_T *l, listwatch_T *lw)); -void list_rem_watch __ARGS((list_T *l, listwatch_T *lwrem)); /* vim: set ft=c : */ diff --git a/src/proto/window.pro b/src/proto/window.pro --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -32,6 +32,7 @@ void goto_tabpage_win __ARGS((tabpage_T void tabpage_move __ARGS((int nr)); void win_goto __ARGS((win_T *wp)); win_T *win_find_nr __ARGS((int winnr)); +tabpage_T *win_find_tabpage __ARGS((win_T *win)); void win_enter __ARGS((win_T *wp, int undo_sync)); win_T *buf_jump_open_win __ARGS((buf_T *buf)); win_T *buf_jump_open_tab __ARGS((buf_T *buf)); @@ -69,6 +70,10 @@ int only_one_window __ARGS((void)); void check_lnums __ARGS((int do_curwin)); void make_snapshot __ARGS((int idx)); void restore_snapshot __ARGS((int idx, int close_curwin)); +int switch_win __ARGS((win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp)); +void restore_win __ARGS((win_T *save_curwin, tabpage_T *save_curtab)); +void switch_buffer __ARGS((buf_T **save_curbuf, buf_T *buf)); +void restore_buffer __ARGS((buf_T *save_curbuf)); int win_hasvertsplit __ARGS((void)); int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id)); int match_delete __ARGS((win_T *wp, int id, int perr)); diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -333,7 +333,7 @@ Number of tabs: 4 Current tab pages: (1): 1 windows, current is Windows: - (0): displays buffer ; cursor is at (955, 0) + (0): displays buffer ; cursor is at (954, 0) (2): 1 windows, current is Windows: (0): displays buffer ; cursor is at (1, 0) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 963, +/**/ 962, /**/ 961, diff --git a/src/window.c b/src/window.c --- a/src/window.c +++ b/src/window.c @@ -4058,6 +4058,25 @@ win_find_nr(winnr) } #endif +#if (defined(FEAT_WINDOWS) && defined(FEAT_PYTHON)) || defined(PROTO) +/* + * Find the tabpage for window "win". + */ + tabpage_T * +win_find_tabpage(win) + win_T *win; +{ + win_T *wp; + tabpage_T *tp; + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + for (wp = tp->tp_firstwin; wp != NULL; wp = wp->w_next) + if (wp == win) + return tp; + return NULL; +} +#endif + #ifdef FEAT_VERTSPLIT /* * Move to window above or below "count" times. @@ -6550,6 +6569,105 @@ restore_snapshot_rec(sn, fr) #endif +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Set "win" to be the curwin and "tp" to be the current tab page. + * restore_win() MUST be called to undo. + * No autocommands will be executed. + * Returns FAIL if switching to "win" failed. + */ + int +switch_win(save_curwin, save_curtab, win, tp) + win_T **save_curwin; + tabpage_T **save_curtab; + win_T *win; + tabpage_T *tp; +{ +# ifdef FEAT_AUTOCMD + block_autocmds(); +# endif +# ifdef FEAT_WINDOWS + *save_curwin = curwin; + if (tp != NULL) + { + *save_curtab = curtab; + goto_tabpage_tp(tp, FALSE, FALSE); + } + if (!win_valid(win)) + { +# ifdef FEAT_AUTOCMD + unblock_autocmds(); +# endif + return FAIL; + } + curwin = win; + curbuf = curwin->w_buffer; +# endif + return OK; +} + +/* + * Restore current tabpage and window saved by switch_win(), if still valid. + */ + void +restore_win(save_curwin, save_curtab) + win_T *save_curwin; + tabpage_T *save_curtab; +{ +# ifdef FEAT_WINDOWS + if (save_curtab != NULL && valid_tabpage(save_curtab)) + goto_tabpage_tp(save_curtab, FALSE, FALSE); + if (win_valid(save_curwin)) + { + curwin = save_curwin; + curbuf = curwin->w_buffer; + } +# endif +# ifdef FEAT_AUTOCMD + unblock_autocmds(); +# endif +} + +/* + * Make "buf" the current buffer. restore_buffer() MUST be called to undo. + * No autocommands will be executed. Use aucmd_prepbuf() if there are any. + */ + void +switch_buffer(save_curbuf, buf) + buf_T *buf; + buf_T **save_curbuf; +{ +# ifdef FEAT_AUTOCMD + block_autocmds(); +# endif + *save_curbuf = curbuf; + --curbuf->b_nwindows; + curbuf = buf; + curwin->w_buffer = buf; + ++curbuf->b_nwindows; +} + +/* + * Restore the current buffer after using switch_buffer(). + */ + void +restore_buffer(save_curbuf) + buf_T *save_curbuf; +{ +# ifdef FEAT_AUTOCMD + unblock_autocmds(); +# endif + /* Check for valid buffer, just in case. */ + if (buf_valid(save_curbuf)) + { + --curbuf->b_nwindows; + curwin->w_buffer = save_curbuf; + curbuf = save_curbuf; + ++curbuf->b_nwindows; + } +} +#endif + #if (defined(FEAT_GUI) && defined(FEAT_VERTSPLIT)) || defined(PROTO) /* * Return TRUE if there is any vertically split window.