• R/O
  • SSH

vim: Commit

Mirror of the Vim source from https://github.com/vim/vim


Commit MetaInfo

Revisãoa961efb326e524be4db58a920d9eb829bb52eb68 (tree)
Hora2020-02-14 21:30:05
AutorBram Moolenaar <Bram@vim....>
CommiterBram Moolenaar

Mensagem de Log

patch 8.2.0256: time and timer related code is spread out

Commit: https://github.com/vim/vim/commit/0a8fed6231c84e4e1b3a7dd6c0d95d3f98207fe0
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Feb 14 13:22:17 2020 +0100

patch 8.2.0256: time and timer related code is spread out
Problem: Time and timer related code is spread out.
Solution: Move time and timer related code to a new file. (Yegappan
Lakshmanan, closes #5604)

Mudança Sumário

Diff

diff -r eb5ef6f5f58b -r a961efb326e5 Filelist
--- a/Filelist Thu Feb 13 22:00:04 2020 +0100
+++ b/Filelist Fri Feb 14 13:30:05 2020 +0100
@@ -127,6 +127,7 @@
127127 src/termlib.c \
128128 src/testing.c \
129129 src/textprop.c \
130+ src/time.c \
130131 src/ui.c \
131132 src/undo.c \
132133 src/usercmd.c \
@@ -275,6 +276,7 @@
275276 src/proto/termlib.pro \
276277 src/proto/testing.pro \
277278 src/proto/textprop.pro \
279+ src/proto/time.pro \
278280 src/proto/ui.pro \
279281 src/proto/undo.pro \
280282 src/proto/usercmd.pro \
diff -r eb5ef6f5f58b -r a961efb326e5 src/Make_cyg_ming.mak
--- a/src/Make_cyg_ming.mak Thu Feb 13 22:00:04 2020 +0100
+++ b/src/Make_cyg_ming.mak Fri Feb 14 13:30:05 2020 +0100
@@ -783,6 +783,7 @@
783783 $(OUTDIR)/term.o \
784784 $(OUTDIR)/testing.o \
785785 $(OUTDIR)/textprop.o \
786+ $(OUTDIR)/time.o \
786787 $(OUTDIR)/ui.o \
787788 $(OUTDIR)/undo.o \
788789 $(OUTDIR)/usercmd.o \
diff -r eb5ef6f5f58b -r a961efb326e5 src/Make_morph.mak
--- a/src/Make_morph.mak Thu Feb 13 22:00:04 2020 +0100
+++ b/src/Make_morph.mak Fri Feb 14 13:30:05 2020 +0100
@@ -102,6 +102,7 @@
102102 term.c \
103103 testing.c \
104104 textprop.c \
105+ time.c \
105106 ui.c \
106107 undo.c \
107108 usercmd.c \
diff -r eb5ef6f5f58b -r a961efb326e5 src/Make_mvc.mak
--- a/src/Make_mvc.mak Thu Feb 13 22:00:04 2020 +0100
+++ b/src/Make_mvc.mak Fri Feb 14 13:30:05 2020 +0100
@@ -799,6 +799,7 @@
799799 $(OUTDIR)\term.obj \
800800 $(OUTDIR)\testing.obj \
801801 $(OUTDIR)\textprop.obj \
802+ $(OUTDIR)\time.obj \
802803 $(OUTDIR)\ui.obj \
803804 $(OUTDIR)\undo.obj \
804805 $(OUTDIR)\usercmd.obj \
@@ -1733,6 +1734,8 @@
17331734
17341735 $(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL)
17351736
1737+$(OUTDIR)/time.obj: $(OUTDIR) time.c $(INCL)
1738+
17361739 $(OUTDIR)/ui.obj: $(OUTDIR) ui.c $(INCL)
17371740
17381741 $(OUTDIR)/undo.obj: $(OUTDIR) undo.c $(INCL)
@@ -1926,6 +1929,7 @@
19261929 proto/term.pro \
19271930 proto/testing.pro \
19281931 proto/textprop.pro \
1932+ proto/time.pro \
19291933 proto/ui.pro \
19301934 proto/undo.pro \
19311935 proto/usercmd.pro \
diff -r eb5ef6f5f58b -r a961efb326e5 src/Make_vms.mms
--- a/src/Make_vms.mms Thu Feb 13 22:00:04 2020 +0100
+++ b/src/Make_vms.mms Fri Feb 14 13:30:05 2020 +0100
@@ -381,6 +381,7 @@
381381 termlib.c \
382382 testing.c \
383383 textprop.c \
384+ time.c \
384385 ui.c \
385386 undo.c \
386387 usercmd.c \
@@ -487,6 +488,7 @@
487488 termlib.obj \
488489 testing.obj \
489490 textprop.obj \
491+ time.obj \
490492 ui.obj \
491493 undo.obj \
492494 usercmd.obj \
@@ -978,6 +980,9 @@
978980 textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \
979981 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
980982 [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
983+time.obj : time.c vim.h [.auto]config.h feature.h os_unix.h \
984+ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
985+ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
981986 ui.obj : ui.c vim.h [.auto]config.h feature.h os_unix.h \
982987 ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
983988 [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h
diff -r eb5ef6f5f58b -r a961efb326e5 src/Makefile
--- a/src/Makefile Thu Feb 13 22:00:04 2020 +0100
+++ b/src/Makefile Fri Feb 14 13:30:05 2020 +0100
@@ -1661,6 +1661,7 @@
16611661 terminal.c \
16621662 testing.c \
16631663 textprop.c \
1664+ time.c \
16641665 ui.c \
16651666 undo.c \
16661667 usercmd.c \
@@ -1800,6 +1801,7 @@
18001801 objects/terminal.o \
18011802 objects/testing.o \
18021803 objects/textprop.o \
1804+ objects/time.o \
18031805 objects/ui.o \
18041806 objects/undo.o \
18051807 objects/usercmd.o \
@@ -1971,6 +1973,7 @@
19711973 termlib.pro \
19721974 testing.pro \
19731975 textprop.pro \
1976+ time.pro \
19741977 ui.pro \
19751978 undo.pro \
19761979 usercmd.pro \
@@ -3433,6 +3436,9 @@
34333436 objects/textprop.o: textprop.c
34343437 $(CCC) -o $@ textprop.c
34353438
3439+objects/time.o: time.c
3440+ $(CCC) -o $@ time.c
3441+
34363442 objects/ui.o: ui.c
34373443 $(CCC) -o $@ ui.c
34383444
@@ -3959,6 +3965,10 @@
39593965 auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
39603966 proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
39613967 proto.h globals.h
3968+objects/time.o: time.c vim.h protodef.h auto/config.h feature.h os_unix.h \
3969+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
3970+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
3971+ proto.h globals.h
39623972 objects/ui.o: ui.c vim.h protodef.h auto/config.h feature.h os_unix.h \
39633973 auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
39643974 proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
diff -r eb5ef6f5f58b -r a961efb326e5 src/README.md
--- a/src/README.md Thu Feb 13 22:00:04 2020 +0100
+++ b/src/README.md Fri Feb 14 13:30:05 2020 +0100
@@ -79,6 +79,7 @@
7979 term.c | terminal handling, termcap codes
8080 testing.c | testing: assert and test functions
8181 textprop.c | text properties
82+time.c | time and timer functions
8283 undo.c | undo and redo
8384 usercmd.c | user defined commands
8485 userfunc.c | user defined functions
diff -r eb5ef6f5f58b -r a961efb326e5 src/evalfunc.c
--- a/src/evalfunc.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/evalfunc.c Fri Feb 14 13:30:05 2020 +0100
@@ -20,10 +20,6 @@
2020 # include <float.h>
2121 #endif
2222
23-#if defined(MACOS_X)
24-# include <time.h> // for time_t
25-#endif
26-
2723 #ifdef FEAT_FLOAT
2824 static void f_abs(typval_T *argvars, typval_T *rettv);
2925 static void f_acos(typval_T *argvars, typval_T *rettv);
@@ -126,7 +122,6 @@
126122 static void f_libcallnr(typval_T *argvars, typval_T *rettv);
127123 static void f_line(typval_T *argvars, typval_T *rettv);
128124 static void f_line2byte(typval_T *argvars, typval_T *rettv);
129-static void f_localtime(typval_T *argvars, typval_T *rettv);
130125 #ifdef FEAT_FLOAT
131126 static void f_log(typval_T *argvars, typval_T *rettv);
132127 static void f_log10(typval_T *argvars, typval_T *rettv);
@@ -173,11 +168,6 @@
173168 static void f_range(typval_T *argvars, typval_T *rettv);
174169 static void f_reg_executing(typval_T *argvars, typval_T *rettv);
175170 static void f_reg_recording(typval_T *argvars, typval_T *rettv);
176-static void f_reltime(typval_T *argvars, typval_T *rettv);
177-#ifdef FEAT_FLOAT
178-static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
179-#endif
180-static void f_reltimestr(typval_T *argvars, typval_T *rettv);
181171 static void f_remote_expr(typval_T *argvars, typval_T *rettv);
182172 static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
183173 static void f_remote_peek(typval_T *argvars, typval_T *rettv);
@@ -234,17 +224,11 @@
234224 static void f_str2list(typval_T *argvars, typval_T *rettv);
235225 static void f_str2nr(typval_T *argvars, typval_T *rettv);
236226 static void f_strchars(typval_T *argvars, typval_T *rettv);
237-#ifdef HAVE_STRFTIME
238-static void f_strftime(typval_T *argvars, typval_T *rettv);
239-#endif
240227 static void f_strgetchar(typval_T *argvars, typval_T *rettv);
241228 static void f_stridx(typval_T *argvars, typval_T *rettv);
242229 static void f_strlen(typval_T *argvars, typval_T *rettv);
243230 static void f_strcharpart(typval_T *argvars, typval_T *rettv);
244231 static void f_strpart(typval_T *argvars, typval_T *rettv);
245-#ifdef HAVE_STRPTIME
246-static void f_strptime(typval_T *argvars, typval_T *rettv);
247-#endif
248232 static void f_strridx(typval_T *argvars, typval_T *rettv);
249233 static void f_strtrans(typval_T *argvars, typval_T *rettv);
250234 static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
@@ -4512,15 +4496,6 @@
45124496 #endif
45134497 }
45144498
4515-/*
4516- * "localtime()" function
4517- */
4518- static void
4519-f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4520-{
4521- rettv->vval.v_number = (varnumber_T)time(NULL);
4522-}
4523-
45244499 #ifdef FEAT_FLOAT
45254500 /*
45264501 * "log()" function
@@ -5500,118 +5475,6 @@
55005475 return_register(reg_recording, rettv);
55015476 }
55025477
5503-#if defined(FEAT_RELTIME)
5504-/*
5505- * Convert a List to proftime_T.
5506- * Return FAIL when there is something wrong.
5507- */
5508- static int
5509-list2proftime(typval_T *arg, proftime_T *tm)
5510-{
5511- long n1, n2;
5512- int error = FALSE;
5513-
5514- if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5515- || arg->vval.v_list->lv_len != 2)
5516- return FAIL;
5517- n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5518- n2 = list_find_nr(arg->vval.v_list, 1L, &error);
5519-# ifdef MSWIN
5520- tm->HighPart = n1;
5521- tm->LowPart = n2;
5522-# else
5523- tm->tv_sec = n1;
5524- tm->tv_usec = n2;
5525-# endif
5526- return error ? FAIL : OK;
5527-}
5528-#endif // FEAT_RELTIME
5529-
5530-/*
5531- * "reltime()" function
5532- */
5533- static void
5534-f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5535-{
5536-#ifdef FEAT_RELTIME
5537- proftime_T res;
5538- proftime_T start;
5539-
5540- if (argvars[0].v_type == VAR_UNKNOWN)
5541- {
5542- // No arguments: get current time.
5543- profile_start(&res);
5544- }
5545- else if (argvars[1].v_type == VAR_UNKNOWN)
5546- {
5547- if (list2proftime(&argvars[0], &res) == FAIL)
5548- return;
5549- profile_end(&res);
5550- }
5551- else
5552- {
5553- // Two arguments: compute the difference.
5554- if (list2proftime(&argvars[0], &start) == FAIL
5555- || list2proftime(&argvars[1], &res) == FAIL)
5556- return;
5557- profile_sub(&res, &start);
5558- }
5559-
5560- if (rettv_list_alloc(rettv) == OK)
5561- {
5562- long n1, n2;
5563-
5564-# ifdef MSWIN
5565- n1 = res.HighPart;
5566- n2 = res.LowPart;
5567-# else
5568- n1 = res.tv_sec;
5569- n2 = res.tv_usec;
5570-# endif
5571- list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5572- list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5573- }
5574-#endif
5575-}
5576-
5577-#ifdef FEAT_FLOAT
5578-/*
5579- * "reltimefloat()" function
5580- */
5581- static void
5582-f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5583-{
5584-# ifdef FEAT_RELTIME
5585- proftime_T tm;
5586-# endif
5587-
5588- rettv->v_type = VAR_FLOAT;
5589- rettv->vval.v_float = 0;
5590-# ifdef FEAT_RELTIME
5591- if (list2proftime(&argvars[0], &tm) == OK)
5592- rettv->vval.v_float = profile_float(&tm);
5593-# endif
5594-}
5595-#endif
5596-
5597-/*
5598- * "reltimestr()" function
5599- */
5600- static void
5601-f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5602-{
5603-#ifdef FEAT_RELTIME
5604- proftime_T tm;
5605-#endif
5606-
5607- rettv->v_type = VAR_STRING;
5608- rettv->vval.v_string = NULL;
5609-#ifdef FEAT_RELTIME
5610- if (list2proftime(&argvars[0], &tm) == OK)
5611- rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5612-#endif
5613-}
5614-
56155478 #if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
56165479 static void
56175480 make_connection(void)
@@ -7422,61 +7285,6 @@
74227285
74237286 }
74247287
7425-#ifdef HAVE_STRFTIME
7426-/*
7427- * "strftime({format}[, {time}])" function
7428- */
7429- static void
7430-f_strftime(typval_T *argvars, typval_T *rettv)
7431-{
7432- char_u result_buf[256];
7433- struct tm tmval;
7434- struct tm *curtime;
7435- time_t seconds;
7436- char_u *p;
7437-
7438- rettv->v_type = VAR_STRING;
7439-
7440- p = tv_get_string(&argvars[0]);
7441- if (argvars[1].v_type == VAR_UNKNOWN)
7442- seconds = time(NULL);
7443- else
7444- seconds = (time_t)tv_get_number(&argvars[1]);
7445- curtime = vim_localtime(&seconds, &tmval);
7446- // MSVC returns NULL for an invalid value of seconds.
7447- if (curtime == NULL)
7448- rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7449- else
7450- {
7451- vimconv_T conv;
7452- char_u *enc;
7453-
7454- conv.vc_type = CONV_NONE;
7455- enc = enc_locale();
7456- convert_setup(&conv, p_enc, enc);
7457- if (conv.vc_type != CONV_NONE)
7458- p = string_convert(&conv, p, NULL);
7459- if (p != NULL)
7460- (void)strftime((char *)result_buf, sizeof(result_buf),
7461- (char *)p, curtime);
7462- else
7463- result_buf[0] = NUL;
7464-
7465- if (conv.vc_type != CONV_NONE)
7466- vim_free(p);
7467- convert_setup(&conv, enc, p_enc);
7468- if (conv.vc_type != CONV_NONE)
7469- rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7470- else
7471- rettv->vval.v_string = vim_strsave(result_buf);
7472-
7473- // Release conversion descriptors
7474- convert_setup(&conv, NULL, NULL);
7475- vim_free(enc);
7476- }
7477-}
7478-#endif
7479-
74807288 /*
74817289 * "strgetchar()" function
74827290 */
@@ -7734,40 +7542,6 @@
77347542 rettv->vval.v_string = vim_strnsave(p + n, len);
77357543 }
77367544
7737-#ifdef HAVE_STRPTIME
7738-/*
7739- * "strptime({format}, {timestring})" function
7740- */
7741- static void
7742-f_strptime(typval_T *argvars, typval_T *rettv)
7743-{
7744- struct tm tmval;
7745- char_u *fmt;
7746- char_u *str;
7747- vimconv_T conv;
7748- char_u *enc;
7749-
7750- vim_memset(&tmval, NUL, sizeof(tmval));
7751- fmt = tv_get_string(&argvars[0]);
7752- str = tv_get_string(&argvars[1]);
7753-
7754- conv.vc_type = CONV_NONE;
7755- enc = enc_locale();
7756- convert_setup(&conv, p_enc, enc);
7757- if (conv.vc_type != CONV_NONE)
7758- fmt = string_convert(&conv, fmt, NULL);
7759- if (fmt == NULL
7760- || strptime((char *)str, (char *)fmt, &tmval) == NULL
7761- || (rettv->vval.v_number = mktime(&tmval)) == -1)
7762- rettv->vval.v_number = 0;
7763-
7764- if (conv.vc_type != CONV_NONE)
7765- vim_free(fmt);
7766- convert_setup(&conv, NULL, NULL);
7767- vim_free(enc);
7768-}
7769-#endif
7770-
77717545 /*
77727546 * "strridx()" function
77737547 */
diff -r eb5ef6f5f58b -r a961efb326e5 src/ex_cmds.c
--- a/src/ex_cmds.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/ex_cmds.c Fri Feb 14 13:30:05 2020 +0100
@@ -1679,20 +1679,6 @@
16791679 }
16801680
16811681 /*
1682- * Return the current time in seconds. Calls time(), unless test_settime()
1683- * was used.
1684- */
1685- time_T
1686-vim_time(void)
1687-{
1688-# ifdef FEAT_EVAL
1689- return time_for_testing == 0 ? time(NULL) : time_for_testing;
1690-# else
1691- return time(NULL);
1692-# endif
1693-}
1694-
1695-/*
16961682 * Implementation of ":fixdel", also used by get_stty().
16971683 * <BS> resulting <Del>
16981684 * ^? ^H
diff -r eb5ef6f5f58b -r a961efb326e5 src/ex_cmds2.c
--- a/src/ex_cmds2.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/ex_cmds2.c Fri Feb 14 13:30:05 2020 +0100
@@ -14,498 +14,6 @@
1414 #include "vim.h"
1515 #include "version.h"
1616
17-#if defined(FEAT_EVAL) || defined(PROTO)
18-# if defined(FEAT_TIMERS) || defined(PROTO)
19-static timer_T *first_timer = NULL;
20-static long last_timer_id = 0;
21-
22-/*
23- * Return time left until "due". Negative if past "due".
24- */
25- long
26-proftime_time_left(proftime_T *due, proftime_T *now)
27-{
28-# ifdef MSWIN
29- LARGE_INTEGER fr;
30-
31- if (now->QuadPart > due->QuadPart)
32- return 0;
33- QueryPerformanceFrequency(&fr);
34- return (long)(((double)(due->QuadPart - now->QuadPart)
35- / (double)fr.QuadPart) * 1000);
36-# else
37- if (now->tv_sec > due->tv_sec)
38- return 0;
39- return (due->tv_sec - now->tv_sec) * 1000
40- + (due->tv_usec - now->tv_usec) / 1000;
41-# endif
42-}
43-
44-/*
45- * Insert a timer in the list of timers.
46- */
47- static void
48-insert_timer(timer_T *timer)
49-{
50- timer->tr_next = first_timer;
51- timer->tr_prev = NULL;
52- if (first_timer != NULL)
53- first_timer->tr_prev = timer;
54- first_timer = timer;
55- did_add_timer = TRUE;
56-}
57-
58-/*
59- * Take a timer out of the list of timers.
60- */
61- static void
62-remove_timer(timer_T *timer)
63-{
64- if (timer->tr_prev == NULL)
65- first_timer = timer->tr_next;
66- else
67- timer->tr_prev->tr_next = timer->tr_next;
68- if (timer->tr_next != NULL)
69- timer->tr_next->tr_prev = timer->tr_prev;
70-}
71-
72- static void
73-free_timer(timer_T *timer)
74-{
75- free_callback(&timer->tr_callback);
76- vim_free(timer);
77-}
78-
79-/*
80- * Create a timer and return it. NULL if out of memory.
81- * Caller should set the callback.
82- */
83- timer_T *
84-create_timer(long msec, int repeat)
85-{
86- timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
87- long prev_id = last_timer_id;
88-
89- if (timer == NULL)
90- return NULL;
91- if (++last_timer_id <= prev_id)
92- // Overflow! Might cause duplicates...
93- last_timer_id = 0;
94- timer->tr_id = last_timer_id;
95- insert_timer(timer);
96- if (repeat != 0)
97- timer->tr_repeat = repeat - 1;
98- timer->tr_interval = msec;
99-
100- profile_setlimit(msec, &timer->tr_due);
101- return timer;
102-}
103-
104-/*
105- * Invoke the callback of "timer".
106- */
107- static void
108-timer_callback(timer_T *timer)
109-{
110- typval_T rettv;
111- typval_T argv[2];
112-
113- argv[0].v_type = VAR_NUMBER;
114- argv[0].vval.v_number = (varnumber_T)timer->tr_id;
115- argv[1].v_type = VAR_UNKNOWN;
116-
117- call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
118- clear_tv(&rettv);
119-}
120-
121-/*
122- * Call timers that are due.
123- * Return the time in msec until the next timer is due.
124- * Returns -1 if there are no pending timers.
125- */
126- long
127-check_due_timer(void)
128-{
129- timer_T *timer;
130- timer_T *timer_next;
131- long this_due;
132- long next_due = -1;
133- proftime_T now;
134- int did_one = FALSE;
135- int need_update_screen = FALSE;
136- long current_id = last_timer_id;
137-
138- // Don't run any timers while exiting or dealing with an error.
139- if (exiting || aborting())
140- return next_due;
141-
142- profile_start(&now);
143- for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
144- {
145- timer_next = timer->tr_next;
146-
147- if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
148- continue;
149- this_due = proftime_time_left(&timer->tr_due, &now);
150- if (this_due <= 1)
151- {
152- // Save and restore a lot of flags, because the timer fires while
153- // waiting for a character, which might be halfway a command.
154- int save_timer_busy = timer_busy;
155- int save_vgetc_busy = vgetc_busy;
156- int save_did_emsg = did_emsg;
157- int save_called_emsg = called_emsg;
158- int save_must_redraw = must_redraw;
159- int save_trylevel = trylevel;
160- int save_did_throw = did_throw;
161- int save_ex_pressedreturn = get_pressedreturn();
162- int save_may_garbage_collect = may_garbage_collect;
163- except_T *save_current_exception = current_exception;
164- vimvars_save_T vvsave;
165-
166- // Create a scope for running the timer callback, ignoring most of
167- // the current scope, such as being inside a try/catch.
168- timer_busy = timer_busy > 0 || vgetc_busy > 0;
169- vgetc_busy = 0;
170- called_emsg = 0;
171- did_emsg = FALSE;
172- did_uncaught_emsg = FALSE;
173- must_redraw = 0;
174- trylevel = 0;
175- did_throw = FALSE;
176- current_exception = NULL;
177- may_garbage_collect = FALSE;
178- save_vimvars(&vvsave);
179-
180- timer->tr_firing = TRUE;
181- timer_callback(timer);
182- timer->tr_firing = FALSE;
183-
184- timer_next = timer->tr_next;
185- did_one = TRUE;
186- timer_busy = save_timer_busy;
187- vgetc_busy = save_vgetc_busy;
188- if (did_uncaught_emsg)
189- ++timer->tr_emsg_count;
190- did_emsg = save_did_emsg;
191- called_emsg = save_called_emsg;
192- trylevel = save_trylevel;
193- did_throw = save_did_throw;
194- current_exception = save_current_exception;
195- restore_vimvars(&vvsave);
196- if (must_redraw != 0)
197- need_update_screen = TRUE;
198- must_redraw = must_redraw > save_must_redraw
199- ? must_redraw : save_must_redraw;
200- set_pressedreturn(save_ex_pressedreturn);
201- may_garbage_collect = save_may_garbage_collect;
202-
203- // Only fire the timer again if it repeats and stop_timer() wasn't
204- // called while inside the callback (tr_id == -1).
205- if (timer->tr_repeat != 0 && timer->tr_id != -1
206- && timer->tr_emsg_count < 3)
207- {
208- profile_setlimit(timer->tr_interval, &timer->tr_due);
209- this_due = proftime_time_left(&timer->tr_due, &now);
210- if (this_due < 1)
211- this_due = 1;
212- if (timer->tr_repeat > 0)
213- --timer->tr_repeat;
214- }
215- else
216- {
217- this_due = -1;
218- remove_timer(timer);
219- free_timer(timer);
220- }
221- }
222- if (this_due > 0 && (next_due == -1 || next_due > this_due))
223- next_due = this_due;
224- }
225-
226- if (did_one)
227- redraw_after_callback(need_update_screen);
228-
229-#ifdef FEAT_BEVAL_TERM
230- if (bevalexpr_due_set)
231- {
232- this_due = proftime_time_left(&bevalexpr_due, &now);
233- if (this_due <= 1)
234- {
235- bevalexpr_due_set = FALSE;
236- if (balloonEval == NULL)
237- {
238- balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
239- balloonEvalForTerm = TRUE;
240- }
241- if (balloonEval != NULL)
242- {
243- general_beval_cb(balloonEval, 0);
244- setcursor();
245- out_flush();
246- }
247- }
248- else if (next_due == -1 || next_due > this_due)
249- next_due = this_due;
250- }
251-#endif
252-#ifdef FEAT_TERMINAL
253- // Some terminal windows may need their buffer updated.
254- next_due = term_check_timers(next_due, &now);
255-#endif
256-
257- return current_id != last_timer_id ? 1 : next_due;
258-}
259-
260-/*
261- * Find a timer by ID. Returns NULL if not found;
262- */
263- static timer_T *
264-find_timer(long id)
265-{
266- timer_T *timer;
267-
268- if (id >= 0)
269- {
270- for (timer = first_timer; timer != NULL; timer = timer->tr_next)
271- if (timer->tr_id == id)
272- return timer;
273- }
274- return NULL;
275-}
276-
277-
278-/*
279- * Stop a timer and delete it.
280- */
281- void
282-stop_timer(timer_T *timer)
283-{
284- if (timer->tr_firing)
285- // Free the timer after the callback returns.
286- timer->tr_id = -1;
287- else
288- {
289- remove_timer(timer);
290- free_timer(timer);
291- }
292-}
293-
294- static void
295-stop_all_timers(void)
296-{
297- timer_T *timer;
298- timer_T *timer_next;
299-
300- for (timer = first_timer; timer != NULL; timer = timer_next)
301- {
302- timer_next = timer->tr_next;
303- stop_timer(timer);
304- }
305-}
306-
307- static void
308-add_timer_info(typval_T *rettv, timer_T *timer)
309-{
310- list_T *list = rettv->vval.v_list;
311- dict_T *dict = dict_alloc();
312- dictitem_T *di;
313- long remaining;
314- proftime_T now;
315-
316- if (dict == NULL)
317- return;
318- list_append_dict(list, dict);
319-
320- dict_add_number(dict, "id", timer->tr_id);
321- dict_add_number(dict, "time", (long)timer->tr_interval);
322-
323- profile_start(&now);
324- remaining = proftime_time_left(&timer->tr_due, &now);
325- dict_add_number(dict, "remaining", (long)remaining);
326-
327- dict_add_number(dict, "repeat",
328- (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
329- dict_add_number(dict, "paused", (long)(timer->tr_paused));
330-
331- di = dictitem_alloc((char_u *)"callback");
332- if (di != NULL)
333- {
334- if (dict_add(dict, di) == FAIL)
335- vim_free(di);
336- else
337- put_callback(&timer->tr_callback, &di->di_tv);
338- }
339-}
340-
341- static void
342-add_timer_info_all(typval_T *rettv)
343-{
344- timer_T *timer;
345-
346- for (timer = first_timer; timer != NULL; timer = timer->tr_next)
347- if (timer->tr_id != -1)
348- add_timer_info(rettv, timer);
349-}
350-
351-/*
352- * Mark references in partials of timers.
353- */
354- int
355-set_ref_in_timer(int copyID)
356-{
357- int abort = FALSE;
358- timer_T *timer;
359- typval_T tv;
360-
361- for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
362- {
363- if (timer->tr_callback.cb_partial != NULL)
364- {
365- tv.v_type = VAR_PARTIAL;
366- tv.vval.v_partial = timer->tr_callback.cb_partial;
367- }
368- else
369- {
370- tv.v_type = VAR_FUNC;
371- tv.vval.v_string = timer->tr_callback.cb_name;
372- }
373- abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
374- }
375- return abort;
376-}
377-
378-# if defined(EXITFREE) || defined(PROTO)
379- void
380-timer_free_all()
381-{
382- timer_T *timer;
383-
384- while (first_timer != NULL)
385- {
386- timer = first_timer;
387- remove_timer(timer);
388- free_timer(timer);
389- }
390-}
391-# endif
392-
393-/*
394- * "timer_info([timer])" function
395- */
396- void
397-f_timer_info(typval_T *argvars, typval_T *rettv)
398-{
399- timer_T *timer = NULL;
400-
401- if (rettv_list_alloc(rettv) != OK)
402- return;
403- if (argvars[0].v_type != VAR_UNKNOWN)
404- {
405- if (argvars[0].v_type != VAR_NUMBER)
406- emsg(_(e_number_exp));
407- else
408- {
409- timer = find_timer((int)tv_get_number(&argvars[0]));
410- if (timer != NULL)
411- add_timer_info(rettv, timer);
412- }
413- }
414- else
415- add_timer_info_all(rettv);
416-}
417-
418-/*
419- * "timer_pause(timer, paused)" function
420- */
421- void
422-f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
423-{
424- timer_T *timer = NULL;
425- int paused = (int)tv_get_number(&argvars[1]);
426-
427- if (argvars[0].v_type != VAR_NUMBER)
428- emsg(_(e_number_exp));
429- else
430- {
431- timer = find_timer((int)tv_get_number(&argvars[0]));
432- if (timer != NULL)
433- timer->tr_paused = paused;
434- }
435-}
436-
437-/*
438- * "timer_start(time, callback [, options])" function
439- */
440- void
441-f_timer_start(typval_T *argvars, typval_T *rettv)
442-{
443- long msec = (long)tv_get_number(&argvars[0]);
444- timer_T *timer;
445- int repeat = 0;
446- callback_T callback;
447- dict_T *dict;
448-
449- rettv->vval.v_number = -1;
450- if (check_secure())
451- return;
452- if (argvars[2].v_type != VAR_UNKNOWN)
453- {
454- if (argvars[2].v_type != VAR_DICT
455- || (dict = argvars[2].vval.v_dict) == NULL)
456- {
457- semsg(_(e_invarg2), tv_get_string(&argvars[2]));
458- return;
459- }
460- if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
461- repeat = dict_get_number(dict, (char_u *)"repeat");
462- }
463-
464- callback = get_callback(&argvars[1]);
465- if (callback.cb_name == NULL)
466- return;
467-
468- timer = create_timer(msec, repeat);
469- if (timer == NULL)
470- free_callback(&callback);
471- else
472- {
473- set_callback(&timer->tr_callback, &callback);
474- rettv->vval.v_number = (varnumber_T)timer->tr_id;
475- }
476-}
477-
478-/*
479- * "timer_stop(timer)" function
480- */
481- void
482-f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
483-{
484- timer_T *timer;
485-
486- if (argvars[0].v_type != VAR_NUMBER)
487- {
488- emsg(_(e_number_exp));
489- return;
490- }
491- timer = find_timer((int)tv_get_number(&argvars[0]));
492- if (timer != NULL)
493- stop_timer(timer);
494-}
495-
496-/*
497- * "timer_stopall()" function
498- */
499- void
500-f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
501-{
502- stop_all_timers();
503-}
504-
505-# endif // FEAT_TIMERS
506-
507-#endif // FEAT_EVAL
508-
50917 /*
51018 * If 'autowrite' option set, try to write the file.
51119 * Careful: autocommands may make "buf" invalid!
diff -r eb5ef6f5f58b -r a961efb326e5 src/main.c
--- a/src/main.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/main.c Fri Feb 14 13:30:05 2020 +0100
@@ -3669,110 +3669,6 @@
36693669
36703670 #endif // NO_VIM_MAIN
36713671
3672-#if defined(STARTUPTIME) || defined(PROTO)
3673-static struct timeval prev_timeval;
3674-
3675-# ifdef MSWIN
3676-/*
3677- * Windows doesn't have gettimeofday(), although it does have struct timeval.
3678- */
3679- static int
3680-gettimeofday(struct timeval *tv, char *dummy UNUSED)
3681-{
3682- long t = clock();
3683- tv->tv_sec = t / CLOCKS_PER_SEC;
3684- tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
3685- return 0;
3686-}
3687-# endif
3688-
3689-/*
3690- * Save the previous time before doing something that could nest.
3691- * set "*tv_rel" to the time elapsed so far.
3692- */
3693- void
3694-time_push(void *tv_rel, void *tv_start)
3695-{
3696- *((struct timeval *)tv_rel) = prev_timeval;
3697- gettimeofday(&prev_timeval, NULL);
3698- ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
3699- - ((struct timeval *)tv_rel)->tv_usec;
3700- ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
3701- - ((struct timeval *)tv_rel)->tv_sec;
3702- if (((struct timeval *)tv_rel)->tv_usec < 0)
3703- {
3704- ((struct timeval *)tv_rel)->tv_usec += 1000000;
3705- --((struct timeval *)tv_rel)->tv_sec;
3706- }
3707- *(struct timeval *)tv_start = prev_timeval;
3708-}
3709-
3710-/*
3711- * Compute the previous time after doing something that could nest.
3712- * Subtract "*tp" from prev_timeval;
3713- * Note: The arguments are (void *) to avoid trouble with systems that don't
3714- * have struct timeval.
3715- */
3716- void
3717-time_pop(
3718- void *tp) // actually (struct timeval *)
3719-{
3720- prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
3721- prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
3722- if (prev_timeval.tv_usec < 0)
3723- {
3724- prev_timeval.tv_usec += 1000000;
3725- --prev_timeval.tv_sec;
3726- }
3727-}
3728-
3729- static void
3730-time_diff(struct timeval *then, struct timeval *now)
3731-{
3732- long usec;
3733- long msec;
3734-
3735- usec = now->tv_usec - then->tv_usec;
3736- msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
3737- usec = usec % 1000L;
3738- fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
3739-}
3740-
3741- void
3742-time_msg(
3743- char *mesg,
3744- void *tv_start) // only for do_source: start time; actually
3745- // (struct timeval *)
3746-{
3747- static struct timeval start;
3748- struct timeval now;
3749-
3750- if (time_fd != NULL)
3751- {
3752- if (strstr(mesg, "STARTING") != NULL)
3753- {
3754- gettimeofday(&start, NULL);
3755- prev_timeval = start;
3756- fprintf(time_fd, "\n\ntimes in msec\n");
3757- fprintf(time_fd, " clock self+sourced self: sourced script\n");
3758- fprintf(time_fd, " clock elapsed: other lines\n\n");
3759- }
3760- gettimeofday(&now, NULL);
3761- time_diff(&start, &now);
3762- if (((struct timeval *)tv_start) != NULL)
3763- {
3764- fprintf(time_fd, " ");
3765- time_diff(((struct timeval *)tv_start), &now);
3766- }
3767- fprintf(time_fd, " ");
3768- time_diff(&prev_timeval, &now);
3769- prev_timeval = now;
3770- fprintf(time_fd, ": %s\n", mesg);
3771- }
3772-}
3773-
3774-#endif
3775-
37763672 #if !defined(NO_VIM_MAIN) && defined(FEAT_EVAL)
37773673 static void
37783674 set_progpath(char_u *argv0)
diff -r eb5ef6f5f58b -r a961efb326e5 src/memline.c
--- a/src/memline.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/memline.c Fri Feb 14 13:30:05 2020 +0100
@@ -2081,94 +2081,6 @@
20812081 #endif
20822082
20832083 /*
2084- * Cache of the current timezone name as retrieved from TZ, or an empty string
2085- * where unset, up to 64 octets long including trailing null byte.
2086- */
2087-#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
2088-static char tz_cache[64];
2089-#endif
2090-
2091-/*
2092- * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
2093- * latter version preferred for reentrancy.
2094- *
2095- * If we use localtime_r(3) and we have tzset(3) available, check to see if the
2096- * environment variable TZ has changed since the last run, and call tzset(3) to
2097- * update the global timezone variables if it has. This is because the POSIX
2098- * standard doesn't require localtime_r(3) implementations to do that as it
2099- * does with localtime(3), and we don't want to call tzset(3) every time.
2100- */
2101- struct tm *
2102-vim_localtime(
2103- const time_t *timep, // timestamp for local representation
2104- struct tm *result UNUSED) // pointer to caller return buffer
2105-{
2106-#ifdef HAVE_LOCALTIME_R
2107-# ifdef HAVE_TZSET
2108- char *tz; // pointer for TZ environment var
2109-
2110- tz = (char *)mch_getenv((char_u *)"TZ");
2111- if (tz == NULL)
2112- tz = "";
2113- if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
2114- {
2115- tzset();
2116- vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
2117- }
2118-# endif // HAVE_TZSET
2119- return localtime_r(timep, result);
2120-#else
2121- return localtime(timep);
2122-#endif // HAVE_LOCALTIME_R
2123-}
2124-
2125-/*
2126- * Replacement for ctime(), which is not safe to use.
2127- * Requires strftime(), otherwise returns "(unknown)".
2128- * If "thetime" is invalid returns "(invalid)". Never returns NULL.
2129- * When "add_newline" is TRUE add a newline like ctime() does.
2130- * Uses a static buffer.
2131- */
2132- char *
2133-get_ctime(time_t thetime, int add_newline)
2134-{
2135- static char buf[50];
2136-#ifdef HAVE_STRFTIME
2137- struct tm tmval;
2138- struct tm *curtime;
2139-
2140- curtime = vim_localtime(&thetime, &tmval);
2141- // MSVC returns NULL for an invalid value of seconds.
2142- if (curtime == NULL)
2143- vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);
2144- else
2145- {
2146- (void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"),
2147- curtime);
2148-# ifdef MSWIN
2149- if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2150- {
2151- char_u *to_free = NULL;
2152- int len;
2153-
2154- acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len);
2155- if (to_free != NULL)
2156- {
2157- STRCPY(buf, to_free);
2158- vim_free(to_free);
2159- }
2160- }
2161-# endif
2162- }
2163-#else
2164- STRCPY(buf, "(unknown)");
2165-#endif
2166- if (add_newline)
2167- STRCAT(buf, "\n");
2168- return buf;
2169-}
2170-
2171-/*
21722084 * Give information about an existing swap file.
21732085 * Returns timestamp (0 when unknown).
21742086 */
diff -r eb5ef6f5f58b -r a961efb326e5 src/misc1.c
--- a/src/misc1.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/misc1.c Fri Feb 14 13:30:05 2020 +0100
@@ -2597,34 +2597,3 @@
25972597 ;
25982598 return path_is_url(p);
25992599 }
2600-
2601-/*
2602- * Put timestamp "tt" in "buf[buflen]" in a nice format.
2603- */
2604- void
2605-add_time(char_u *buf, size_t buflen, time_t tt)
2606-{
2607-#ifdef HAVE_STRFTIME
2608- struct tm tmval;
2609- struct tm *curtime;
2610-
2611- if (vim_time() - tt >= 100)
2612- {
2613- curtime = vim_localtime(&tt, &tmval);
2614- if (vim_time() - tt < (60L * 60L * 12L))
2615- // within 12 hours
2616- (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
2617- else
2618- // longer ago
2619- (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
2620- }
2621- else
2622-#endif
2623- {
2624- long seconds = (long)(vim_time() - tt);
2625-
2626- vim_snprintf((char *)buf, buflen,
2627- NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
2628- seconds);
2629- }
2630-}
diff -r eb5ef6f5f58b -r a961efb326e5 src/misc2.c
--- a/src/misc2.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/misc2.c Fri Feb 14 13:30:05 2020 +0100
@@ -4127,26 +4127,6 @@
41274127 }
41284128
41294129 /*
4130- * Read 8 bytes from "fd" and turn them into a time_T, MSB first.
4131- * Returns -1 when encountering EOF.
4132- */
4133- time_T
4134-get8ctime(FILE *fd)
4135-{
4136- int c;
4137- time_T n = 0;
4138- int i;
4139-
4140- for (i = 0; i < 8; ++i)
4141- {
4142- c = getc(fd);
4143- if (c == EOF) return -1;
4144- n = (n << 8) + c;
4145- }
4146- return n;
4147-}
4148-
4149-/*
41504130 * Read a string of length "cnt" from "fd" into allocated memory.
41514131 * Returns NULL when out of memory or unable to read that many bytes.
41524132 */
@@ -4191,68 +4171,6 @@
41914171 return OK;
41924172 }
41934173
4194-#ifdef _MSC_VER
4195-# if (_MSC_VER <= 1200)
4196-// This line is required for VC6 without the service pack. Also see the
4197-// matching #pragma below.
4198- # pragma optimize("", off)
4199-# endif
4200-#endif
4201-
4202-/*
4203- * Write time_T to file "fd" in 8 bytes.
4204- * Returns FAIL when the write failed.
4205- */
4206- int
4207-put_time(FILE *fd, time_T the_time)
4208-{
4209- char_u buf[8];
4210-
4211- time_to_bytes(the_time, buf);
4212- return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL;
4213-}
4214-
4215-/*
4216- * Write time_T to "buf[8]".
4217- */
4218- void
4219-time_to_bytes(time_T the_time, char_u *buf)
4220-{
4221- int c;
4222- int i;
4223- int bi = 0;
4224- time_T wtime = the_time;
4225-
4226- // time_T can be up to 8 bytes in size, more than long_u, thus we
4227- // can't use put_bytes() here.
4228- // Another problem is that ">>" may do an arithmetic shift that keeps the
4229- // sign. This happens for large values of wtime. A cast to long_u may
4230- // truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes,
4231- // it's safe to assume that long_u is 4 bytes or more and when using 8
4232- // bytes the top bit won't be set.
4233- for (i = 7; i >= 0; --i)
4234- {
4235- if (i + 1 > (int)sizeof(time_T))
4236- // ">>" doesn't work well when shifting more bits than avail
4237- buf[bi++] = 0;
4238- else
4239- {
4240-#if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
4241- c = (int)(wtime >> (i * 8));
4242-#else
4243- c = (int)((long_u)wtime >> (i * 8));
4244-#endif
4245- buf[bi++] = c;
4246- }
4247- }
4248-}
4249-
4250-#ifdef _MSC_VER
4251-# if (_MSC_VER <= 1200)
4252- # pragma optimize("", on)
4253-# endif
4254-#endif
4255-
42564174 #endif
42574175
42584176 #if defined(FEAT_QUICKFIX) || defined(FEAT_SPELL) || defined(PROTO)
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto.h
--- a/src/proto.h Thu Feb 13 22:00:04 2020 +0100
+++ b/src/proto.h Fri Feb 14 13:30:05 2020 +0100
@@ -221,6 +221,7 @@
221221 # include "textprop.pro"
222222 # endif
223223 # include "testing.pro"
224+# include "time.pro"
224225 # include "ui.pro"
225226 # include "undo.pro"
226227 # include "usercmd.pro"
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto/ex_cmds.pro
--- a/src/proto/ex_cmds.pro Thu Feb 13 22:00:04 2020 +0100
+++ b/src/proto/ex_cmds.pro Fri Feb 14 13:30:05 2020 +0100
@@ -9,7 +9,6 @@
99 void do_shell(char_u *cmd, int flags);
1010 char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp);
1111 void append_redir(char_u *buf, int buflen, char_u *opt, char_u *fname);
12-time_T vim_time(void);
1312 void do_fixdel(exarg_T *eap);
1413 void print_line_no_prefix(linenr_T lnum, int use_number, int list);
1514 void print_line(linenr_T lnum, int use_number, int list);
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto/ex_cmds2.pro
--- a/src/proto/ex_cmds2.pro Thu Feb 13 22:00:04 2020 +0100
+++ b/src/proto/ex_cmds2.pro Fri Feb 14 13:30:05 2020 +0100
@@ -1,15 +1,4 @@
11 /* ex_cmds2.c */
2-long proftime_time_left(proftime_T *due, proftime_T *now);
3-timer_T *create_timer(long msec, int repeat);
4-long check_due_timer(void);
5-void stop_timer(timer_T *timer);
6-int set_ref_in_timer(int copyID);
7-void timer_free_all(void);
8-void f_timer_info(typval_T *argvars, typval_T *rettv);
9-void f_timer_pause(typval_T *argvars, typval_T *rettv);
10-void f_timer_start(typval_T *argvars, typval_T *rettv);
11-void f_timer_stop(typval_T *argvars, typval_T *rettv);
12-void f_timer_stopall(typval_T *argvars, typval_T *rettv);
132 int autowrite(buf_T *buf, int forceit);
143 void autowrite_all(void);
154 int check_changed(buf_T *buf, int flags);
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto/main.pro
--- a/src/proto/main.pro Thu Feb 13 22:00:04 2020 +0100
+++ b/src/proto/main.pro Fri Feb 14 13:30:05 2020 +0100
@@ -12,9 +12,6 @@
1212 void getout(int exitval);
1313 int process_env(char_u *env, int is_viminit);
1414 void mainerr_arg_missing(char_u *str);
15-void time_push(void *tv_rel, void *tv_start);
16-void time_pop(void *tp);
17-void time_msg(char *mesg, void *tv_start);
1815 void server_to_input_buf(char_u *str);
1916 char_u *eval_client_expr_to_string(char_u *expr);
2017 int sendToLocalVim(char_u *cmd, int asExpr, char_u **result);
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto/memline.pro
--- a/src/proto/memline.pro Thu Feb 13 22:00:04 2020 +0100
+++ b/src/proto/memline.pro Fri Feb 14 13:30:05 2020 +0100
@@ -13,8 +13,6 @@
1313 int recover_names(char_u *fname, int list, int nr, char_u **fname_out);
1414 char_u *make_percent_swname(char_u *dir, char_u *name);
1515 void get_b0_dict(char_u *fname, dict_T *d);
16-struct tm *vim_localtime(const time_t *timep, struct tm *result);
17-char *get_ctime(time_t thetime, int add_newline);
1816 void ml_sync_all(int check_file, int check_char);
1917 void ml_preserve(buf_T *buf, int message);
2018 char_u *ml_get(linenr_T lnum);
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto/misc1.pro
--- a/src/proto/misc1.pro Thu Feb 13 22:00:04 2020 +0100
+++ b/src/proto/misc1.pro Fri Feb 14 13:30:05 2020 +0100
@@ -47,5 +47,4 @@
4747 char_u *get_isolated_shell_name(void);
4848 int path_is_url(char_u *p);
4949 int path_with_url(char_u *fname);
50-void add_time(char_u *buf, size_t buflen, time_t tt);
5150 /* vim: set ft=c : */
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto/misc2.pro
--- a/src/proto/misc2.pro Thu Feb 13 22:00:04 2020 +0100
+++ b/src/proto/misc2.pro Fri Feb 14 13:30:05 2020 +0100
@@ -94,11 +94,8 @@
9494 int get2c(FILE *fd);
9595 int get3c(FILE *fd);
9696 int get4c(FILE *fd);
97-time_T get8ctime(FILE *fd);
9897 char_u *read_string(FILE *fd, int cnt);
9998 int put_bytes(FILE *fd, long_u nr, int len);
100-int put_time(FILE *fd, time_T the_time);
101-void time_to_bytes(time_T the_time, char_u *buf);
10299 int has_non_ascii(char_u *s);
103100 int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
104101 int build_argv_from_string(char_u *cmd, char ***argv, int *argc);
diff -r eb5ef6f5f58b -r a961efb326e5 src/proto/time.pro
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto/time.pro Fri Feb 14 13:30:05 2020 +0100
@@ -0,0 +1,28 @@
1+/* time.c */
2+char *get_ctime(time_t thetime, int add_newline);
3+time_T vim_time(void);
4+void f_localtime(typval_T *argvars, typval_T *rettv);
5+void f_reltime(typval_T *argvars, typval_T *rettv);
6+void f_reltimefloat(typval_T *argvars, typval_T *rettv);
7+void f_reltimestr(typval_T *argvars, typval_T *rettv);
8+void f_strftime(typval_T *argvars, typval_T *rettv);
9+void f_strptime(typval_T *argvars, typval_T *rettv);
10+long proftime_time_left(proftime_T *due, proftime_T *now);
11+timer_T *create_timer(long msec, int repeat);
12+long check_due_timer(void);
13+void stop_timer(timer_T *timer);
14+int set_ref_in_timer(int copyID);
15+void timer_free_all(void);
16+void f_timer_info(typval_T *argvars, typval_T *rettv);
17+void f_timer_pause(typval_T *argvars, typval_T *rettv);
18+void f_timer_start(typval_T *argvars, typval_T *rettv);
19+void f_timer_stop(typval_T *argvars, typval_T *rettv);
20+void f_timer_stopall(typval_T *argvars, typval_T *rettv);
21+void time_push(void *tv_rel, void *tv_start);
22+void time_pop(void *tp);
23+void time_msg(char *mesg, void *tv_start);
24+time_T get8ctime(FILE *fd);
25+int put_time(FILE *fd, time_T the_time);
26+void time_to_bytes(time_T the_time, char_u *buf);
27+void add_time(char_u *buf, size_t buflen, time_t tt);
28+/* vim: set ft=c : */
diff -r eb5ef6f5f58b -r a961efb326e5 src/time.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/time.c Fri Feb 14 13:30:05 2020 +0100
@@ -0,0 +1,1041 @@
1+/* vi:set ts=8 sts=4 sw=4 noet:
2+ *
3+ * VIM - Vi IMproved by Bram Moolenaar
4+ *
5+ * Do ":help uganda" in Vim to read copying and usage conditions.
6+ * Do ":help credits" in Vim to see a list of people who contributed.
7+ * See README.txt for an overview of the Vim source code.
8+ */
9+
10+/*
11+ * time.c: functions related to time and timers
12+ */
13+
14+#include "vim.h"
15+
16+/*
17+ * Cache of the current timezone name as retrieved from TZ, or an empty string
18+ * where unset, up to 64 octets long including trailing null byte.
19+ */
20+#if defined(HAVE_LOCALTIME_R) && defined(HAVE_TZSET)
21+static char tz_cache[64];
22+#endif
23+
24+/*
25+ * Call either localtime(3) or localtime_r(3) from POSIX libc time.h, with the
26+ * latter version preferred for reentrancy.
27+ *
28+ * If we use localtime_r(3) and we have tzset(3) available, check to see if the
29+ * environment variable TZ has changed since the last run, and call tzset(3) to
30+ * update the global timezone variables if it has. This is because the POSIX
31+ * standard doesn't require localtime_r(3) implementations to do that as it
32+ * does with localtime(3), and we don't want to call tzset(3) every time.
33+ */
34+ static struct tm *
35+vim_localtime(
36+ const time_t *timep, // timestamp for local representation
37+ struct tm *result UNUSED) // pointer to caller return buffer
38+{
39+#ifdef HAVE_LOCALTIME_R
40+# ifdef HAVE_TZSET
41+ char *tz; // pointer for TZ environment var
42+
43+ tz = (char *)mch_getenv((char_u *)"TZ");
44+ if (tz == NULL)
45+ tz = "";
46+ if (STRNCMP(tz_cache, tz, sizeof(tz_cache) - 1) != 0)
47+ {
48+ tzset();
49+ vim_strncpy((char_u *)tz_cache, (char_u *)tz, sizeof(tz_cache) - 1);
50+ }
51+# endif // HAVE_TZSET
52+ return localtime_r(timep, result);
53+#else
54+ return localtime(timep);
55+#endif // HAVE_LOCALTIME_R
56+}
57+
58+/*
59+ * Return the current time in seconds. Calls time(), unless test_settime()
60+ * was used.
61+ */
62+ time_T
63+vim_time(void)
64+{
65+# ifdef FEAT_EVAL
66+ return time_for_testing == 0 ? time(NULL) : time_for_testing;
67+# else
68+ return time(NULL);
69+# endif
70+}
71+
72+/*
73+ * Replacement for ctime(), which is not safe to use.
74+ * Requires strftime(), otherwise returns "(unknown)".
75+ * If "thetime" is invalid returns "(invalid)". Never returns NULL.
76+ * When "add_newline" is TRUE add a newline like ctime() does.
77+ * Uses a static buffer.
78+ */
79+ char *
80+get_ctime(time_t thetime, int add_newline)
81+{
82+ static char buf[50];
83+#ifdef HAVE_STRFTIME
84+ struct tm tmval;
85+ struct tm *curtime;
86+
87+ curtime = vim_localtime(&thetime, &tmval);
88+ // MSVC returns NULL for an invalid value of seconds.
89+ if (curtime == NULL)
90+ vim_strncpy((char_u *)buf, (char_u *)_("(Invalid)"), sizeof(buf) - 1);
91+ else
92+ {
93+ (void)strftime(buf, sizeof(buf) - 1, _("%a %b %d %H:%M:%S %Y"),
94+ curtime);
95+# ifdef MSWIN
96+ if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
97+ {
98+ char_u *to_free = NULL;
99+ int len;
100+
101+ acp_to_enc((char_u *)buf, (int)strlen(buf), &to_free, &len);
102+ if (to_free != NULL)
103+ {
104+ STRCPY(buf, to_free);
105+ vim_free(to_free);
106+ }
107+ }
108+# endif
109+ }
110+#else
111+ STRCPY(buf, "(unknown)");
112+#endif
113+ if (add_newline)
114+ STRCAT(buf, "\n");
115+ return buf;
116+}
117+
118+#if defined(FEAT_EVAL) || defined(PROTO)
119+
120+#if defined(MACOS_X)
121+# include <time.h> // for time_t
122+#endif
123+
124+/*
125+ * "localtime()" function
126+ */
127+ void
128+f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
129+{
130+ rettv->vval.v_number = (varnumber_T)time(NULL);
131+}
132+
133+# if defined(FEAT_RELTIME)
134+/*
135+ * Convert a List to proftime_T.
136+ * Return FAIL when there is something wrong.
137+ */
138+ static int
139+list2proftime(typval_T *arg, proftime_T *tm)
140+{
141+ long n1, n2;
142+ int error = FALSE;
143+
144+ if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
145+ || arg->vval.v_list->lv_len != 2)
146+ return FAIL;
147+ n1 = list_find_nr(arg->vval.v_list, 0L, &error);
148+ n2 = list_find_nr(arg->vval.v_list, 1L, &error);
149+# ifdef MSWIN
150+ tm->HighPart = n1;
151+ tm->LowPart = n2;
152+# else
153+ tm->tv_sec = n1;
154+ tm->tv_usec = n2;
155+# endif
156+ return error ? FAIL : OK;
157+}
158+# endif // FEAT_RELTIME
159+
160+/*
161+ * "reltime()" function
162+ */
163+ void
164+f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
165+{
166+# ifdef FEAT_RELTIME
167+ proftime_T res;
168+ proftime_T start;
169+
170+ if (argvars[0].v_type == VAR_UNKNOWN)
171+ {
172+ // No arguments: get current time.
173+ profile_start(&res);
174+ }
175+ else if (argvars[1].v_type == VAR_UNKNOWN)
176+ {
177+ if (list2proftime(&argvars[0], &res) == FAIL)
178+ return;
179+ profile_end(&res);
180+ }
181+ else
182+ {
183+ // Two arguments: compute the difference.
184+ if (list2proftime(&argvars[0], &start) == FAIL
185+ || list2proftime(&argvars[1], &res) == FAIL)
186+ return;
187+ profile_sub(&res, &start);
188+ }
189+
190+ if (rettv_list_alloc(rettv) == OK)
191+ {
192+ long n1, n2;
193+
194+# ifdef MSWIN
195+ n1 = res.HighPart;
196+ n2 = res.LowPart;
197+# else
198+ n1 = res.tv_sec;
199+ n2 = res.tv_usec;
200+# endif
201+ list_append_number(rettv->vval.v_list, (varnumber_T)n1);
202+ list_append_number(rettv->vval.v_list, (varnumber_T)n2);
203+ }
204+# endif
205+}
206+
207+# ifdef FEAT_FLOAT
208+/*
209+ * "reltimefloat()" function
210+ */
211+ void
212+f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
213+{
214+# ifdef FEAT_RELTIME
215+ proftime_T tm;
216+# endif
217+
218+ rettv->v_type = VAR_FLOAT;
219+ rettv->vval.v_float = 0;
220+# ifdef FEAT_RELTIME
221+ if (list2proftime(&argvars[0], &tm) == OK)
222+ rettv->vval.v_float = profile_float(&tm);
223+# endif
224+}
225+# endif
226+
227+/*
228+ * "reltimestr()" function
229+ */
230+ void
231+f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
232+{
233+# ifdef FEAT_RELTIME
234+ proftime_T tm;
235+# endif
236+
237+ rettv->v_type = VAR_STRING;
238+ rettv->vval.v_string = NULL;
239+# ifdef FEAT_RELTIME
240+ if (list2proftime(&argvars[0], &tm) == OK)
241+ rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
242+# endif
243+}
244+
245+# if defined(HAVE_STRFTIME) || defined(PROTO)
246+/*
247+ * "strftime({format}[, {time}])" function
248+ */
249+ void
250+f_strftime(typval_T *argvars, typval_T *rettv)
251+{
252+ char_u result_buf[256];
253+ struct tm tmval;
254+ struct tm *curtime;
255+ time_t seconds;
256+ char_u *p;
257+
258+ rettv->v_type = VAR_STRING;
259+
260+ p = tv_get_string(&argvars[0]);
261+ if (argvars[1].v_type == VAR_UNKNOWN)
262+ seconds = time(NULL);
263+ else
264+ seconds = (time_t)tv_get_number(&argvars[1]);
265+ curtime = vim_localtime(&seconds, &tmval);
266+ // MSVC returns NULL for an invalid value of seconds.
267+ if (curtime == NULL)
268+ rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
269+ else
270+ {
271+ vimconv_T conv;
272+ char_u *enc;
273+
274+ conv.vc_type = CONV_NONE;
275+ enc = enc_locale();
276+ convert_setup(&conv, p_enc, enc);
277+ if (conv.vc_type != CONV_NONE)
278+ p = string_convert(&conv, p, NULL);
279+ if (p != NULL)
280+ (void)strftime((char *)result_buf, sizeof(result_buf),
281+ (char *)p, curtime);
282+ else
283+ result_buf[0] = NUL;
284+
285+ if (conv.vc_type != CONV_NONE)
286+ vim_free(p);
287+ convert_setup(&conv, enc, p_enc);
288+ if (conv.vc_type != CONV_NONE)
289+ rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
290+ else
291+ rettv->vval.v_string = vim_strsave(result_buf);
292+
293+ // Release conversion descriptors
294+ convert_setup(&conv, NULL, NULL);
295+ vim_free(enc);
296+ }
297+}
298+# endif
299+
300+# if defined(HAVE_STRPTIME) || defined(PROTO)
301+/*
302+ * "strptime({format}, {timestring})" function
303+ */
304+ void
305+f_strptime(typval_T *argvars, typval_T *rettv)
306+{
307+ struct tm tmval;
308+ char_u *fmt;
309+ char_u *str;
310+ vimconv_T conv;
311+ char_u *enc;
312+
313+ vim_memset(&tmval, NUL, sizeof(tmval));
314+ fmt = tv_get_string(&argvars[0]);
315+ str = tv_get_string(&argvars[1]);
316+
317+ conv.vc_type = CONV_NONE;
318+ enc = enc_locale();
319+ convert_setup(&conv, p_enc, enc);
320+ if (conv.vc_type != CONV_NONE)
321+ fmt = string_convert(&conv, fmt, NULL);
322+ if (fmt == NULL
323+ || strptime((char *)str, (char *)fmt, &tmval) == NULL
324+ || (rettv->vval.v_number = mktime(&tmval)) == -1)
325+ rettv->vval.v_number = 0;
326+
327+ if (conv.vc_type != CONV_NONE)
328+ vim_free(fmt);
329+ convert_setup(&conv, NULL, NULL);
330+ vim_free(enc);
331+}
332+# endif
333+
334+# if defined(FEAT_TIMERS) || defined(PROTO)
335+static timer_T *first_timer = NULL;
336+static long last_timer_id = 0;
337+
338+/*
339+ * Return time left until "due". Negative if past "due".
340+ */
341+ long
342+proftime_time_left(proftime_T *due, proftime_T *now)
343+{
344+# ifdef MSWIN
345+ LARGE_INTEGER fr;
346+
347+ if (now->QuadPart > due->QuadPart)
348+ return 0;
349+ QueryPerformanceFrequency(&fr);
350+ return (long)(((double)(due->QuadPart - now->QuadPart)
351+ / (double)fr.QuadPart) * 1000);
352+# else
353+ if (now->tv_sec > due->tv_sec)
354+ return 0;
355+ return (due->tv_sec - now->tv_sec) * 1000
356+ + (due->tv_usec - now->tv_usec) / 1000;
357+# endif
358+}
359+
360+/*
361+ * Insert a timer in the list of timers.
362+ */
363+ static void
364+insert_timer(timer_T *timer)
365+{
366+ timer->tr_next = first_timer;
367+ timer->tr_prev = NULL;
368+ if (first_timer != NULL)
369+ first_timer->tr_prev = timer;
370+ first_timer = timer;
371+ did_add_timer = TRUE;
372+}
373+
374+/*
375+ * Take a timer out of the list of timers.
376+ */
377+ static void
378+remove_timer(timer_T *timer)
379+{
380+ if (timer->tr_prev == NULL)
381+ first_timer = timer->tr_next;
382+ else
383+ timer->tr_prev->tr_next = timer->tr_next;
384+ if (timer->tr_next != NULL)
385+ timer->tr_next->tr_prev = timer->tr_prev;
386+}
387+
388+ static void
389+free_timer(timer_T *timer)
390+{
391+ free_callback(&timer->tr_callback);
392+ vim_free(timer);
393+}
394+
395+/*
396+ * Create a timer and return it. NULL if out of memory.
397+ * Caller should set the callback.
398+ */
399+ timer_T *
400+create_timer(long msec, int repeat)
401+{
402+ timer_T *timer = ALLOC_CLEAR_ONE(timer_T);
403+ long prev_id = last_timer_id;
404+
405+ if (timer == NULL)
406+ return NULL;
407+ if (++last_timer_id <= prev_id)
408+ // Overflow! Might cause duplicates...
409+ last_timer_id = 0;
410+ timer->tr_id = last_timer_id;
411+ insert_timer(timer);
412+ if (repeat != 0)
413+ timer->tr_repeat = repeat - 1;
414+ timer->tr_interval = msec;
415+
416+ profile_setlimit(msec, &timer->tr_due);
417+ return timer;
418+}
419+
420+/*
421+ * Invoke the callback of "timer".
422+ */
423+ static void
424+timer_callback(timer_T *timer)
425+{
426+ typval_T rettv;
427+ typval_T argv[2];
428+
429+ argv[0].v_type = VAR_NUMBER;
430+ argv[0].vval.v_number = (varnumber_T)timer->tr_id;
431+ argv[1].v_type = VAR_UNKNOWN;
432+
433+ call_callback(&timer->tr_callback, -1, &rettv, 1, argv);
434+ clear_tv(&rettv);
435+}
436+
437+/*
438+ * Call timers that are due.
439+ * Return the time in msec until the next timer is due.
440+ * Returns -1 if there are no pending timers.
441+ */
442+ long
443+check_due_timer(void)
444+{
445+ timer_T *timer;
446+ timer_T *timer_next;
447+ long this_due;
448+ long next_due = -1;
449+ proftime_T now;
450+ int did_one = FALSE;
451+ int need_update_screen = FALSE;
452+ long current_id = last_timer_id;
453+
454+ // Don't run any timers while exiting or dealing with an error.
455+ if (exiting || aborting())
456+ return next_due;
457+
458+ profile_start(&now);
459+ for (timer = first_timer; timer != NULL && !got_int; timer = timer_next)
460+ {
461+ timer_next = timer->tr_next;
462+
463+ if (timer->tr_id == -1 || timer->tr_firing || timer->tr_paused)
464+ continue;
465+ this_due = proftime_time_left(&timer->tr_due, &now);
466+ if (this_due <= 1)
467+ {
468+ // Save and restore a lot of flags, because the timer fires while
469+ // waiting for a character, which might be halfway a command.
470+ int save_timer_busy = timer_busy;
471+ int save_vgetc_busy = vgetc_busy;
472+ int save_did_emsg = did_emsg;
473+ int save_called_emsg = called_emsg;
474+ int save_must_redraw = must_redraw;
475+ int save_trylevel = trylevel;
476+ int save_did_throw = did_throw;
477+ int save_ex_pressedreturn = get_pressedreturn();
478+ int save_may_garbage_collect = may_garbage_collect;
479+ except_T *save_current_exception = current_exception;
480+ vimvars_save_T vvsave;
481+
482+ // Create a scope for running the timer callback, ignoring most of
483+ // the current scope, such as being inside a try/catch.
484+ timer_busy = timer_busy > 0 || vgetc_busy > 0;
485+ vgetc_busy = 0;
486+ called_emsg = 0;
487+ did_emsg = FALSE;
488+ did_uncaught_emsg = FALSE;
489+ must_redraw = 0;
490+ trylevel = 0;
491+ did_throw = FALSE;
492+ current_exception = NULL;
493+ may_garbage_collect = FALSE;
494+ save_vimvars(&vvsave);
495+
496+ timer->tr_firing = TRUE;
497+ timer_callback(timer);
498+ timer->tr_firing = FALSE;
499+
500+ timer_next = timer->tr_next;
501+ did_one = TRUE;
502+ timer_busy = save_timer_busy;
503+ vgetc_busy = save_vgetc_busy;
504+ if (did_uncaught_emsg)
505+ ++timer->tr_emsg_count;
506+ did_emsg = save_did_emsg;
507+ called_emsg = save_called_emsg;
508+ trylevel = save_trylevel;
509+ did_throw = save_did_throw;
510+ current_exception = save_current_exception;
511+ restore_vimvars(&vvsave);
512+ if (must_redraw != 0)
513+ need_update_screen = TRUE;
514+ must_redraw = must_redraw > save_must_redraw
515+ ? must_redraw : save_must_redraw;
516+ set_pressedreturn(save_ex_pressedreturn);
517+ may_garbage_collect = save_may_garbage_collect;
518+
519+ // Only fire the timer again if it repeats and stop_timer() wasn't
520+ // called while inside the callback (tr_id == -1).
521+ if (timer->tr_repeat != 0 && timer->tr_id != -1
522+ && timer->tr_emsg_count < 3)
523+ {
524+ profile_setlimit(timer->tr_interval, &timer->tr_due);
525+ this_due = proftime_time_left(&timer->tr_due, &now);
526+ if (this_due < 1)
527+ this_due = 1;
528+ if (timer->tr_repeat > 0)
529+ --timer->tr_repeat;
530+ }
531+ else
532+ {
533+ this_due = -1;
534+ remove_timer(timer);
535+ free_timer(timer);
536+ }
537+ }
538+ if (this_due > 0 && (next_due == -1 || next_due > this_due))
539+ next_due = this_due;
540+ }
541+
542+ if (did_one)
543+ redraw_after_callback(need_update_screen);
544+
545+#ifdef FEAT_BEVAL_TERM
546+ if (bevalexpr_due_set)
547+ {
548+ this_due = proftime_time_left(&bevalexpr_due, &now);
549+ if (this_due <= 1)
550+ {
551+ bevalexpr_due_set = FALSE;
552+ if (balloonEval == NULL)
553+ {
554+ balloonEval = ALLOC_CLEAR_ONE(BalloonEval);
555+ balloonEvalForTerm = TRUE;
556+ }
557+ if (balloonEval != NULL)
558+ {
559+ general_beval_cb(balloonEval, 0);
560+ setcursor();
561+ out_flush();
562+ }
563+ }
564+ else if (next_due == -1 || next_due > this_due)
565+ next_due = this_due;
566+ }
567+#endif
568+#ifdef FEAT_TERMINAL
569+ // Some terminal windows may need their buffer updated.
570+ next_due = term_check_timers(next_due, &now);
571+#endif
572+
573+ return current_id != last_timer_id ? 1 : next_due;
574+}
575+
576+/*
577+ * Find a timer by ID. Returns NULL if not found;
578+ */
579+ static timer_T *
580+find_timer(long id)
581+{
582+ timer_T *timer;
583+
584+ if (id >= 0)
585+ {
586+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
587+ if (timer->tr_id == id)
588+ return timer;
589+ }
590+ return NULL;
591+}
592+
593+
594+/*
595+ * Stop a timer and delete it.
596+ */
597+ void
598+stop_timer(timer_T *timer)
599+{
600+ if (timer->tr_firing)
601+ // Free the timer after the callback returns.
602+ timer->tr_id = -1;
603+ else
604+ {
605+ remove_timer(timer);
606+ free_timer(timer);
607+ }
608+}
609+
610+ static void
611+stop_all_timers(void)
612+{
613+ timer_T *timer;
614+ timer_T *timer_next;
615+
616+ for (timer = first_timer; timer != NULL; timer = timer_next)
617+ {
618+ timer_next = timer->tr_next;
619+ stop_timer(timer);
620+ }
621+}
622+
623+ static void
624+add_timer_info(typval_T *rettv, timer_T *timer)
625+{
626+ list_T *list = rettv->vval.v_list;
627+ dict_T *dict = dict_alloc();
628+ dictitem_T *di;
629+ long remaining;
630+ proftime_T now;
631+
632+ if (dict == NULL)
633+ return;
634+ list_append_dict(list, dict);
635+
636+ dict_add_number(dict, "id", timer->tr_id);
637+ dict_add_number(dict, "time", (long)timer->tr_interval);
638+
639+ profile_start(&now);
640+ remaining = proftime_time_left(&timer->tr_due, &now);
641+ dict_add_number(dict, "remaining", (long)remaining);
642+
643+ dict_add_number(dict, "repeat",
644+ (long)(timer->tr_repeat < 0 ? -1 : timer->tr_repeat + 1));
645+ dict_add_number(dict, "paused", (long)(timer->tr_paused));
646+
647+ di = dictitem_alloc((char_u *)"callback");
648+ if (di != NULL)
649+ {
650+ if (dict_add(dict, di) == FAIL)
651+ vim_free(di);
652+ else
653+ put_callback(&timer->tr_callback, &di->di_tv);
654+ }
655+}
656+
657+ static void
658+add_timer_info_all(typval_T *rettv)
659+{
660+ timer_T *timer;
661+
662+ for (timer = first_timer; timer != NULL; timer = timer->tr_next)
663+ if (timer->tr_id != -1)
664+ add_timer_info(rettv, timer);
665+}
666+
667+/*
668+ * Mark references in partials of timers.
669+ */
670+ int
671+set_ref_in_timer(int copyID)
672+{
673+ int abort = FALSE;
674+ timer_T *timer;
675+ typval_T tv;
676+
677+ for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
678+ {
679+ if (timer->tr_callback.cb_partial != NULL)
680+ {
681+ tv.v_type = VAR_PARTIAL;
682+ tv.vval.v_partial = timer->tr_callback.cb_partial;
683+ }
684+ else
685+ {
686+ tv.v_type = VAR_FUNC;
687+ tv.vval.v_string = timer->tr_callback.cb_name;
688+ }
689+ abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
690+ }
691+ return abort;
692+}
693+
694+# if defined(EXITFREE) || defined(PROTO)
695+ void
696+timer_free_all()
697+{
698+ timer_T *timer;
699+
700+ while (first_timer != NULL)
701+ {
702+ timer = first_timer;
703+ remove_timer(timer);
704+ free_timer(timer);
705+ }
706+}
707+# endif
708+
709+/*
710+ * "timer_info([timer])" function
711+ */
712+ void
713+f_timer_info(typval_T *argvars, typval_T *rettv)
714+{
715+ timer_T *timer = NULL;
716+
717+ if (rettv_list_alloc(rettv) != OK)
718+ return;
719+ if (argvars[0].v_type != VAR_UNKNOWN)
720+ {
721+ if (argvars[0].v_type != VAR_NUMBER)
722+ emsg(_(e_number_exp));
723+ else
724+ {
725+ timer = find_timer((int)tv_get_number(&argvars[0]));
726+ if (timer != NULL)
727+ add_timer_info(rettv, timer);
728+ }
729+ }
730+ else
731+ add_timer_info_all(rettv);
732+}
733+
734+/*
735+ * "timer_pause(timer, paused)" function
736+ */
737+ void
738+f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
739+{
740+ timer_T *timer = NULL;
741+ int paused = (int)tv_get_number(&argvars[1]);
742+
743+ if (argvars[0].v_type != VAR_NUMBER)
744+ emsg(_(e_number_exp));
745+ else
746+ {
747+ timer = find_timer((int)tv_get_number(&argvars[0]));
748+ if (timer != NULL)
749+ timer->tr_paused = paused;
750+ }
751+}
752+
753+/*
754+ * "timer_start(time, callback [, options])" function
755+ */
756+ void
757+f_timer_start(typval_T *argvars, typval_T *rettv)
758+{
759+ long msec = (long)tv_get_number(&argvars[0]);
760+ timer_T *timer;
761+ int repeat = 0;
762+ callback_T callback;
763+ dict_T *dict;
764+
765+ rettv->vval.v_number = -1;
766+ if (check_secure())
767+ return;
768+ if (argvars[2].v_type != VAR_UNKNOWN)
769+ {
770+ if (argvars[2].v_type != VAR_DICT
771+ || (dict = argvars[2].vval.v_dict) == NULL)
772+ {
773+ semsg(_(e_invarg2), tv_get_string(&argvars[2]));
774+ return;
775+ }
776+ if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
777+ repeat = dict_get_number(dict, (char_u *)"repeat");
778+ }
779+
780+ callback = get_callback(&argvars[1]);
781+ if (callback.cb_name == NULL)
782+ return;
783+
784+ timer = create_timer(msec, repeat);
785+ if (timer == NULL)
786+ free_callback(&callback);
787+ else
788+ {
789+ set_callback(&timer->tr_callback, &callback);
790+ rettv->vval.v_number = (varnumber_T)timer->tr_id;
791+ }
792+}
793+
794+/*
795+ * "timer_stop(timer)" function
796+ */
797+ void
798+f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
799+{
800+ timer_T *timer;
801+
802+ if (argvars[0].v_type != VAR_NUMBER)
803+ {
804+ emsg(_(e_number_exp));
805+ return;
806+ }
807+ timer = find_timer((int)tv_get_number(&argvars[0]));
808+ if (timer != NULL)
809+ stop_timer(timer);
810+}
811+
812+/*
813+ * "timer_stopall()" function
814+ */
815+ void
816+f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
817+{
818+ stop_all_timers();
819+}
820+
821+# endif // FEAT_TIMERS
822+
823+# if defined(STARTUPTIME) || defined(PROTO)
824+static struct timeval prev_timeval;
825+
826+# ifdef MSWIN
827+/*
828+ * Windows doesn't have gettimeofday(), although it does have struct timeval.
829+ */
830+ static int
831+gettimeofday(struct timeval *tv, char *dummy UNUSED)
832+{
833+ long t = clock();
834+ tv->tv_sec = t / CLOCKS_PER_SEC;
835+ tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC;
836+ return 0;
837+}
838+# endif
839+
840+/*
841+ * Save the previous time before doing something that could nest.
842+ * set "*tv_rel" to the time elapsed so far.
843+ */
844+ void
845+time_push(void *tv_rel, void *tv_start)
846+{
847+ *((struct timeval *)tv_rel) = prev_timeval;
848+ gettimeofday(&prev_timeval, NULL);
849+ ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec
850+ - ((struct timeval *)tv_rel)->tv_usec;
851+ ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec
852+ - ((struct timeval *)tv_rel)->tv_sec;
853+ if (((struct timeval *)tv_rel)->tv_usec < 0)
854+ {
855+ ((struct timeval *)tv_rel)->tv_usec += 1000000;
856+ --((struct timeval *)tv_rel)->tv_sec;
857+ }
858+ *(struct timeval *)tv_start = prev_timeval;
859+}
860+
861+/*
862+ * Compute the previous time after doing something that could nest.
863+ * Subtract "*tp" from prev_timeval;
864+ * Note: The arguments are (void *) to avoid trouble with systems that don't
865+ * have struct timeval.
866+ */
867+ void
868+time_pop(
869+ void *tp) // actually (struct timeval *)
870+{
871+ prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec;
872+ prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec;
873+ if (prev_timeval.tv_usec < 0)
874+ {
875+ prev_timeval.tv_usec += 1000000;
876+ --prev_timeval.tv_sec;
877+ }
878+}
879+
880+ static void
881+time_diff(struct timeval *then, struct timeval *now)
882+{
883+ long usec;
884+ long msec;
885+
886+ usec = now->tv_usec - then->tv_usec;
887+ msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L,
888+ usec = usec % 1000L;
889+ fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L);
890+}
891+
892+ void
893+time_msg(
894+ char *mesg,
895+ void *tv_start) // only for do_source: start time; actually
896+ // (struct timeval *)
897+{
898+ static struct timeval start;
899+ struct timeval now;
900+
901+ if (time_fd != NULL)
902+ {
903+ if (strstr(mesg, "STARTING") != NULL)
904+ {
905+ gettimeofday(&start, NULL);
906+ prev_timeval = start;
907+ fprintf(time_fd, "\n\ntimes in msec\n");
908+ fprintf(time_fd, " clock self+sourced self: sourced script\n");
909+ fprintf(time_fd, " clock elapsed: other lines\n\n");
910+ }
911+ gettimeofday(&now, NULL);
912+ time_diff(&start, &now);
913+ if (((struct timeval *)tv_start) != NULL)
914+ {
915+ fprintf(time_fd, " ");
916+ time_diff(((struct timeval *)tv_start), &now);
917+ }
918+ fprintf(time_fd, " ");
919+ time_diff(&prev_timeval, &now);
920+ prev_timeval = now;
921+ fprintf(time_fd, ": %s\n", mesg);
922+ }
923+}
924+# endif // STARTUPTIME
925+#endif // FEAT_EVAL
926+
927+#if defined(FEAT_SPELL) || defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
928+/*
929+ * Read 8 bytes from "fd" and turn them into a time_T, MSB first.
930+ * Returns -1 when encountering EOF.
931+ */
932+ time_T
933+get8ctime(FILE *fd)
934+{
935+ int c;
936+ time_T n = 0;
937+ int i;
938+
939+ for (i = 0; i < 8; ++i)
940+ {
941+ c = getc(fd);
942+ if (c == EOF) return -1;
943+ n = (n << 8) + c;
944+ }
945+ return n;
946+}
947+
948+#ifdef _MSC_VER
949+# if (_MSC_VER <= 1200)
950+// This line is required for VC6 without the service pack. Also see the
951+// matching #pragma below.
952+ # pragma optimize("", off)
953+# endif
954+#endif
955+
956+/*
957+ * Write time_T to file "fd" in 8 bytes.
958+ * Returns FAIL when the write failed.
959+ */
960+ int
961+put_time(FILE *fd, time_T the_time)
962+{
963+ char_u buf[8];
964+
965+ time_to_bytes(the_time, buf);
966+ return fwrite(buf, (size_t)8, (size_t)1, fd) == 1 ? OK : FAIL;
967+}
968+
969+/*
970+ * Write time_T to "buf[8]".
971+ */
972+ void
973+time_to_bytes(time_T the_time, char_u *buf)
974+{
975+ int c;
976+ int i;
977+ int bi = 0;
978+ time_T wtime = the_time;
979+
980+ // time_T can be up to 8 bytes in size, more than long_u, thus we
981+ // can't use put_bytes() here.
982+ // Another problem is that ">>" may do an arithmetic shift that keeps the
983+ // sign. This happens for large values of wtime. A cast to long_u may
984+ // truncate if time_T is 8 bytes. So only use a cast when it is 4 bytes,
985+ // it's safe to assume that long_u is 4 bytes or more and when using 8
986+ // bytes the top bit won't be set.
987+ for (i = 7; i >= 0; --i)
988+ {
989+ if (i + 1 > (int)sizeof(time_T))
990+ // ">>" doesn't work well when shifting more bits than avail
991+ buf[bi++] = 0;
992+ else
993+ {
994+#if defined(SIZEOF_TIME_T) && SIZEOF_TIME_T > 4
995+ c = (int)(wtime >> (i * 8));
996+#else
997+ c = (int)((long_u)wtime >> (i * 8));
998+#endif
999+ buf[bi++] = c;
1000+ }
1001+ }
1002+}
1003+
1004+#ifdef _MSC_VER
1005+# if (_MSC_VER <= 1200)
1006+ # pragma optimize("", on)
1007+# endif
1008+#endif
1009+
1010+#endif
1011+
1012+/*
1013+ * Put timestamp "tt" in "buf[buflen]" in a nice format.
1014+ */
1015+ void
1016+add_time(char_u *buf, size_t buflen, time_t tt)
1017+{
1018+#ifdef HAVE_STRFTIME
1019+ struct tm tmval;
1020+ struct tm *curtime;
1021+
1022+ if (vim_time() - tt >= 100)
1023+ {
1024+ curtime = vim_localtime(&tt, &tmval);
1025+ if (vim_time() - tt < (60L * 60L * 12L))
1026+ // within 12 hours
1027+ (void)strftime((char *)buf, buflen, "%H:%M:%S", curtime);
1028+ else
1029+ // longer ago
1030+ (void)strftime((char *)buf, buflen, "%Y/%m/%d %H:%M:%S", curtime);
1031+ }
1032+ else
1033+#endif
1034+ {
1035+ long seconds = (long)(vim_time() - tt);
1036+
1037+ vim_snprintf((char *)buf, buflen,
1038+ NGETTEXT("%ld second ago", "%ld seconds ago", seconds),
1039+ seconds);
1040+ }
1041+}
diff -r eb5ef6f5f58b -r a961efb326e5 src/version.c
--- a/src/version.c Thu Feb 13 22:00:04 2020 +0100
+++ b/src/version.c Fri Feb 14 13:30:05 2020 +0100
@@ -743,6 +743,8 @@
743743 static int included_patches[] =
744744 { /* Add new patch number below this line */
745745 /**/
746+ 256,
747+/**/
746748 255,
747749 /**/
748750 254,
Show on old repository browser