Mercurial > vim
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 */ |