To: vim_dev@googlegroups.com Subject: Patch 9.0.0914 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0914 Problem: deletebufline() may move marks in the wrong window. Solution: Find a window for the buffer being changed. (closes #11583) Files: src/evalbuffer.c, src/testdir/test_bufline.vim *** ../vim-9.0.0913/src/evalbuffer.c 2022-11-19 13:59:39.511861139 +0000 --- src/evalbuffer.c 2022-11-20 11:12:50.860191314 +0000 *************** *** 119,124 **** --- 119,177 ---- } } + typedef struct { + win_T *cob_curwin_save; + aco_save_T cob_aco; + int cob_using_aco; + int cob_save_VIsual_active; + } cob_T; + + /* + * Used before making a change in "buf", which is not the current one: Make + * "buf" the current buffer and find a window for this buffer, so that side + * effects are done correctly (e.g., adjusting marks). + * + * Information is saved in "cob" and MUST be restored by calling + * change_other_buffer_restore(). + */ + static void + change_other_buffer_prepare(cob_T *cob, buf_T *buf) + { + CLEAR_POINTER(cob); + + // Set "curbuf" to the buffer being changed. Then make sure there is a + // window for it to handle any side effects. + cob->cob_save_VIsual_active = VIsual_active; + VIsual_active = FALSE; + cob->cob_curwin_save = curwin; + curbuf = buf; + find_win_for_curbuf(); // simplest: find existing window for "buf" + + if (curwin->w_buffer != buf) + { + // No existing window for this buffer. It is dangerous to have + // curwin->w_buffer differ from "curbuf", use the autocmd window. + curbuf = curwin->w_buffer; + aucmd_prepbuf(&cob->cob_aco, buf); + cob->cob_using_aco = TRUE; + } + } + + static void + change_other_buffer_restore(cob_T *cob) + { + if (cob->cob_using_aco) + { + aucmd_restbuf(&cob->cob_aco); + } + else + { + curwin = cob->cob_curwin_save; + curbuf = curwin->w_buffer; + } + VIsual_active = cob->cob_save_VIsual_active; + } + /* * Set line or list of lines in buffer "buf" to "lines". * Any type is allowed and converted to a string. *************** *** 137,146 **** listitem_T *li = NULL; long added = 0; linenr_T append_lnum; - win_T *curwin_save = NULL; - aco_save_T aco; - int using_aco = FALSE; - int save_VIsual_active = VIsual_active; // When using the current buffer ml_mfp will be set if needed. Useful when // setline() is used on startup. For other buffers the buffer must be --- 190,195 ---- *************** *** 154,177 **** return; } if (!is_curbuf) ! { ! // Set "curbuf" to the buffer being changed. Then make sure there is a ! // window for it to handle any side effects. ! VIsual_active = FALSE; ! curwin_save = curwin; ! curbuf = buf; ! find_win_for_curbuf(); // simplest: find existing window for "buf" ! ! if (curwin->w_buffer != buf) ! { ! // No existing window for this buffer. It is dangerous to have ! // curwin->w_buffer differ from "curbuf", use the autocmd window. ! curbuf = curwin->w_buffer; ! aucmd_prepbuf(&aco, buf); ! using_aco = TRUE; ! } ! } if (append) // appendbufline() uses the line number below which we insert --- 203,213 ---- return; } + // After this don't use "return", goto "cleanup"! + cob_T cob; if (!is_curbuf) ! // set "curbuf" to "buf" and find a window for this buffer ! change_other_buffer_prepare(&cob, buf); if (append) // appendbufline() uses the line number below which we insert *************** *** 272,289 **** done: if (!is_curbuf) ! { ! if (using_aco) ! { ! aucmd_restbuf(&aco); ! } ! else ! { ! curwin = curwin_save; ! curbuf = curwin->w_buffer; ! } ! VIsual_active = save_VIsual_active; ! } } /* --- 308,314 ---- done: if (!is_curbuf) ! change_other_buffer_restore(&cob); } /* *************** *** 521,532 **** linenr_T lnum; long count; int is_curbuf; - buf_T *curbuf_save = NULL; - win_T *curwin_save = NULL; tabpage_T *tp; win_T *wp; int did_emsg_before = did_emsg; - int save_VIsual_active = VIsual_active; rettv->vval.v_number = 1; // FAIL by default --- 546,554 ---- *************** *** 539,545 **** buf = tv_get_buf(&argvars[0], FALSE); if (buf == NULL) return; - is_curbuf = buf == curbuf; first = tv_get_lnum_buf(&argvars[1], buf); if (did_emsg > did_emsg_before) --- 561,566 ---- *************** *** 554,567 **** return; // After this don't use "return", goto "cleanup"! if (!is_curbuf) ! { ! VIsual_active = FALSE; ! curbuf_save = curbuf; ! curwin_save = curwin; ! curbuf = buf; ! find_win_for_curbuf(); ! } if (last > curbuf->b_ml.ml_line_count) last = curbuf->b_ml.ml_line_count; count = last - first + 1; --- 575,586 ---- return; // After this don't use "return", goto "cleanup"! + is_curbuf = buf == curbuf; + cob_T cob; if (!is_curbuf) ! // set "curbuf" to "buf" and find a window for this buffer ! change_other_buffer_prepare(&cob, buf); ! if (last > curbuf->b_ml.ml_line_count) last = curbuf->b_ml.ml_line_count; count = last - first + 1; *************** *** 599,609 **** cleanup: if (!is_curbuf) ! { ! curbuf = curbuf_save; ! curwin = curwin_save; ! VIsual_active = save_VIsual_active; ! } } /* --- 618,624 ---- cleanup: if (!is_curbuf) ! change_other_buffer_restore(&cob); } /* *** ../vim-9.0.0913/src/testdir/test_bufline.vim 2022-11-06 22:25:59.111977620 +0000 --- src/testdir/test_bufline.vim 2022-11-20 10:48:00.503566772 +0000 *************** *** 98,109 **** new let b = bufnr('%') hide call assert_equal(0, appendbufline(b, 0, ['foo', 'bar'])) call assert_equal(['foo'], getbufline(b, 1)) call assert_equal(['bar'], getbufline(b, 2)) call assert_equal(['foo', 'bar'], getbufline(b, 1, 2)) exe "bd!" b ! call assert_equal([], getbufline(b, 1, 2)) split Xtest call setline(1, ['a', 'b', 'c']) --- 98,122 ---- new let b = bufnr('%') hide + + new + call setline(1, ['line1', 'line2', 'line3']) + normal! 2gggg + call assert_equal(2, line("''")) + call assert_equal(0, appendbufline(b, 0, ['foo', 'bar'])) call assert_equal(['foo'], getbufline(b, 1)) call assert_equal(['bar'], getbufline(b, 2)) call assert_equal(['foo', 'bar'], getbufline(b, 1, 2)) + call assert_equal(0, appendbufline(b, 0, 'baz')) + call assert_equal(['baz', 'foo', 'bar'], getbufline(b, 1, 3)) + + " appendbufline() in a hidden buffer shouldn't move marks in current window. + call assert_equal(2, line("''")) + bwipe! + exe "bd!" b ! call assert_equal([], getbufline(b, 1, 3)) split Xtest call setline(1, ['a', 'b', 'c']) *************** *** 173,182 **** --- 186,206 ---- let b = bufnr('%') call setline(1, ['aaa', 'bbb', 'ccc']) hide + + new + call setline(1, ['line1', 'line2', 'line3']) + normal! 2gggg + call assert_equal(2, line("''")) + call assert_equal(0, deletebufline(b, 2)) call assert_equal(['aaa', 'ccc'], getbufline(b, 1, 2)) call assert_equal(0, deletebufline(b, 2, 8)) call assert_equal(['aaa'], getbufline(b, 1, 2)) + + " deletebufline() in a hidden buffer shouldn't move marks in current window. + call assert_equal(2, line("''")) + bwipe! + exe "bd!" b call assert_equal(1, b->deletebufline(1)) *** ../vim-9.0.0913/src/version.c 2022-11-19 21:17:48.841226535 +0000 --- src/version.c 2022-11-20 10:49:34.531666036 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 914, /**/ -- From "know your smileys": :-E Has major dental problems /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///