diff src/ex_cmds2.c @ 8577:63dc856bd13d v7.4.1578

commit https://github.com/vim/vim/commit/975b5271eed4fa0500c24a8f37be0b1797cb9db7 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Mar 15 23:10:59 2016 +0100 patch 7.4.1578 Problem: There is no way to invoke a function later or periodically. Solution: Add timer support.
author Christian Brabandt <cb@256bit.org>
date Tue, 15 Mar 2016 23:15:05 +0100
parents 981cc3bef9f3
children fb8d7086e99d
line wrap: on
line diff
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -1088,6 +1088,174 @@ profile_zero(proftime_T *tm)
 
 # endif  /* FEAT_PROFILE || FEAT_RELTIME */
 
+# if defined(FEAT_TIMERS) || defined(PROTO)
+static timer_T	*first_timer = NULL;
+static int	last_timer_id = 0;
+
+/*
+ * Insert a timer in the list of timers.
+ */
+    static void
+insert_timer(timer_T *timer)
+{
+    timer->tr_next = first_timer;
+    timer->tr_prev = NULL;
+    if (first_timer != NULL)
+	first_timer->tr_prev = timer;
+    first_timer = timer;
+}
+
+/*
+ * Take a timer out of the list of timers.
+ */
+    static void
+remove_timer(timer_T *timer)
+{
+    if (timer->tr_prev == NULL)
+	first_timer = timer->tr_next;
+    else
+	timer->tr_prev->tr_next = timer->tr_next;
+    if (timer->tr_next != NULL)
+	timer->tr_next->tr_prev = timer->tr_prev;
+}
+
+    static void
+free_timer(timer_T *timer)
+{
+    vim_free(timer->tr_callback);
+    partial_unref(timer->tr_partial);
+    vim_free(timer);
+}
+
+/*
+ * Create a timer and return it.  NULL if out of memory.
+ * Caller should set the callback.
+ */
+    timer_T *
+create_timer(long msec, int repeat)
+{
+    timer_T	*timer = (timer_T *)alloc_clear(sizeof(timer_T));
+
+    if (timer == NULL)
+	return NULL;
+    timer->tr_id = ++last_timer_id;
+    insert_timer(timer);
+    if (repeat != 0)
+    {
+	timer->tr_repeat = repeat - 1;
+	timer->tr_interval = msec;
+    }
+
+    profile_setlimit(msec, &timer->tr_due);
+    return timer;
+}
+
+/*
+ * Invoke the callback of "timer".
+ */
+    static void
+timer_callback(timer_T *timer)
+{
+    typval_T	rettv;
+    int		dummy;
+    typval_T	argv[2];
+
+    argv[0].v_type = VAR_NUMBER;
+    argv[0].vval.v_number = timer->tr_id;
+    argv[1].v_type = VAR_UNKNOWN;
+
+    call_func(timer->tr_callback, (int)STRLEN(timer->tr_callback),
+			&rettv, 1, argv, 0L, 0L, &dummy, TRUE,
+			timer->tr_partial, NULL);
+    clear_tv(&rettv);
+}
+
+/*
+ * Call timers that are due.
+ * Return the time in msec until the next timer is due.
+ */
+    long
+check_due_timer()
+{
+    timer_T	*timer;
+    long	this_due;
+    long	next_due;
+    proftime_T	now;
+    int		did_one = FALSE;
+# ifdef WIN3264
+    LARGE_INTEGER   fr;
+
+    QueryPerformanceFrequency(&fr);
+# endif
+    while (!got_int)
+    {
+	profile_start(&now);
+	next_due = -1;
+	for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+	{
+# ifdef WIN3264
+	    this_due = (long)(((double)(timer->tr_due.QuadPart - now.QuadPart)
+					       / (double)fr.QuadPart) * 1000);
+# else
+	    this_due = (timer->tr_due.tv_sec - now.tv_sec) * 1000
+			       + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
+# endif
+	    if (this_due <= 1)
+	    {
+		remove_timer(timer);
+		timer_callback(timer);
+		did_one = TRUE;
+		if (timer->tr_repeat != 0)
+		{
+		    profile_setlimit(timer->tr_interval, &timer->tr_due);
+		    if (timer->tr_repeat > 0)
+			--timer->tr_repeat;
+		    insert_timer(timer);
+		}
+		else
+		    free_timer(timer);
+		/* the callback may do anything, start all over */
+		break;
+	    }
+	    if (next_due == -1 || next_due > this_due)
+		next_due = this_due;
+	}
+	if (timer == NULL)
+	    break;
+    }
+
+    if (did_one)
+	redraw_after_callback();
+
+    return next_due;
+}
+
+/*
+ * Find a timer by ID.  Returns NULL if not found;
+ */
+    timer_T *
+find_timer(int id)
+{
+    timer_T *timer;
+
+    for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+	if (timer->tr_id == id)
+	    break;
+    return timer;
+}
+
+
+/*
+ * Stop a timer and delete it.
+ */
+    void
+stop_timer(timer_T *timer)
+{
+    remove_timer(timer);
+    free_timer(timer);
+}
+# endif
+
 #if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)
 # if defined(HAVE_MATH_H)
 #  include <math.h>