• R/O
  • SSH

vim: Commit

Mirror of the Vim source from https://github.com/vim/vim


Commit MetaInfo

Revisioneff0d98467e32830ea7a4751ea7071eab640829b (tree)
Time2022-11-20 20:15:04
AuthorBram Moolenaar <Bram@vim....>
CommiterBram Moolenaar

Log Message

patch 9.0.0914: deletebufline() may move marks in the wrong window

Commit: https://github.com/vim/vim/commit/228e422855d43965f2c3319ff0cdc26ea422c10f
Author: zeertzjq <zeertzjq@outlook.com>
Date: Sun Nov 20 11:13:17 2022 +0000

patch 9.0.0914: deletebufline() may move marks in the wrong window
Problem: deletebufline() may move marks in the wrong window.
Solution: Find a window for the buffer being changed. (closes https://github.com/vim/vim/issues/11583)

Change Summary

Incremental Difference

diff -r 519bd5b00672 -r eff0d98467e3 src/evalbuffer.c
--- a/src/evalbuffer.c Sat Nov 19 22:30:04 2022 +0100
+++ b/src/evalbuffer.c Sun Nov 20 12:15:04 2022 +0100
@@ -119,6 +119,59 @@
119119 }
120120 }
121121
122+typedef struct {
123+ win_T *cob_curwin_save;
124+ aco_save_T cob_aco;
125+ int cob_using_aco;
126+ int cob_save_VIsual_active;
127+} cob_T;
128+
129+/*
130+ * Used before making a change in "buf", which is not the current one: Make
131+ * "buf" the current buffer and find a window for this buffer, so that side
132+ * effects are done correctly (e.g., adjusting marks).
133+ *
134+ * Information is saved in "cob" and MUST be restored by calling
135+ * change_other_buffer_restore().
136+ */
137+ static void
138+change_other_buffer_prepare(cob_T *cob, buf_T *buf)
139+{
140+ CLEAR_POINTER(cob);
141+
142+ // Set "curbuf" to the buffer being changed. Then make sure there is a
143+ // window for it to handle any side effects.
144+ cob->cob_save_VIsual_active = VIsual_active;
145+ VIsual_active = FALSE;
146+ cob->cob_curwin_save = curwin;
147+ curbuf = buf;
148+ find_win_for_curbuf(); // simplest: find existing window for "buf"
149+
150+ if (curwin->w_buffer != buf)
151+ {
152+ // No existing window for this buffer. It is dangerous to have
153+ // curwin->w_buffer differ from "curbuf", use the autocmd window.
154+ curbuf = curwin->w_buffer;
155+ aucmd_prepbuf(&cob->cob_aco, buf);
156+ cob->cob_using_aco = TRUE;
157+ }
158+}
159+
160+ static void
161+change_other_buffer_restore(cob_T *cob)
162+{
163+ if (cob->cob_using_aco)
164+ {
165+ aucmd_restbuf(&cob->cob_aco);
166+ }
167+ else
168+ {
169+ curwin = cob->cob_curwin_save;
170+ curbuf = curwin->w_buffer;
171+ }
172+ VIsual_active = cob->cob_save_VIsual_active;
173+}
174+
122175 /*
123176 * Set line or list of lines in buffer "buf" to "lines".
124177 * Any type is allowed and converted to a string.
@@ -137,10 +190,6 @@
137190 listitem_T *li = NULL;
138191 long added = 0;
139192 linenr_T append_lnum;
140- win_T *curwin_save = NULL;
141- aco_save_T aco;
142- int using_aco = FALSE;
143- int save_VIsual_active = VIsual_active;
144193
145194 // When using the current buffer ml_mfp will be set if needed. Useful when
146195 // setline() is used on startup. For other buffers the buffer must be
@@ -154,24 +203,11 @@
154203 return;
155204 }
156205
206+ // After this don't use "return", goto "cleanup"!
207+ cob_T cob;
157208 if (!is_curbuf)
158- {
159- // Set "curbuf" to the buffer being changed. Then make sure there is a
160- // window for it to handle any side effects.
161- VIsual_active = FALSE;
162- curwin_save = curwin;
163- curbuf = buf;
164- find_win_for_curbuf(); // simplest: find existing window for "buf"
165-
166- if (curwin->w_buffer != buf)
167- {
168- // No existing window for this buffer. It is dangerous to have
169- // curwin->w_buffer differ from "curbuf", use the autocmd window.
170- curbuf = curwin->w_buffer;
171- aucmd_prepbuf(&aco, buf);
172- using_aco = TRUE;
173- }
174- }
209+ // set "curbuf" to "buf" and find a window for this buffer
210+ change_other_buffer_prepare(&cob, buf);
175211
176212 if (append)
177213 // appendbufline() uses the line number below which we insert
@@ -272,18 +308,7 @@
272308
273309 done:
274310 if (!is_curbuf)
275- {
276- if (using_aco)
277- {
278- aucmd_restbuf(&aco);
279- }
280- else
281- {
282- curwin = curwin_save;
283- curbuf = curwin->w_buffer;
284- }
285- VIsual_active = save_VIsual_active;
286- }
311+ change_other_buffer_restore(&cob);
287312 }
288313
289314 /*
@@ -521,12 +546,9 @@
521546 linenr_T lnum;
522547 long count;
523548 int is_curbuf;
524- buf_T *curbuf_save = NULL;
525- win_T *curwin_save = NULL;
526549 tabpage_T *tp;
527550 win_T *wp;
528551 int did_emsg_before = did_emsg;
529- int save_VIsual_active = VIsual_active;
530552
531553 rettv->vval.v_number = 1; // FAIL by default
532554
@@ -539,7 +561,6 @@
539561 buf = tv_get_buf(&argvars[0], FALSE);
540562 if (buf == NULL)
541563 return;
542- is_curbuf = buf == curbuf;
543564
544565 first = tv_get_lnum_buf(&argvars[1], buf);
545566 if (did_emsg > did_emsg_before)
@@ -554,14 +575,12 @@
554575 return;
555576
556577 // After this don't use "return", goto "cleanup"!
578+ is_curbuf = buf == curbuf;
579+ cob_T cob;
557580 if (!is_curbuf)
558- {
559- VIsual_active = FALSE;
560- curbuf_save = curbuf;
561- curwin_save = curwin;
562- curbuf = buf;
563- find_win_for_curbuf();
564- }
581+ // set "curbuf" to "buf" and find a window for this buffer
582+ change_other_buffer_prepare(&cob, buf);
583+
565584 if (last > curbuf->b_ml.ml_line_count)
566585 last = curbuf->b_ml.ml_line_count;
567586 count = last - first + 1;
@@ -599,11 +618,7 @@
599618
600619 cleanup:
601620 if (!is_curbuf)
602- {
603- curbuf = curbuf_save;
604- curwin = curwin_save;
605- VIsual_active = save_VIsual_active;
606- }
621+ change_other_buffer_restore(&cob);
607622 }
608623
609624 /*
diff -r 519bd5b00672 -r eff0d98467e3 src/testdir/test_bufline.vim
--- a/src/testdir/test_bufline.vim Sat Nov 19 22:30:04 2022 +0100
+++ b/src/testdir/test_bufline.vim Sun Nov 20 12:15:04 2022 +0100
@@ -98,12 +98,25 @@
9898 new
9999 let b = bufnr('%')
100100 hide
101+
102+ new
103+ call setline(1, ['line1', 'line2', 'line3'])
104+ normal! 2gggg
105+ call assert_equal(2, line("''"))
106+
101107 call assert_equal(0, appendbufline(b, 0, ['foo', 'bar']))
102108 call assert_equal(['foo'], getbufline(b, 1))
103109 call assert_equal(['bar'], getbufline(b, 2))
104110 call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
111+ call assert_equal(0, appendbufline(b, 0, 'baz'))
112+ call assert_equal(['baz', 'foo', 'bar'], getbufline(b, 1, 3))
113+
114+ " appendbufline() in a hidden buffer shouldn't move marks in current window.
115+ call assert_equal(2, line("''"))
116+ bwipe!
117+
105118 exe "bd!" b
106- call assert_equal([], getbufline(b, 1, 2))
119+ call assert_equal([], getbufline(b, 1, 3))
107120
108121 split Xtest
109122 call setline(1, ['a', 'b', 'c'])
@@ -173,10 +186,21 @@
173186 let b = bufnr('%')
174187 call setline(1, ['aaa', 'bbb', 'ccc'])
175188 hide
189+
190+ new
191+ call setline(1, ['line1', 'line2', 'line3'])
192+ normal! 2gggg
193+ call assert_equal(2, line("''"))
194+
176195 call assert_equal(0, deletebufline(b, 2))
177196 call assert_equal(['aaa', 'ccc'], getbufline(b, 1, 2))
178197 call assert_equal(0, deletebufline(b, 2, 8))
179198 call assert_equal(['aaa'], getbufline(b, 1, 2))
199+
200+ " deletebufline() in a hidden buffer shouldn't move marks in current window.
201+ call assert_equal(2, line("''"))
202+ bwipe!
203+
180204 exe "bd!" b
181205 call assert_equal(1, b->deletebufline(1))
182206
diff -r 519bd5b00672 -r eff0d98467e3 src/version.c
--- a/src/version.c Sat Nov 19 22:30:04 2022 +0100
+++ b/src/version.c Sun Nov 20 12:15:04 2022 +0100
@@ -696,6 +696,8 @@
696696 static int included_patches[] =
697697 { /* Add new patch number below this line */
698698 /**/
699+ 914,
700+/**/
699701 913,
700702 /**/
701703 912,
Show on old repository browser