]> granicus.if.org Git - vim/commitdiff
patch 8.1.1320: it is not possible to track changes to a buffer v8.1.1320
authorBram Moolenaar <Bram@vim.org>
Sat, 11 May 2019 17:14:16 +0000 (19:14 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 11 May 2019 17:14:16 +0000 (19:14 +0200)
Problem:    It is not possible to track changes to a buffer.
Solution:   Add listener_add() and listener_remove(). No docs or tests yet.

src/change.c
src/proto/change.pro
src/structs.h
src/version.c

index 750634b26e85a0bc12eac6d414f50ee7ab7eed98..06d20f4ac26979b9d7b629dabfa795265a023af9 100644 (file)
@@ -151,6 +151,134 @@ changed_internal(void)
 #endif
 }
 
+#ifdef FEAT_EVAL
+static list_T *recorded_changes = NULL;
+static long next_listener_id = 0;
+
+/*
+ * Record a change for listeners added with listener_add().
+ */
+    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 (recorded_changes == NULL)
+    {
+       recorded_changes = list_alloc();
+       if (recorded_changes == NULL)  // out of memory
+           return;
+       ++recorded_changes->lv_refcount;
+       recorded_changes->lv_lock = VAR_FIXED;
+    }
+
+    dict = dict_alloc();
+    if (dict == NULL)
+       return;
+    dict_add_number(dict, "lnum", (varnumber_T)lnum);
+    dict_add_number(dict, "end", (varnumber_T)lnume);
+    dict_add_number(dict, "added", (varnumber_T)xtra);
+    dict_add_number(dict, "col", (varnumber_T)col);
+
+    list_append_dict(recorded_changes, dict);
+}
+
+/*
+ * listener_add() function
+ */
+    void
+f_listener_add(typval_T *argvars, typval_T *rettv)
+{
+    char_u     *callback;
+    partial_T  *partial;
+    listener_T *lnr;
+
+    callback = get_callback(&argvars[0], &partial);
+    if (callback == NULL)
+       return;
+
+    lnr = (listener_T *)alloc_clear((sizeof(listener_T)));
+    if (lnr == NULL)
+    {
+       free_callback(callback, partial);
+       return;
+    }
+    lnr->lr_next = curbuf->b_listener;
+    curbuf->b_listener = lnr;
+
+    if (partial == NULL)
+       lnr->lr_callback = vim_strsave(callback);
+    else
+       lnr->lr_callback = callback;  // pointer into the partial
+    lnr->lr_partial = partial;
+
+    lnr->lr_id = ++next_listener_id;
+    rettv->vval.v_number = lnr->lr_id;
+}
+
+/*
+ * listener_remove() function
+ */
+    void
+f_listener_remove(typval_T *argvars, typval_T *rettv UNUSED)
+{
+    listener_T *lnr;
+    listener_T *next;
+    listener_T *prev = NULL;
+    int                id = tv_get_number(argvars);
+    buf_T      *buf = curbuf;
+
+    for (lnr = buf->b_listener; lnr != NULL; lnr = next)
+    {
+       next = lnr->lr_next;
+       if (lnr->lr_id == id)
+       {
+           if (prev != NULL)
+               prev->lr_next = lnr->lr_next;
+           else
+               buf->b_listener = lnr->lr_next;
+           free_callback(lnr->lr_callback, lnr->lr_partial);
+           vim_free(lnr);
+       }
+       prev = lnr;
+    }
+}
+
+/*
+ * Called when a sequence of changes is done: invoke listeners added with
+ * listener_add().
+ */
+    void
+invoke_listeners(void)
+{
+    listener_T *lnr;
+    typval_T   rettv;
+    int                dummy;
+    typval_T   argv[2];
+
+    if (recorded_changes == NULL)  // nothing changed
+       return;
+    argv[0].v_type = VAR_LIST;
+    argv[0].vval.v_list = recorded_changes;
+
+    for (lnr = curbuf->b_listener; lnr != NULL; lnr = lnr->lr_next)
+    {
+       call_func(lnr->lr_callback, -1, &rettv,
+                  1, argv, NULL, 0L, 0L, &dummy, TRUE, lnr->lr_partial, NULL);
+       clear_tv(&rettv);
+    }
+
+    list_unref(recorded_changes);
+    recorded_changes = NULL;
+}
+#endif
+
 /*
  * Common code for when a change was made.
  * See changed_lines() for the arguments.
@@ -175,6 +303,9 @@ changed_common(
     // mark the buffer as modified
     changed();
 
+#ifdef FEAT_EVAL
+    may_record_change(lnum, col, lnume, xtra);
+#endif
 #ifdef FEAT_DIFF
     if (curwin->w_p_diff && diff_internal())
        curtab->tp_diff_update = TRUE;
index 34733f502a72e1ff3216bcf41ed6701072f42d13..4e8a1e64c79c829099734374239fabe5bd7005b4 100644 (file)
@@ -2,6 +2,9 @@
 void change_warning(int col);
 void changed(void);
 void changed_internal(void);
+void f_listener_add(typval_T *argvars, typval_T *rettv);
+void f_listener_remove(typval_T *argvars, typval_T *rettv);
+void invoke_listeners(void);
 void changed_bytes(linenr_T lnum, colnr_T col);
 void inserted_bytes(linenr_T lnum, colnr_T col, int added);
 void appended_lines(linenr_T lnum, long count);
index 16e5ce3da81223e031a13950872cb99a5304c5eb..36bdf9a53ee7ffba632672c5c3155e501bbe4f83 100644 (file)
@@ -1873,6 +1873,19 @@ typedef struct
 #endif
 } jobopt_T;
 
+#ifdef FEAT_EVAL
+/*
+ * Structure used for listeners added with listener_add().
+ */
+typedef struct listener_S listener_T;
+struct listener_S
+{
+    listener_T *lr_next;
+    int                lr_id;
+    char_u     *lr_callback;
+    partial_T  *lr_partial;
+};
+#endif
 
 /* structure used for explicit stack while garbage collecting hash tables */
 typedef struct ht_stack_S
@@ -2424,6 +2437,8 @@ struct file_buffer
 #ifdef FEAT_EVAL
     dictitem_T b_bufvar;       /* variable for "b:" Dictionary */
     dict_T     *b_vars;        /* internal variables, local to buffer */
+
+    listener_T *b_listener;
 #endif
 #ifdef FEAT_TEXT_PROP
     int                b_has_textprop; // TRUE when text props were added
index 7bcb8c87350922eb0756c09c88cbe3c607a047e3..1829fa338ab3bf970f40ac13d0c95c5de623801f 100644 (file)
@@ -767,6 +767,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1320,
 /**/
     1319,
 /**/