comparison src/change.c @ 16666:978bcd70883d v8.1.1335

patch 8.1.1335: listener callback is called after inserting text commit https://github.com/vim/vim/commit/dda4144d39a9d685b8dda830978e7410bd372c40 Author: Bram Moolenaar <Bram@vim.org> Date: Thu May 16 22:11:47 2019 +0200 patch 8.1.1335: listener callback is called after inserting text Problem: Listener callback is called after inserting text. Solution: Flush the changes before inserting or deleting a line. Store changes per buffer.
author Bram Moolenaar <Bram@vim.org>
date Thu, 16 May 2019 22:15:06 +0200
parents 1fc9cd08cf3c
children 1c2d9f67d98f
comparison
equal deleted inserted replaced
16665:64f31042d128 16666:978bcd70883d
150 need_maketitle = TRUE; // set window title later 150 need_maketitle = TRUE; // set window title later
151 #endif 151 #endif
152 } 152 }
153 153
154 #ifdef FEAT_EVAL 154 #ifdef FEAT_EVAL
155 static list_T *recorded_changes = NULL;
156 static long next_listener_id = 0; 155 static long next_listener_id = 0;
157 156
158 /* 157 /*
158 * Check if the change at "lnum" / "col" is above or overlaps with an existing
159 * changed. If above then flush changes and invoke listeners.
160 * If "merge" is TRUE do the merge.
161 * Returns TRUE if the change was merged.
162 */
163 static int
164 check_recorded_changes(
165 buf_T *buf,
166 linenr_T lnum,
167 colnr_T col,
168 linenr_T lnume,
169 long xtra,
170 int merge)
171 {
172 if (buf->b_recorded_changes != NULL && xtra != 0)
173 {
174 listitem_T *li;
175 linenr_T nr;
176
177 for (li = buf->b_recorded_changes->lv_first; li != NULL;
178 li = li->li_next)
179 {
180 nr = (linenr_T)dict_get_number(
181 li->li_tv.vval.v_dict, (char_u *)"lnum");
182 if (nr >= lnum || nr > lnume)
183 {
184 if (li->li_next == NULL && lnum == nr
185 && col + 1 == (colnr_T)dict_get_number(
186 li->li_tv.vval.v_dict, (char_u *)"col"))
187 {
188 if (merge)
189 {
190 dictitem_T *di;
191
192 // Same start point and nothing is following, entries
193 // can be merged.
194 di = dict_find(li->li_tv.vval.v_dict,
195 (char_u *)"end", -1);
196 nr = tv_get_number(&di->di_tv);
197 if (lnume > nr)
198 di->di_tv.vval.v_number = lnume;
199 di = dict_find(li->li_tv.vval.v_dict,
200 (char_u *)"added", -1);
201 di->di_tv.vval.v_number += xtra;
202 return TRUE;
203 }
204 }
205 else
206 {
207 // the current change is going to make the line number in
208 // the older change invalid, flush now
209 invoke_listeners(curbuf);
210 break;
211 }
212 }
213 }
214 }
215 return FALSE;
216 }
217
218 /*
159 * Record a change for listeners added with listener_add(). 219 * Record a change for listeners added with listener_add().
220 * Always for the current buffer.
160 */ 221 */
161 static void 222 static void
162 may_record_change( 223 may_record_change(
163 linenr_T lnum, 224 linenr_T lnum,
164 colnr_T col, 225 colnr_T col,
170 if (curbuf->b_listener == NULL) 231 if (curbuf->b_listener == NULL)
171 return; 232 return;
172 233
173 // If the new change is going to change the line numbers in already listed 234 // If the new change is going to change the line numbers in already listed
174 // changes, then flush. 235 // changes, then flush.
175 if (recorded_changes != NULL && xtra != 0) 236 if (check_recorded_changes(curbuf, lnum, col, lnume, xtra, TRUE))
176 { 237 return;
177 listitem_T *li; 238
178 linenr_T nr; 239 if (curbuf->b_recorded_changes == NULL)
179 240 {
180 for (li = recorded_changes->lv_first; li != NULL; li = li->li_next) 241 curbuf->b_recorded_changes = list_alloc();
181 { 242 if (curbuf->b_recorded_changes == NULL) // out of memory
182 nr = (linenr_T)dict_get_number(
183 li->li_tv.vval.v_dict, (char_u *)"lnum");
184 if (nr >= lnum || nr > lnume)
185 {
186 if (li->li_next == NULL && lnum == nr
187 && col + 1 == (colnr_T)dict_get_number(
188 li->li_tv.vval.v_dict, (char_u *)"col"))
189 {
190 dictitem_T *di;
191
192 // Same start point and nothing is following, entries can
193 // be merged.
194 di = dict_find(li->li_tv.vval.v_dict, (char_u *)"end", -1);
195 nr = tv_get_number(&di->di_tv);
196 if (lnume > nr)
197 di->di_tv.vval.v_number = lnume;
198 di = dict_find(li->li_tv.vval.v_dict,
199 (char_u *)"added", -1);
200 di->di_tv.vval.v_number += xtra;
201 return;
202 }
203
204 // the current change is going to make the line number in the
205 // older change invalid, flush now
206 invoke_listeners(curbuf);
207 break;
208 }
209 }
210 }
211
212 if (recorded_changes == NULL)
213 {
214 recorded_changes = list_alloc();
215 if (recorded_changes == NULL) // out of memory
216 return; 243 return;
217 ++recorded_changes->lv_refcount; 244 ++curbuf->b_recorded_changes->lv_refcount;
218 recorded_changes->lv_lock = VAR_FIXED; 245 curbuf->b_recorded_changes->lv_lock = VAR_FIXED;
219 } 246 }
220 247
221 dict = dict_alloc(); 248 dict = dict_alloc();
222 if (dict == NULL) 249 if (dict == NULL)
223 return; 250 return;
224 dict_add_number(dict, "lnum", (varnumber_T)lnum); 251 dict_add_number(dict, "lnum", (varnumber_T)lnum);
225 dict_add_number(dict, "end", (varnumber_T)lnume); 252 dict_add_number(dict, "end", (varnumber_T)lnume);
226 dict_add_number(dict, "added", (varnumber_T)xtra); 253 dict_add_number(dict, "added", (varnumber_T)xtra);
227 dict_add_number(dict, "col", (varnumber_T)col + 1); 254 dict_add_number(dict, "col", (varnumber_T)col + 1);
228 255
229 list_append_dict(recorded_changes, dict); 256 list_append_dict(curbuf->b_recorded_changes, dict);
230 } 257 }
231 258
232 /* 259 /*
233 * listener_add() function 260 * listener_add() function
234 */ 261 */
315 prev = lnr; 342 prev = lnr;
316 } 343 }
317 } 344 }
318 345
319 /* 346 /*
347 * Called before inserting a line above "lnum"/"lnum3" or deleting line "lnum"
348 * to "lnume".
349 */
350 void
351 may_invoke_listeners(buf_T *buf, linenr_T lnum, linenr_T lnume, int added)
352 {
353 check_recorded_changes(buf, lnum, 0, lnume, added, FALSE);
354 }
355
356 /*
320 * Called when a sequence of changes is done: invoke listeners added with 357 * Called when a sequence of changes is done: invoke listeners added with
321 * listener_add(). 358 * listener_add().
322 */ 359 */
323 void 360 void
324 invoke_listeners(buf_T *buf) 361 invoke_listeners(buf_T *buf)
330 listitem_T *li; 367 listitem_T *li;
331 linenr_T start = MAXLNUM; 368 linenr_T start = MAXLNUM;
332 linenr_T end = 0; 369 linenr_T end = 0;
333 linenr_T added = 0; 370 linenr_T added = 0;
334 371
335 if (recorded_changes == NULL // nothing changed 372 if (buf->b_recorded_changes == NULL // nothing changed
336 || buf->b_listener == NULL) // no listeners 373 || buf->b_listener == NULL) // no listeners
337 return; 374 return;
338 375
339 argv[0].v_type = VAR_NUMBER; 376 argv[0].v_type = VAR_NUMBER;
340 argv[0].vval.v_number = buf->b_fnum; // a:bufnr 377 argv[0].vval.v_number = buf->b_fnum; // a:bufnr
341 378
342 379
343 for (li = recorded_changes->lv_first; li != NULL; li = li->li_next) 380 for (li = buf->b_recorded_changes->lv_first; li != NULL; li = li->li_next)
344 { 381 {
345 varnumber_T lnum; 382 varnumber_T lnum;
346 383
347 lnum = dict_get_number(li->li_tv.vval.v_dict, (char_u *)"lnum"); 384 lnum = dict_get_number(li->li_tv.vval.v_dict, (char_u *)"lnum");
348 if (start > lnum) 385 if (start > lnum)
358 argv[2].vval.v_number = end; 395 argv[2].vval.v_number = end;
359 argv[3].v_type = VAR_NUMBER; 396 argv[3].v_type = VAR_NUMBER;
360 argv[3].vval.v_number = added; 397 argv[3].vval.v_number = added;
361 398
362 argv[4].v_type = VAR_LIST; 399 argv[4].v_type = VAR_LIST;
363 argv[4].vval.v_list = recorded_changes; 400 argv[4].vval.v_list = buf->b_recorded_changes;
364 ++textlock; 401 ++textlock;
365 402
366 for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next) 403 for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
367 { 404 {
368 call_func(lnr->lr_callback, -1, &rettv, 405 call_func(lnr->lr_callback, -1, &rettv,
369 5, argv, NULL, 0L, 0L, &dummy, TRUE, lnr->lr_partial, NULL); 406 5, argv, NULL, 0L, 0L, &dummy, TRUE, lnr->lr_partial, NULL);
370 clear_tv(&rettv); 407 clear_tv(&rettv);
371 } 408 }
372 409
373 --textlock; 410 --textlock;
374 list_unref(recorded_changes); 411 list_unref(buf->b_recorded_changes);
375 recorded_changes = NULL; 412 buf->b_recorded_changes = NULL;
376 } 413 }
377 #endif 414 #endif
378 415
379 /* 416 /*
380 * Common code for when a change was made. 417 * Common code for when a change was made.