summaryrefslogtreecommitdiffstats
path: root/src/ex_cmds2.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-03-15 23:10:59 +0100
committerBram Moolenaar <Bram@vim.org>2016-03-15 23:10:59 +0100
commit975b5271eed4fa0500c24a8f37be0b1797cb9db7 (patch)
treee2f73f9ae91f1fce55de8757dc1599fcc169c3fe /src/ex_cmds2.c
parentab1fa3955f25dfdb7e329c3bd76e175c93c8cb5e (diff)
patch 7.4.1578v7.4.1578
Problem: There is no way to invoke a function later or periodically. Solution: Add timer support.
Diffstat (limited to 'src/ex_cmds2.c')
-rw-r--r--src/ex_cmds2.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index d7bf60901e..018f44cc29 100644
--- 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>