summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-02-23 13:20:22 +0100
committerBram Moolenaar <Bram@vim.org>2016-02-23 13:20:22 +0100
commit4e221c99e85ed40c98892068a01270b9e7492d98 (patch)
treed2b51bcd1f0adff723d86acfdc7d3d6481bcaf87
parent0bb6108eb4e1ecaed437bc507f514f5da7816d9e (diff)
patch 7.4.1398v7.4.1398
Problem: The close-cb option is not implemented yet. Solution: Implemente close-cb. (Yasuhiro Matsumoto)
-rw-r--r--src/channel.c48
-rw-r--r--src/eval.c14
-rw-r--r--src/proto/channel.pro4
-rw-r--r--src/structs.h42
-rw-r--r--src/testdir/test_channel.py4
-rw-r--r--src/testdir/test_channel.vim32
-rw-r--r--src/version.c2
7 files changed, 116 insertions, 30 deletions
diff --git a/src/channel.c b/src/channel.c
index 71fd4b687b..e9068fee5e 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -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)
{
diff --git a/src/eval.c b/src/eval.c
index bf3bcb948c..341199c17f 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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]);
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index fa06f4f294..81935bf9a5 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -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);
diff --git a/src/structs.h b/src/structs.h
index e1720ce389..cf5ae2b179 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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;
diff --git a/src/testdir/test_channel.py b/src/testdir/test_channel.py
index 26c7dea8d7..9a3c9213ad 100644
--- a/src/testdir/test_channel.py
+++ b/src/testdir/test_channel.py
@@ -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"
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 2b4b189259..2e74e9fe34 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -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
+
diff --git a/src/version.c b/src/version.c
index b8cd111335..c23db828c3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -749,6 +749,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1398,
+/**/
1397,
/**/
1396,