diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-05-16 22:11:47 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-05-16 22:11:47 +0200 |
commit | dda4144d39a9d685b8dda830978e7410bd372c40 (patch) | |
tree | 7044aa90183afff7fbf2cb141943c3812d6c2647 /src/change.c | |
parent | eda652215abf696f86b872888945a2d2dd8c7192 (diff) | |
download | vim-git-dda4144d39a9d685b8dda830978e7410bd372c40.tar.gz |
patch 8.1.1335: listener callback is called after inserting textv8.1.1335
Problem: Listener callback is called after inserting text.
Solution: Flush the changes before inserting or deleting a line. Store
changes per buffer.
Diffstat (limited to 'src/change.c')
-rw-r--r-- | src/change.c | 125 |
1 files changed, 81 insertions, 44 deletions
diff --git a/src/change.c b/src/change.c index 86f1ffcfb..f1c3cc4d0 100644 --- a/src/change.c +++ b/src/change.c @@ -152,32 +152,30 @@ changed_internal(void) } #ifdef FEAT_EVAL -static list_T *recorded_changes = NULL; static long next_listener_id = 0; /* - * Record a change for listeners added with listener_add(). + * Check if the change at "lnum" / "col" is above or overlaps with an existing + * changed. If above then flush changes and invoke listeners. + * If "merge" is TRUE do the merge. + * Returns TRUE if the change was merged. */ - static void -may_record_change( - linenr_T lnum, - colnr_T col, - linenr_T lnume, - long xtra) + static int +check_recorded_changes( + buf_T *buf, + linenr_T lnum, + colnr_T col, + linenr_T lnume, + long xtra, + int merge) { - dict_T *dict; - - if (curbuf->b_listener == NULL) - return; - - // If the new change is going to change the line numbers in already listed - // changes, then flush. - if (recorded_changes != NULL && xtra != 0) + if (buf->b_recorded_changes != NULL && xtra != 0) { listitem_T *li; linenr_T nr; - for (li = recorded_changes->lv_first; li != NULL; li = li->li_next) + for (li = buf->b_recorded_changes->lv_first; li != NULL; + li = li->li_next) { nr = (linenr_T)dict_get_number( li->li_tv.vval.v_dict, (char_u *)"lnum"); @@ -187,35 +185,64 @@ may_record_change( && col + 1 == (colnr_T)dict_get_number( li->li_tv.vval.v_dict, (char_u *)"col")) { - dictitem_T *di; - - // Same start point and nothing is following, entries can - // be merged. - di = dict_find(li->li_tv.vval.v_dict, (char_u *)"end", -1); - nr = tv_get_number(&di->di_tv); - if (lnume > nr) - di->di_tv.vval.v_number = lnume; - di = dict_find(li->li_tv.vval.v_dict, + if (merge) + { + dictitem_T *di; + + // Same start point and nothing is following, entries + // can be merged. + di = dict_find(li->li_tv.vval.v_dict, + (char_u *)"end", -1); + nr = tv_get_number(&di->di_tv); + if (lnume > nr) + di->di_tv.vval.v_number = lnume; + di = dict_find(li->li_tv.vval.v_dict, (char_u *)"added", -1); - di->di_tv.vval.v_number += xtra; - return; + di->di_tv.vval.v_number += xtra; + return TRUE; + } + } + else + { + // the current change is going to make the line number in + // the older change invalid, flush now + invoke_listeners(curbuf); + break; } - - // the current change is going to make the line number in the - // older change invalid, flush now - invoke_listeners(curbuf); - break; } } } + return FALSE; +} - if (recorded_changes == NULL) +/* + * Record a change for listeners added with listener_add(). + * Always for the current buffer. + */ + static void +may_record_change( + linenr_T lnum, + colnr_T col, + linenr_T lnume, + long xtra) +{ + dict_T *dict; + + if (curbuf->b_listener == NULL) + return; + + // If the new change is going to change the line numbers in already listed + // changes, then flush. + if (check_recorded_changes(curbuf, lnum, col, lnume, xtra, TRUE)) + return; + + if (curbuf->b_recorded_changes == NULL) { - recorded_changes = list_alloc(); - if (recorded_changes == NULL) // out of memory + curbuf->b_recorded_changes = list_alloc(); + if (curbuf->b_recorded_changes == NULL) // out of memory return; - ++recorded_changes->lv_refcount; - recorded_changes->lv_lock = VAR_FIXED; + ++curbuf->b_recorded_changes->lv_refcount; + curbuf->b_recorded_changes->lv_lock = VAR_FIXED; } dict = dict_alloc(); @@ -226,7 +253,7 @@ may_record_change( dict_add_number(dict, "added", (varnumber_T)xtra); dict_add_number(dict, "col", (varnumber_T)col + 1); - list_append_dict(recorded_changes, dict); + list_append_dict(curbuf->b_recorded_changes, dict); } /* @@ -317,6 +344,16 @@ f_listener_remove(typval_T *argvars, typval_T *rettv UNUSED) } /* + * Called before inserting a line above "lnum"/"lnum3" or deleting line "lnum" + * to "lnume". + */ + void +may_invoke_listeners(buf_T *buf, linenr_T lnum, linenr_T lnume, int added) +{ + check_recorded_changes(buf, lnum, 0, lnume, added, FALSE); +} + +/* * Called when a sequence of changes is done: invoke listeners added with * listener_add(). */ @@ -332,7 +369,7 @@ invoke_listeners(buf_T *buf) linenr_T end = 0; linenr_T added = 0; - if (recorded_changes == NULL // nothing changed + if (buf->b_recorded_changes == NULL // nothing changed || buf->b_listener == NULL) // no listeners return; @@ -340,7 +377,7 @@ invoke_listeners(buf_T *buf) argv[0].vval.v_number = buf->b_fnum; // a:bufnr - for (li = recorded_changes->lv_first; li != NULL; li = li->li_next) + for (li = buf->b_recorded_changes->lv_first; li != NULL; li = li->li_next) { varnumber_T lnum; @@ -360,7 +397,7 @@ invoke_listeners(buf_T *buf) argv[3].vval.v_number = added; argv[4].v_type = VAR_LIST; - argv[4].vval.v_list = recorded_changes; + argv[4].vval.v_list = buf->b_recorded_changes; ++textlock; for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next) @@ -371,8 +408,8 @@ invoke_listeners(buf_T *buf) } --textlock; - list_unref(recorded_changes); - recorded_changes = NULL; + list_unref(buf->b_recorded_changes); + buf->b_recorded_changes = NULL; } #endif |