comparison src/evalbuffer.c @ 31160:eff0d98467e3 v9.0.0914

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)
author Bram Moolenaar <Bram@vim.org>
date Sun, 20 Nov 2022 12:15:04 +0100
parents ac6f5741b155
children 7831da568864
comparison
equal deleted inserted replaced
31159:519bd5b00672 31160:eff0d98467e3
117 break; 117 break;
118 } 118 }
119 } 119 }
120 } 120 }
121 121
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
122 /* 175 /*
123 * Set line or list of lines in buffer "buf" to "lines". 176 * Set line or list of lines in buffer "buf" to "lines".
124 * Any type is allowed and converted to a string. 177 * Any type is allowed and converted to a string.
125 */ 178 */
126 static void 179 static void
135 char_u *line = NULL; 188 char_u *line = NULL;
136 list_T *l = NULL; 189 list_T *l = NULL;
137 listitem_T *li = NULL; 190 listitem_T *li = NULL;
138 long added = 0; 191 long added = 0;
139 linenr_T append_lnum; 192 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;
144 193
145 // When using the current buffer ml_mfp will be set if needed. Useful when 194 // When using the current buffer ml_mfp will be set if needed. Useful when
146 // setline() is used on startup. For other buffers the buffer must be 195 // setline() is used on startup. For other buffers the buffer must be
147 // loaded. 196 // loaded.
148 int is_curbuf = buf == curbuf; 197 int is_curbuf = buf == curbuf;
152 if (in_vim9script() && lnum < 1) 201 if (in_vim9script() && lnum < 1)
153 semsg(_(e_invalid_line_number_nr), lnum_arg); 202 semsg(_(e_invalid_line_number_nr), lnum_arg);
154 return; 203 return;
155 } 204 }
156 205
206 // After this don't use "return", goto "cleanup"!
207 cob_T cob;
157 if (!is_curbuf) 208 if (!is_curbuf)
158 { 209 // set "curbuf" to "buf" and find a window for this buffer
159 // Set "curbuf" to the buffer being changed. Then make sure there is a 210 change_other_buffer_prepare(&cob, buf);
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 }
175 211
176 if (append) 212 if (append)
177 // appendbufline() uses the line number below which we insert 213 // appendbufline() uses the line number below which we insert
178 append_lnum = lnum - 1; 214 append_lnum = lnum - 1;
179 else 215 else
270 update_topline(); 306 update_topline();
271 } 307 }
272 308
273 done: 309 done:
274 if (!is_curbuf) 310 if (!is_curbuf)
275 { 311 change_other_buffer_restore(&cob);
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 }
287 } 312 }
288 313
289 /* 314 /*
290 * "append(lnum, string/list)" function 315 * "append(lnum, string/list)" function
291 */ 316 */
519 buf_T *buf; 544 buf_T *buf;
520 linenr_T first, last; 545 linenr_T first, last;
521 linenr_T lnum; 546 linenr_T lnum;
522 long count; 547 long count;
523 int is_curbuf; 548 int is_curbuf;
524 buf_T *curbuf_save = NULL;
525 win_T *curwin_save = NULL;
526 tabpage_T *tp; 549 tabpage_T *tp;
527 win_T *wp; 550 win_T *wp;
528 int did_emsg_before = did_emsg; 551 int did_emsg_before = did_emsg;
529 int save_VIsual_active = VIsual_active;
530 552
531 rettv->vval.v_number = 1; // FAIL by default 553 rettv->vval.v_number = 1; // FAIL by default
532 554
533 if (in_vim9script() 555 if (in_vim9script()
534 && (check_for_buffer_arg(argvars, 0) == FAIL 556 && (check_for_buffer_arg(argvars, 0) == FAIL
537 return; 559 return;
538 560
539 buf = tv_get_buf(&argvars[0], FALSE); 561 buf = tv_get_buf(&argvars[0], FALSE);
540 if (buf == NULL) 562 if (buf == NULL)
541 return; 563 return;
542 is_curbuf = buf == curbuf;
543 564
544 first = tv_get_lnum_buf(&argvars[1], buf); 565 first = tv_get_lnum_buf(&argvars[1], buf);
545 if (did_emsg > did_emsg_before) 566 if (did_emsg > did_emsg_before)
546 return; 567 return;
547 if (argvars[2].v_type != VAR_UNKNOWN) 568 if (argvars[2].v_type != VAR_UNKNOWN)
552 if (buf->b_ml.ml_mfp == NULL || first < 1 573 if (buf->b_ml.ml_mfp == NULL || first < 1
553 || first > buf->b_ml.ml_line_count || last < first) 574 || first > buf->b_ml.ml_line_count || last < first)
554 return; 575 return;
555 576
556 // After this don't use "return", goto "cleanup"! 577 // After this don't use "return", goto "cleanup"!
578 is_curbuf = buf == curbuf;
579 cob_T cob;
557 if (!is_curbuf) 580 if (!is_curbuf)
558 { 581 // set "curbuf" to "buf" and find a window for this buffer
559 VIsual_active = FALSE; 582 change_other_buffer_prepare(&cob, buf);
560 curbuf_save = curbuf; 583
561 curwin_save = curwin;
562 curbuf = buf;
563 find_win_for_curbuf();
564 }
565 if (last > curbuf->b_ml.ml_line_count) 584 if (last > curbuf->b_ml.ml_line_count)
566 last = curbuf->b_ml.ml_line_count; 585 last = curbuf->b_ml.ml_line_count;
567 count = last - first + 1; 586 count = last - first + 1;
568 587
569 // When coming here from Insert mode, sync undo, so that this can be 588 // When coming here from Insert mode, sync undo, so that this can be
597 deleted_lines_mark(first, count); 616 deleted_lines_mark(first, count);
598 rettv->vval.v_number = 0; // OK 617 rettv->vval.v_number = 0; // OK
599 618
600 cleanup: 619 cleanup:
601 if (!is_curbuf) 620 if (!is_curbuf)
602 { 621 change_other_buffer_restore(&cob);
603 curbuf = curbuf_save;
604 curwin = curwin_save;
605 VIsual_active = save_VIsual_active;
606 }
607 } 622 }
608 623
609 /* 624 /*
610 * Returns buffer options, variables and other attributes in a dictionary. 625 * Returns buffer options, variables and other attributes in a dictionary.
611 */ 626 */