Skip to content

Commit

Permalink
patch 8.1.1320: it is not possible to track changes to a buffer
Browse files Browse the repository at this point in the history
Problem:    It is not possible to track changes to a buffer.
Solution:   Add listener_add() and listener_remove(). No docs or tests yet.
  • Loading branch information
brammool committed May 11, 2019
1 parent 6ed8819 commit 6d2399b
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 0 deletions.
131 changes: 131 additions & 0 deletions src/change.c
Expand Up @@ -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.
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/proto/change.pro
Expand Up @@ -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);
Expand Down
15 changes: 15 additions & 0 deletions src/structs.h
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Expand Up @@ -767,6 +767,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1320,
/**/
1319,
/**/
Expand Down

0 comments on commit 6d2399b

Please sign in to comment.