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.
diff --git a/src/change.c b/src/change.c
index 86f1ffc..f1c3cc4 100644
--- a/src/change.c
+++ b/src/change.c
@@ -152,11 +152,72 @@
 }
 
 #ifdef FEAT_EVAL
-static list_T *recorded_changes = NULL;
 static long next_listener_id = 0;
 
 /*
+ * 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 int
+check_recorded_changes(
+	buf_T		*buf,
+	linenr_T	lnum,
+	colnr_T		col,
+	linenr_T	lnume,
+	long		xtra,
+	int		merge)
+{
+    if (buf->b_recorded_changes != NULL && xtra != 0)
+    {
+	listitem_T *li;
+	linenr_T    nr;
+
+	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");
+	    if (nr >= lnum || nr > lnume)
+	    {
+		if (li->li_next == NULL && lnum == nr
+			&& col + 1 == (colnr_T)dict_get_number(
+				      li->li_tv.vval.v_dict, (char_u *)"col"))
+		{
+		    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 TRUE;
+		    }
+		}
+		else
+		{
+		    // the current change is going to make the line number in
+		    // the older change invalid, flush now
+		    invoke_listeners(curbuf);
+		    break;
+		}
+	    }
+	}
+    }
+    return FALSE;
+}
+
+/*
  * Record a change for listeners added with listener_add().
+ * Always for the current buffer.
  */
     static void
 may_record_change(
@@ -172,50 +233,16 @@
 
     // If the new change is going to change the line numbers in already listed
     // changes, then flush.
-    if (recorded_changes != NULL && xtra != 0)
+    if (check_recorded_changes(curbuf, lnum, col, lnume, xtra, TRUE))
+	return;
+
+    if (curbuf->b_recorded_changes == NULL)
     {
-	listitem_T *li;
-	linenr_T    nr;
-
-	for (li = 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");
-	    if (nr >= lnum || nr > lnume)
-	    {
-		if (li->li_next == NULL && lnum == nr
-			&& 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,
-							(char_u *)"added", -1);
-		    di->di_tv.vval.v_number += xtra;
-		    return;
-		}
-
-		// the current change is going to make the line number in the
-		// older change invalid, flush now
-		invoke_listeners(curbuf);
-		break;
-	    }
-	}
-    }
-
-    if (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 @@
     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 @@
 }
 
 /*
+ * 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 @@
     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 @@
     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 @@
     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 @@
     }
 
     --textlock;
-    list_unref(recorded_changes);
-    recorded_changes = NULL;
+    list_unref(buf->b_recorded_changes);
+    buf->b_recorded_changes = NULL;
 }
 #endif