summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-02-16 19:25:12 +0100
committerBram Moolenaar <Bram@vim.org>2016-02-16 19:25:12 +0100
commit9a6e33a19b18f20c25b73392cd2faa3ec4890c8c (patch)
tree2c13d3d751e1e635c4ca4fa8dbc854598a669f89
parent5d54a045989599468b7a971fc354b0cba4e2b09d (diff)
downloadvim-git-9a6e33a19b18f20c25b73392cd2faa3ec4890c8c.tar.gz
patch 7.4.1336v7.4.1336
Problem: Channel NL mode is not supported yet. Solution: Add NL mode support to channels.
-rw-r--r--src/channel.c127
-rw-r--r--src/os_win32.c3
-rw-r--r--src/proto/channel.pro2
-rw-r--r--src/proto/os_unix.pro2
-rw-r--r--src/proto/os_win32.pro2
-rw-r--r--src/structs.h8
-rw-r--r--src/testdir/test_channel.vim34
-rw-r--r--src/testdir/test_channel_pipe.py3
-rw-r--r--src/version.c2
9 files changed, 150 insertions, 33 deletions
diff --git a/src/channel.c b/src/channel.c
index e0ae267a7..3cfe1bea3 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -669,12 +669,12 @@ channel_set_job(channel_T *channel, job_T *job)
}
/*
- * Set the json mode of channel "channel" to "ch_mode".
+ * Set the mode of channel "channel" to "mode".
*/
void
-channel_set_json_mode(channel_T *channel, ch_mode_T ch_mode)
+channel_set_mode(channel_T *channel, ch_mode_T mode)
{
- channel->ch_mode = ch_mode;
+ channel->ch_mode = mode;
}
/*
@@ -1057,7 +1057,8 @@ channel_exe_cmd(channel_T *channel, char_u *cmd, typval_T *arg2, typval_T *arg3)
/*
* Invoke a callback for channel "channel" if needed.
- * Return OK when a message was handled, there might be another one.
+ * TODO: add "which" argument, read stderr.
+ * Return TRUE when a message was handled, there might be another one.
*/
static int
may_invoke_callback(channel_T *channel)
@@ -1074,7 +1075,7 @@ may_invoke_callback(channel_T *channel)
/* this channel is handled elsewhere (netbeans) */
return FALSE;
- if (ch_mode != MODE_RAW)
+ if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
{
/* Get any json message in the queue. */
if (channel_get_json(channel, -1, &listtv) == FAIL)
@@ -1113,18 +1114,51 @@ may_invoke_callback(channel_T *channel)
}
else if (channel_peek(channel) == NULL)
{
- /* nothing to read on raw channel */
+ /* nothing to read on RAW or NL channel */
return FALSE;
}
else
{
- /* If there is no callback, don't do anything. */
+ /* If there is no callback drop the message. */
if (channel->ch_callback == NULL)
+ {
+ while ((msg = channel_get(channel)) != NULL)
+ vim_free(msg);
return FALSE;
+ }
+
+ if (ch_mode == MODE_NL)
+ {
+ char_u *nl;
+ char_u *buf;
+
+ /* See if we have a message ending in NL in the first buffer. If
+ * not try to concatenate the first and the second buffer. */
+ while (TRUE)
+ {
+ buf = channel_peek(channel);
+ nl = vim_strchr(buf, NL);
+ if (nl != NULL)
+ break;
+ if (channel_collapse(channel) == FAIL)
+ return FALSE; /* incomplete message */
+ }
+ if (nl[1] == NUL)
+ /* get the whole buffer */
+ msg = channel_get(channel);
+ else
+ {
+ /* Copy the message into allocated memory and remove it from
+ * the buffer. */
+ msg = vim_strnsave(buf, (int)(nl - buf));
+ mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1);
+ }
+ }
+ else
+ /* For a raw channel we don't know where the message ends, just
+ * get everything we have. */
+ msg = channel_get_all(channel);
- /* For a raw channel we don't know where the message ends, just get
- * everything. */
- msg = channel_get_all(channel);
argv[1].v_type = VAR_STRING;
argv[1].vval.v_string = msg;
}
@@ -1276,12 +1310,20 @@ channel_save(channel_T *channel, char_u *buf, int len)
return FAIL; /* out of memory */
}
- /* TODO: don't strip CR when channel is in raw mode */
- p = node->rq_buffer;
- for (i = 0; i < len; ++i)
- if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL)
- *p++ = buf[i];
- *p = NUL;
+ if (channel->ch_mode == MODE_NL)
+ {
+ /* Drop any CR before a NL. */
+ p = node->rq_buffer;
+ for (i = 0; i < len; ++i)
+ if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL)
+ *p++ = buf[i];
+ *p = NUL;
+ }
+ else
+ {
+ mch_memmove(node->rq_buffer, buf, len);
+ node->rq_buffer[len] = NUL;
+ }
/* append node to the tail of the queue */
node->rq_next = NULL;
@@ -1570,21 +1612,33 @@ channel_read(channel_T *channel, int which, char *func)
}
/*
- * Read from raw channel "channel". Blocks until there is something to read or
- * the timeout expires.
+ * Read from RAW or NL channel "channel". Blocks until there is something to
+ * read or the timeout expires.
+ * TODO: add "which" argument and read from stderr.
* Returns what was read in allocated memory.
* Returns NULL in case of error or timeout.
*/
char_u *
channel_read_block(channel_T *channel)
{
- ch_log(channel, "Reading raw\n");
- if (channel_peek(channel) == NULL)
+ char_u *buf;
+ char_u *msg;
+ ch_mode_T mode = channel->ch_mode;
+ sock_T fd = get_read_fd(channel);
+ char_u *nl;
+
+ ch_logsn(channel, "Blocking %s read, timeout: %d msec\n",
+ mode == MODE_RAW ? "RAW" : "NL", channel->ch_timeout);
+
+ while (TRUE)
{
- sock_T fd = get_read_fd(channel);
+ buf = channel_peek(channel);
+ if (buf != NULL && (mode == MODE_RAW
+ || (mode == MODE_NL && vim_strchr(buf, NL) != NULL)))
+ break;
+ if (buf != NULL && channel_collapse(channel) == OK)
+ continue;
- /* TODO: read both out and err if they are different */
- ch_log(channel, "No readahead\n");
/* Wait for up to the channel timeout. */
if (fd == CHAN_FD_INVALID
|| channel_wait(channel, fd, channel->ch_timeout) == FAIL)
@@ -1592,9 +1646,30 @@ channel_read_block(channel_T *channel)
channel_read(channel, -1, "channel_read_block");
}
- /* TODO: only get the first message */
- ch_log(channel, "Returning readahead\n");
- return channel_get_all(channel);
+ if (mode == MODE_RAW)
+ {
+ msg = channel_get_all(channel);
+ }
+ else
+ {
+ nl = vim_strchr(buf, NL);
+ if (nl[1] == NUL)
+ {
+ /* get the whole buffer */
+ msg = channel_get(channel);
+ *nl = NUL;
+ }
+ else
+ {
+ /* Copy the message into allocated memory and remove it from the
+ * buffer. */
+ msg = vim_strnsave(buf, (int)(nl - buf));
+ mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1);
+ }
+ }
+ if (log_fd != NULL)
+ ch_logn(channel, "Returning %d bytes\n", (int)STRLEN(msg));
+ return msg;
}
/*
diff --git a/src/os_win32.c b/src/os_win32.c
index 4fd117f9e..c6f5cc26f 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -5034,7 +5034,7 @@ mch_call_shell(
#if defined(FEAT_JOB) || defined(PROTO)
void
-mch_start_job(char *cmd, job_T *job)
+mch_start_job(char *cmd, job_T *job, jobopt_T *options)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
@@ -5121,6 +5121,7 @@ mch_start_job(char *cmd, job_T *job)
job->jv_channel = channel;
channel_set_pipes(channel, (sock_T)ifd[1], (sock_T)ofd[0], (sock_T)efd[0]);
channel_set_job(channel, job);
+ channel_set_mode(channel, options->jo_mode);
# ifdef FEAT_GUI
channel_gui_register(channel);
diff --git a/src/proto/channel.pro b/src/proto/channel.pro
index c5e61be5c..e1c88627f 100644
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -7,7 +7,7 @@ void channel_gui_register_all(void);
channel_T *channel_open(char *hostname, int port_in, int waittime, void (*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_json_mode(channel_T *channel, ch_mode_T ch_mode);
+void channel_set_mode(channel_T *channel, ch_mode_T ch_mode);
void channel_set_timeout(channel_T *channel, int timeout);
void channel_set_callback(channel_T *channel, char_u *callback);
void channel_set_req_callback(channel_T *channel, char_u *callback, int id);
diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro
index c97f7fecf..25d25797e 100644
--- a/src/proto/os_unix.pro
+++ b/src/proto/os_unix.pro
@@ -57,7 +57,7 @@ void mch_set_shellsize(void);
void mch_new_shellsize(void);
int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
int mch_call_shell(char_u *cmd, int options);
-void mch_start_job(char **argv, job_T *job);
+void mch_start_job(char **argv, job_T *job, jobopt_T *options);
char *mch_job_status(job_T *job);
int mch_stop_job(job_T *job, char_u *how);
void mch_clear_job(job_T *job);
diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro
index 2fa6e1024..19c59ec96 100644
--- a/src/proto/os_win32.pro
+++ b/src/proto/os_win32.pro
@@ -40,7 +40,7 @@ void mch_set_shellsize(void);
void mch_new_shellsize(void);
void mch_set_winsize_now(void);
int mch_call_shell(char_u *cmd, int options);
-void mch_start_job(char *cmd, job_T *job);
+void mch_start_job(char *cmd, job_T *job, jobopt_T *options);
char *mch_job_status(job_T *job);
int mch_stop_job(job_T *job, char_u *how);
void mch_clear_job(job_T *job);
diff --git a/src/structs.h b/src/structs.h
index 723876723..eb72f90f2 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1372,6 +1372,14 @@ struct channel_S {
int ch_refcount; /* reference count */
};
+/*
+ * Options for job commands.
+ */
+typedef struct
+{
+ ch_mode_T jo_mode;
+} jobopt_T;
+
/* structure used for explicit stack while garbage collecting hash tables */
typedef struct ht_stack_S
diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim
index 62b5c89b4..e9c2a98e7 100644
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -284,7 +284,30 @@ func Test_connect_waittime()
endif
endfunc
-func Test_pipe()
+func Test_raw_pipe()
+ if !has('job')
+ return
+ endif
+ let job = job_start(s:python . " test_channel_pipe.py", {'mode': 'raw'})
+ call assert_equal("run", job_status(job))
+ try
+ let handle = job_getchannel(job)
+ call ch_sendraw(handle, "echo something\n", 0)
+ let msg = ch_readraw(handle)
+ call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
+
+ call ch_sendraw(handle, "double this\n", 0)
+ let msg = ch_readraw(handle)
+ call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
+
+ let reply = ch_sendraw(handle, "quit\n")
+ call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g'))
+ finally
+ call job_stop(job)
+ endtry
+endfunc
+
+func Test_nl_pipe()
if !has('job')
return
endif
@@ -293,9 +316,14 @@ func Test_pipe()
try
let handle = job_getchannel(job)
call ch_sendraw(handle, "echo something\n", 0)
- call assert_equal("something\n", ch_readraw(handle))
+ call assert_equal("something", ch_readraw(handle))
+
+ call ch_sendraw(handle, "double this\n", 0)
+ call assert_equal("this", ch_readraw(handle))
+ call assert_equal("AND this", ch_readraw(handle))
+
let reply = ch_sendraw(handle, "quit\n")
- call assert_equal("Goodbye!\n", reply)
+ call assert_equal("Goodbye!", reply)
finally
call job_stop(job)
endtry
diff --git a/src/testdir/test_channel_pipe.py b/src/testdir/test_channel_pipe.py
index 495fa8012..5994d27ff 100644
--- a/src/testdir/test_channel_pipe.py
+++ b/src/testdir/test_channel_pipe.py
@@ -21,4 +21,7 @@ if __name__ == "__main__":
if typed.startswith("echo"):
print(typed[5:-1])
sys.stdout.flush()
+ if typed.startswith("double"):
+ print(typed[7:-1] + "\nAND " + typed[7:-1])
+ sys.stdout.flush()
diff --git a/src/version.c b/src/version.c
index 15d40bb65..b07f6b816 100644
--- a/src/version.c
+++ b/src/version.c
@@ -748,6 +748,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1336,
+/**/
1335,
/**/
1334,