]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 7.4.1398 v7.4.1398
authorBram Moolenaar <Bram@vim.org>
Tue, 23 Feb 2016 12:20:22 +0000 (13:20 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 23 Feb 2016 12:20:22 +0000 (13:20 +0100)
Problem:    The close-cb option is not implemented yet.
Solution:   Implemente close-cb. (Yasuhiro Matsumoto)

src/channel.c
src/eval.c
src/proto/channel.pro
src/structs.h
src/testdir/test_channel.py
src/testdir/test_channel.vim
src/version.c

index 71fd4b687b236a1eaf013f5974928dfe6f0f3bf8..e9068fee5e0b322c166cbc1036b2e49b3cd39295 100644 (file)
@@ -485,7 +485,11 @@ static char *e_cannot_connect = N_("E902: Cannot connect to port");
  * Returns NULL for failure.
  */
     channel_T *
-channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void))
+channel_open(
+       char *hostname,
+       int port_in,
+       int waittime,
+       void (*nb_close_cb)(void))
 {
     int                        sd = -1;
     struct sockaddr_in server;
@@ -711,7 +715,7 @@ channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void))
     }
 
     channel->CH_SOCK_FD = (sock_T)sd;
-    channel->ch_close_cb = close_cb;
+    channel->ch_nb_close_cb = nb_close_cb;
 
 #ifdef FEAT_GUI
     channel_gui_register(channel);
@@ -790,6 +794,15 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
        else
            *cbp = NULL;
     }
+    if (opt->jo_set & JO_CLOSE_CALLBACK)
+    {
+       cbp = &channel->ch_close_cb;
+       vim_free(*cbp);
+       if (opt->jo_close_cb != NULL && *opt->jo_close_cb != NUL)
+           *cbp = vim_strsave(opt->jo_close_cb);
+       else
+           *cbp = NULL;
+    }
 }
 
 /*
@@ -1255,7 +1268,7 @@ may_invoke_callback(channel_T *channel, int part)
     ch_mode_T  ch_mode = channel->ch_part[part].ch_mode;
     char_u     *callback = NULL;
 
-    if (channel->ch_close_cb != NULL)
+    if (channel->ch_nb_close_cb != NULL)
        /* this channel is handled elsewhere (netbeans) */
        return FALSE;
 
@@ -1477,7 +1490,28 @@ channel_close(channel_T *channel)
     }
 #endif
 
-    channel->ch_close_cb = NULL;
+    if (channel->ch_close_cb != NULL)
+    {
+         typval_T      argv[1];
+         typval_T      rettv;
+         int           dummy;
+
+         /* invoke the close callback; increment the refcount to avoid it
+          * being freed halfway */
+         argv[0].v_type = VAR_CHANNEL;
+         argv[0].vval.v_channel = channel;
+         ++channel->ch_refcount;
+         call_func(channel->ch_close_cb, (int)STRLEN(channel->ch_close_cb),
+                                &rettv, 1, argv, 0L, 0L, &dummy, TRUE, NULL);
+         clear_tv(&rettv);
+         --channel->ch_refcount;
+
+         /* the callback is only called once */
+         vim_free(channel->ch_close_cb);
+         channel->ch_close_cb = NULL;
+    }
+
+    channel->ch_nb_close_cb = NULL;
     channel_clear(channel);
 }
 
@@ -1539,6 +1573,8 @@ channel_clear(channel_T *channel)
 #endif
     vim_free(channel->ch_callback);
     channel->ch_callback = NULL;
+    vim_free(channel->ch_close_cb);
+    channel->ch_close_cb = NULL;
 }
 
 #if defined(EXITFREE) || defined(PROTO)
@@ -1732,8 +1768,8 @@ channel_read(channel_T *channel, int part, char *func)
         * keep stdin and stderr open?  Probably not, assume the other side
         * has died. */
        channel_close(channel);
-       if (channel->ch_close_cb != NULL)
-           (*channel->ch_close_cb)();
+       if (channel->ch_nb_close_cb != NULL)
+           (*channel->ch_nb_close_cb)();
 
        if (len < 0)
        {
index bf3bcb948cfa0a55acc89b73ac0dcab556ff735a..341199c17f7bd719cd914af87de946c63a8bf602 100644 (file)
@@ -10067,6 +10067,18 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported)
                    return FAIL;
                }
            }
