Tony,

Thanks for the feedback. I've attached a new patch with some basic comments and 
non-ANSI C function definitions.

I'd really like to get feedback on the changes to gui_wait_for_chars() and 
mch_inchar(). That's where the meat of this patch is.

Sincerely,

Geoff

On Monday, September 2, 2013 5:00:00 PM UTC-7, Tony Mechelynck wrote:
> On 02/09/13 03:42, Geoff Greer wrote:
> 
> > This patch adds asynchronous functions to vimscript. If you want to perform 
> > an action in 700ms, simply:
> 
> >
> 
> > let timeout_id = settimeout(700, 'echo("hello")')
> 
> >
> 
> > To cancel the timeout before it's fired:
> 
> >
> 
> > canceltimeout(timeout_id)
> 
> >
> 
> > setinterval() also returns an id that can be used with canceltimeout.
> 
> >
> 
> > The reason for this patch is simple: asynchronous functionality is needed 
> > to implement real-time collaborative editing in Vim. This is one of the 
> > most voted-for features (see http://www.vim.org/sponsor/vote_results.php).
> 
> >
> 
> > Along with Matt Kaniaris, I founded Floobits to build real-time 
> > collaboration into every editor. We wrote a plugin for Vim, but we had to 
> > use hacks to get async behavior (abusing feedkeys or client-server). These 
> > methods had side-effects such as breaking leaderkeys or other shortcuts. 
> > After a lot of experimenting, we decided to try patching Vim.
> 
> >
> 
> > Since Vim is character-driven, we had to munge some low-level input 
> > functions to get the desired behavior. We changed gui_wait_for_chars() and 
> > mch_inchar() so that call_timeouts() is run every ticktime milliseconds. 
> > The default ticktime is 100ms.
> 
> >
> 
> > This patch isn't finished yet, but it works on unix-based OSes. If the 
> > reaction is positive, our intention is to change mch_inchar() (or something 
> > similar) in other OS-specific files. That will get async functions working 
> > for everyone.
> 
> >
> 
> > Even if our patch isn't the best approach, we'd love to help get async 
> > functions in Vim. Doing so will open the door to a lot of cool plugins.
> 
> >
> 
> > Oh, and this is the first time either myself or Matt have submitted a patch 
> > to Vim, so please be gentle.
> 
> >
> 
> > Sincerely,
> 
> >
> 
> > Geoff Greer
> 
> >
> 
> Your patch is not in the approved coding style (see :help style-examples)
> 
> 
> 
> Wrong:
> 
> 
> 
>       void
> 
> insert_timeouts(timeout_T *to) {
> 
>       timeout_T *cur = timeouts
> 
>       timeout_T *prev = NULL
> 
> 
> 
> 
> 
> OK:
> 
> /*
> 
>   * Explanation of what the function is used for
> 
>   * and of how to call it
> 
>   */
> 
>       void
> 
> insert_timeouts(to)
> 
>       timeout_T *to;                  /* short comment about to */
> 
> {
> 
>       timeout_T *cur = timeouts;      /* short comment about cur */
> 
>       timeout_T *prev = NULL;         /* short comment about prev */
> 
> 
> 
> NOTE: Don't use ANSI style function declarations.  A few people still 
> 
> have to
> 
> use a compiler that doesn't support it.
> 
> 
> 
> 
> 
> 
> 
> 
> 
> Best regards,
> 
> Tony.
> 
> -- 
> 
> Consensus Terrorism:
> 
>       The process that decides in-office attitudes and behavior.
> 
>               -- Douglas Coupland, "Generation X: Tales for an Accelerated
> 
>                  Culture"

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
diff -r d17ef148ada4 Filelist
--- a/Filelist	Fri Aug 30 17:29:16 2013 +0200
+++ b/Filelist	Mon Sep 02 18:20:17 2013 -0700
@@ -7,6 +7,8 @@
 		src/arabic.c \
 		src/arabic.h \
 		src/ascii.h \
+		src/async.c \
+		src/async.h \
 		src/blowfish.c \
 		src/buffer.c \
 		src/charset.c \
diff -r d17ef148ada4 src/Makefile
--- a/src/Makefile	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/Makefile	Mon Sep 02 18:20:17 2013 -0700
@@ -1424,6 +1424,7 @@
 TAGS_INCL = *.h
 
 BASIC_SRC = \
+	async.c \
 	blowfish.c \
 	buffer.c \
 	charset.c \
@@ -1513,6 +1514,7 @@
 #LINT_SRC = $(BASIC_SRC)
 
 OBJ_COMMON = \
+	objects/async.o \
 	objects/buffer.o \
 	objects/blowfish.o \
 	objects/charset.o \
@@ -2484,6 +2486,9 @@
 objects:
 	mkdir objects
 
+objects/async.o: async.c
+	$(CCC) -o $@ async.c
+
 objects/blowfish.o: blowfish.c
 	$(CCC) -o $@ blowfish.c
 
diff -r d17ef148ada4 src/async.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/async.c	Mon Sep 02 18:20:17 2013 -0700
@@ -0,0 +1,60 @@
+#include "vim.h"
+
+#ifdef FEAT_ASYNC
+
+/*
+ * Insert a new timeout into the timeout linked list.
+ * This is called by set_timeout() in eval.c
+ */
+    void
+insert_timeout(to)
+    timeout_T *to;  /* timeout to insert */
+{
+    timeout_T *cur = timeouts;
+    timeout_T *prev = NULL;
+
+    if (timeouts == NULL) {
+        timeouts = to;
+        return;
+    }
+    while (cur != NULL) {
+        if (cur->tm > to->tm) {
+            if (prev) {
+                prev->next = to;
+            } else {
+                timeouts = to;
+            }
+            to->next = cur;
+            return;
+        }
+        prev = cur;
+        cur = cur->next;
+    }
+}
+
+/*
+ * Execute timeouts that are due.
+ * This is called every ticktime milliseconds by low-level input functions.
+ */
+    void
+call_timeouts() {
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    unsigned long tm = now.tv_sec * 1000 + now.tv_usec/1000;
+    timeout_T *tmp;
+
+    while (timeouts != NULL && timeouts->tm < tm) {
+        call_func_retnr(timeouts->cmd, 0, 0, FALSE);
+        tmp = timeouts;
+        timeouts = timeouts->next;
+        if (tmp->interval == -1) {
+            free(tmp->cmd);
+            free(tmp);
+        } else {
+            tmp->tm = tm + tmp->interval;
+            insert_timeout(tmp);
+        }
+    }
+}
+
+#endif
diff -r d17ef148ada4 src/async.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/async.h	Mon Sep 02 18:20:17 2013 -0700
@@ -0,0 +1,5 @@
+
+EXTERN timeout_T *timeouts INIT(= NULL);
+
+void insert_timeout(timeout_T *to);
+void call_timeouts();
diff -r d17ef148ada4 src/eval.c
--- a/src/eval.c	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/eval.c	Mon Sep 02 18:20:17 2013 -0700
@@ -674,6 +674,11 @@
 static void f_setloclist __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_setmatches __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_setpos __ARGS((typval_T *argvars, typval_T *rettv));
+#ifdef FEAT_ASYNC
+static void f_canceltimeout __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_setinterval __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_settimeout __ARGS((typval_T *argvars, typval_T *rettv));
+#endif
 static void f_setqflist __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_setreg __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_settabvar __ARGS((typval_T *argvars, typval_T *rettv));
@@ -7861,6 +7866,9 @@
     {"byte2line",	1, 1, f_byte2line},
     {"byteidx",		2, 2, f_byteidx},
     {"call",		2, 3, f_call},
+#ifdef FEAT_ASYNC
+    {"canceltimeout", 1, 1, f_canceltimeout},
+#endif
 #ifdef FEAT_FLOAT
     {"ceil",		1, 1, f_ceil},
 #endif
@@ -8059,6 +8067,9 @@
     {"serverlist",	0, 0, f_serverlist},
     {"setbufvar",	3, 3, f_setbufvar},
     {"setcmdpos",	1, 1, f_setcmdpos},
+#ifdef FEAT_ASYNC
+    {"setinterval",    2, 2, f_setinterval},
+#endif
     {"setline",		2, 2, f_setline},
     {"setloclist",	2, 3, f_setloclist},
     {"setmatches",	1, 1, f_setmatches},
@@ -8067,6 +8078,9 @@
     {"setreg",		2, 3, f_setreg},
     {"settabvar",	3, 3, f_settabvar},
     {"settabwinvar",	4, 4, f_settabwinvar},
+#ifdef FEAT_ASYNC
+    {"settimeout",    2, 2, f_settimeout},
+#endif
     {"setwinvar",	3, 3, f_setwinvar},
 #ifdef FEAT_CRYPT
     {"sha256",		1, 1, f_sha256},
@@ -12416,6 +12430,9 @@
 #ifdef FEAT_RELTIME
 	"reltime",
 #endif
+#ifdef FEAT_ASYNC
+    "async",
+#endif
 #ifdef FEAT_QUICKFIX
 	"quickfix",
 #endif
@@ -16589,6 +16606,93 @@
 #endif
 }
 
+#ifdef FEAT_ASYNC
+static int timeout_id = 0;
+
+    static void
+set_timeout(argvars, rettv, interval)
+    typval_T    *argvars;
+    typval_T    *rettv;
+    int interval;
+{
+    long i = get_tv_number(&argvars[0]);
+    char_u *cmd = get_tv_string(&argvars[1]);
+    struct timeval now;
+    rettv->v_type = VAR_NUMBER;
+
+    if (i < 0) {
+        rettv->vval.v_number = -1;
+        EMSG2(_(e_invarg2), "Interval cannot be negative.");
+        return;
+    }
+
+    gettimeofday(&now, NULL);
+    timeout_T *to = malloc(sizeof(timeout_T));
+    to->id = timeout_id++;
+    rettv->vval.v_number = to->id;
+    to->tm = now.tv_sec * 1000 + now.tv_usec/1000 + i;
+    to->cmd = (char_u*)strdup((char*)cmd);
+    to->interval = interval ? i : -1;
+    to->next = NULL;
+
+    insert_timeout(to);
+}
+
+    static void
+f_setinterval(argvars, rettv)
+    typval_T    *argvars;
+    typval_T    *rettv;
+{
+    set_timeout(argvars, rettv, TRUE);
+}
+
+    static void
+f_settimeout(argvars, rettv)
+    typval_T    *argvars;
+    typval_T    *rettv;
+{
+    set_timeout(argvars, rettv, FALSE);
+}
+
+    static void
+f_canceltimeout(argvars, rettv)
+    typval_T    *argvars;
+    typval_T    *rettv;
+{
+    long id = get_tv_number(&argvars[0]);
+    if (id < 0) {
+        rettv->vval.v_number = -1;
+        EMSG2(_(e_invarg2), "Timeout id cannot be negative.");
+        return;
+    }
+
+    timeout_T *tmp = timeouts;
+    timeout_T *prev = NULL;
+    timeout_T *next;
+    while (tmp != NULL) {
+        next = tmp->next;
+        if (tmp->id == id) {
+            if (prev) {
+                prev->next = next;
+            } else {
+                timeouts = next;
+            }
+            free(tmp->cmd);
+            free(tmp);
+            rettv->vval.v_number = 0;
+            rettv->v_type = VAR_NUMBER;
+            return;
+        } else {
+            prev = tmp;
+        }
+        tmp = next;
+    }
+    rettv->vval.v_number = 1;
+    rettv->v_type = VAR_NUMBER;
+    EMSG2(_(e_invarg2), "Timeout id not found.");
+}
+#endif
+
 /*
  * "setpos()" function
  */
diff -r d17ef148ada4 src/feature.h
--- a/src/feature.h	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/feature.h	Mon Sep 02 18:20:17 2013 -0700
@@ -467,6 +467,13 @@
 #endif
 
 /*
+ * +async		settimeout and setinterval functions.
+ */
+#if defined(FEAT_NORMAL)
+# define FEAT_ASYNC
+#endif
+
+/*
  * +diff		Displaying diffs in a nice way.
  *			Requires +windows and +autocmd.
  */
diff -r d17ef148ada4 src/gui.c
--- a/src/gui.c	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/gui.c	Mon Sep 02 18:20:17 2013 -0700
@@ -2898,18 +2898,31 @@
     gui_mch_start_blink();
 
     retval = FAIL;
+
+    int i = 0;
+    while (i < p_ut) {
+#ifdef FEAT_ASYNC
+		retval = gui_mch_wait_for_chars(p_tt);
+		call_timeouts();
+		i += p_tt;
+#else
+		retval = gui_mch_wait_for_chars(p_ut);
+		i += p_ut;
+#endif
+		if (retval == OK) {
+			break;
+		}
+    }
+
+#ifdef FEAT_AUTOCMD
     /*
      * We may want to trigger the CursorHold event.  First wait for
      * 'updatetime' and if nothing is typed within that time put the
      * K_CURSORHOLD key in the input buffer.
      */
-    if (gui_mch_wait_for_chars(p_ut) == OK)
-	retval = OK;
-#ifdef FEAT_AUTOCMD
-    else if (trigger_cursorhold())
+    if (retval == FAIL && trigger_cursorhold())
     {
 	char_u	buf[3];
-
 	/* Put K_CURSORHOLD in the input buffer. */
 	buf[0] = CSI;
 	buf[1] = KS_EXTRA;
@@ -2920,13 +2933,6 @@
     }
 #endif
 
-    if (retval == FAIL)
-    {
-	/* Blocking wait. */
-	before_blocking();
-	retval = gui_mch_wait_for_chars(-1L);
-    }
-
     gui_mch_stop_blink();
     return retval;
 }
diff -r d17ef148ada4 src/option.c
--- a/src/option.c	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/option.c	Mon Sep 02 18:20:17 2013 -0700
@@ -2590,6 +2590,11 @@
 			    (char_u *)NULL, PV_NONE,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
+#ifdef FEAT_ASYNC
+    {"ticktime",  "tt",   P_NUM|P_VI_DEF,
+			    (char_u *)&p_tt, PV_NONE,
+			    {(char_u *)100L, (char_u *)0L} SCRIPTID_INIT},
+#endif
     {"tildeop",	    "top",  P_BOOL|P_VI_DEF|P_VIM,
 			    (char_u *)&p_to, PV_NONE,
 			    {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
diff -r d17ef148ada4 src/option.h
--- a/src/option.h	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/option.h	Mon Sep 02 18:20:17 2013 -0700
@@ -795,6 +795,9 @@
 #ifdef FEAT_INS_EXPAND
 EXTERN char_u	*p_tsr;		/* 'thesaurus' */
 #endif
+#ifdef FEAT_ASYNC
+EXTERN long	p_tt;		/* 'ticktime' */
+#endif
 EXTERN int	p_ttimeout;	/* 'ttimeout' */
 EXTERN long	p_ttm;		/* 'ttimeoutlen' */
 EXTERN int	p_tbi;		/* 'ttybuiltin' */
diff -r d17ef148ada4 src/os_unix.c
--- a/src/os_unix.c	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/os_unix.c	Mon Sep 02 18:20:17 2013 -0700
@@ -379,6 +379,7 @@
     int		tb_change_cnt;
 {
     int		len;
+    int 	retval = FAIL;
 
 #ifdef FEAT_NETBEANS_INTG
     /* Process the queued netbeans messages. */
@@ -393,7 +394,8 @@
     if (wtime >= 0)
     {
 	while (WaitForChar(wtime) == 0)		/* no character available */
-	{
+	{	
+		call_timeouts();
 	    if (!do_resize)	/* return if not interrupted by resize */
 		return 0;
 	    handle_resize();
@@ -410,7 +412,22 @@
 	 * flush all the swap files to disk.
 	 * Also done when interrupted by SIGWINCH.
 	 */
-	if (WaitForChar(p_ut) == 0)
+
+#ifdef FEAT_ASYNC
+	int t = 0;
+	while (t < p_ut) {
+		retval = WaitForChar(p_tt);
+		call_timeouts();
+		t += p_tt;
+		if (retval == OK) {
+			break;
+		}
+	}
+#else
+	retval = WaitForChar(p_ut);
+#endif
+
+	if (retval == FAIL)
 	{
 #ifdef FEAT_AUTOCMD
 	    if (trigger_cursorhold() && maxlen >= 3
@@ -440,12 +457,29 @@
 	 * We want to be interrupted by the winch signal
 	 * or by an event on the monitored file descriptors.
 	 */
+
+	
+	#ifdef FEAT_ASYNC
+	while (TRUE) {
+		retval = WaitForChar(p_tt);
+		call_timeouts();
+		if (retval == OK) {
+			break;
+		}
+	    if (do_resize) {
+    	    /* interrupted by SIGWINCH signal */
+    		handle_resize();
+    	    return 0;
+	    }
+	}
+	#else
 	if (WaitForChar(-1L) == 0)
 	{
 	    if (do_resize)	    /* interrupted by SIGWINCH signal */
 		handle_resize();
 	    return 0;
 	}
+	#endif
 #endif
 
 	/* If input was put directly in typeahead buffer bail out here. */
diff -r d17ef148ada4 src/structs.h
--- a/src/structs.h	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/structs.h	Mon Sep 02 18:20:17 2013 -0700
@@ -2540,3 +2540,17 @@
   UINT32_T state[8];
   char_u   buffer[64];
 } context_sha256_T;
+
+#ifdef FEAT_ASYNC
+/*
+ * Used for async settimeout/interval.
+ */
+struct timeout_T {
+    int id;                     /* timeout/interval id */
+    int interval;               /* interval period if interval, otherwise -1 */
+    unsigned long tm;           /* time to fire (epoch milliseconds) */
+    char_u *cmd;                /* vim command to run */
+    struct timeout_T *next;     /* pointer to next timeout in linked list */
+};
+typedef struct timeout_T timeout_T;
+#endif
diff -r d17ef148ada4 src/version.c
--- a/src/version.c	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/version.c	Mon Sep 02 18:20:17 2013 -0700
@@ -77,6 +77,11 @@
 #else
 	"-arabic",
 #endif
+#ifdef FEAT_ASYNC
+	"+async",
+#else
+	"-async",
+#endif
 #ifdef FEAT_AUTOCMD
 	"+autocmd",
 #else
diff -r d17ef148ada4 src/vim.h
--- a/src/vim.h	Fri Aug 30 17:29:16 2013 +0200
+++ b/src/vim.h	Mon Sep 02 18:20:17 2013 -0700
@@ -2123,6 +2123,10 @@
 # endif
 #endif
 
+#ifdef FEAT_ASYNC
+# include "async.h"
+#endif
+
 #if defined(FEAT_BROWSE) && defined(GTK_CHECK_VERSION)
 # if GTK_CHECK_VERSION(2,4,0)
 #  define USE_FILE_CHOOSER

Raspunde prin e-mail lui