+           else if (STRCMP(hi->hi_key, "close-cb") == 0)
+           {
+               if (!(supported & JO_CLOSE_CALLBACK))
+                   break;
+               opt->jo_set |= JO_CLOSE_CALLBACK;
+               opt->jo_close_cb = get_callback(item);
+               if (opt->jo_close_cb == NULL)
+               {
+                   EMSG2(_(e_invarg2), "close-cb");
+                   return FAIL;
+               }
+           }
            else if (STRCMP(hi->hi_key, "waittime") == 0)
            {
                if (!(supported & JO_WAITTIME))
@@ -18924,7 +18936,7 @@ item_compare2(const void *s1, const void *s2)
 
     rettv.v_type = VAR_UNKNOWN;                /* clear_tv() uses this */
     res = call_func(sortinfo->item_compare_func,
-                                (int)STRLEN(sortinfo->item_compare_func),
+                                (int)STRLEN(sortinfo->item_compare_func),
                                 &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
                                 sortinfo->item_compare_selfdict);
     clear_tv(&argv[0]);
index fa06f4f294126f74e5726081ecf8affa08d66554..81935bf9a559a87b14f6055071e4217d7b0a75ff 100644 (file)
@@ -7,10 +7,10 @@ channel_T *add_channel(void);
 void channel_free(channel_T *channel);
 void channel_gui_register(channel_T *channel);
 void channel_gui_register_all(void);
-channel_T *channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
+channel_T *channel_open(char *hostname, int port_in, int waittime, void (*nb_close_cb)(void));
 void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
 void channel_set_job(channel_T *channel, job_T *job);
-void channel_set_options(channel_T *channel, jobopt_T *options);
+void channel_set_options(channel_T *channel, jobopt_T *opt);
 void channel_set_req_callback(channel_T *channel, int part, char_u *callback, int id);
 char_u *channel_get(channel_T *channel, int part);
 int channel_collapse(channel_T *channel, int part);
index e1720ce38911b470c92db9f2cc1a818d747d87e1..cf5ae2b179f20d497871b3ffefefffb7fbb2b7dd 100644 (file)
@@ -1366,9 +1366,12 @@ struct channel_S {
                                 * first error until the connection works
                                 * again. */
 
-    void       (*ch_close_cb)(void); /* callback for when channel is closed */
+    void       (*ch_nb_close_cb)(void);
+                               /* callback for Netbeans when channel is
+                                * closed */
 
     char_u     *ch_callback;   /* call when any msg is not handled */
+    char_u     *ch_close_cb;   /* call when channel is closed */
 
     job_T      *ch_job;        /* Job that uses this channel; this does not
                                 * count as a reference to avoid a circular
@@ -1377,25 +1380,27 @@ struct channel_S {
     int                ch_refcount;    /* reference count */
 };
 
-#define JO_MODE                0x0001  /* channel mode */
-#define JO_IN_MODE     0x0002  /* stdin mode */
-#define JO_OUT_MODE    0x0004  /* stdout mode */
-#define JO_ERR_MODE    0x0008  /* stderr mode */
-#define JO_CALLBACK    0x0010  /* channel callback */
-#define JO_OUT_CALLBACK        0x0020  /* stdout callback */
-#define JO_ERR_CALLBACK        0x0040  /* stderr callback */
-#define JO_WAITTIME    0x0080  /* only for ch_open() */
-#define JO_TIMEOUT     0x0100  /* all timeouts */
-#define JO_OUT_TIMEOUT 0x0200  /* stdout timeouts */
-#define JO_ERR_TIMEOUT 0x0400  /* stderr timeouts */
-#define JO_PART                0x0800  /* "part" */
-#define JO_ID          0x1000  /* "id" */
-#define JO_STOPONEXIT  0x2000  /* "stoponexit" */
-#define JO_EXIT_CB     0x4000  /* "exit-cb" */
-#define JO_ALL         0xffffff
+#define JO_MODE                    0x0001      /* channel mode */
+#define JO_IN_MODE         0x0002      /* stdin mode */
+#define JO_OUT_MODE        0x0004      /* stdout mode */
+#define JO_ERR_MODE        0x0008      /* stderr mode */
+#define JO_CALLBACK        0x0010      /* channel callback */
+#define JO_OUT_CALLBACK            0x0020      /* stdout callback */
+#define JO_ERR_CALLBACK            0x0040      /* stderr callback */
+#define JO_CLOSE_CALLBACK   0x0080     /* close callback */
+#define JO_WAITTIME        0x0100      /* only for ch_open() */
+#define JO_TIMEOUT         0x0200      /* all timeouts */
+#define JO_OUT_TIMEOUT     0x0400      /* stdout timeouts */
+#define JO_ERR_TIMEOUT     0x0800      /* stderr timeouts */
+#define JO_PART                    0x1000      /* "part" */
+#define JO_ID              0x2000      /* "id" */
+#define JO_STOPONEXIT      0x4000      /* "stoponexit" */
+#define JO_EXIT_CB         0x8000      /* "exit-cb" */
+#define JO_ALL             0xffffff
 
 #define JO_MODE_ALL    (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
-#define JO_CB_ALL      (JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK)
+#define JO_CB_ALL \
+    (JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK + JO_CLOSE_CALLBACK)
 #define JO_TIMEOUT_ALL (JO_TIMEOUT + JO_OUT_TIMEOUT + JO_ERR_TIMEOUT)
 
 /*
@@ -1412,6 +1417,7 @@ typedef struct
     char_u     *jo_callback;   /* not allocated! */
     char_u     *jo_out_cb;     /* not allocated! */
     char_u     *jo_err_cb;     /* not allocated! */
+    char_u     *jo_close_cb;   /* not allocated! */
     int                jo_waittime;
     int                jo_timeout;
     int                jo_out_timeout;
index 26c7dea8d73300663de33d0a8ac0bcb7202cbb8a..9a3c9213ad5e2c3aa961b7c5b3cb0ab27c708791 100644 (file)
@@ -140,6 +140,10 @@ class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
                         print("sending: {}".format(cmd))
                         self.request.sendall(cmd.encode('utf-8'))
                         response = ""
+                    elif decoded[1] == 'close me':
+                        print("closing")
+                        self.request.close()
+                        response = ""
                     elif decoded[1] == 'wait a bit':
                         time.sleep(0.2)
                         response = "waited"
index 2b4b1892595d8362bebd2eb95fece5cb9b1180eb..2e74e9fe3413f984c26ebd6b3a4e8c8c48828ec3 100644 (file)
@@ -471,9 +471,9 @@ endfunc
 
 """""""""
 
-let s:job_ret = 'not yet'
+let s:job_exit_ret = 'not yet'
 function MyExitCb(job, status)
-  let s:job_ret = 'done'
+  let s:job_exit_ret = 'done'
 endfunc
 
 function s:test_exit_callback(port)
@@ -490,6 +490,32 @@ func Test_exit_callback()
 
     " calling job_status() triggers the callback
     call job_status(s:exit_job)
-    call assert_equal('done', s:job_ret)
+    call assert_equal('done', s:job_exit_ret)
   endif
 endfunc
+
+"""""""""
+
+let s:ch_close_ret = 'alive'
+function MyCloseCb(ch)
+  let s:ch_close_ret = 'closed'
+endfunc
+
+function s:test_close_callback(port)
+  let handle = ch_open('localhost:' . a:port, s:chopt)
+  if ch_status(handle) == "fail"
+    call assert_false(1, "Can't open channel")
+    return
+  endif
+  call ch_setoptions(handle, {'close-cb': 'MyCloseCb'})
+
+  call assert_equal('', ch_sendexpr(handle, 'close me'))
+  sleep 20m
+  call assert_equal('closed', s:ch_close_ret)
+endfunc
+
+func Test_close_callback()
+  call ch_log('Test_close_callback()')
+  call s:run_server('s:test_close_callback')
+endfunc
+
index b8cd1113357aed3e6fd93dbe8d50220078a16046..c23db828c3b6b8e6dd27290516f82d82e3ee976e 100644 (file)
@@ -748,6 +748,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1398,
 /**/
     1397,
 /**/