To: vim_dev@googlegroups.com Subject: Patch 7.4.1336 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1336 Problem: Channel NL mode is not supported yet. Solution: Add NL mode support to channels. Files: src/channel.c, src/netbeans.c, src/structs.h, src/os_unix.d, src/os_win32.c, src/proto/channel.pro, src/proto/os_unix.pro, src/proto/os_win32.pro, src/testdir/test_channel.vim, src/testdir/test_channel_pipe.py *** ../vim-7.4.1335/src/channel.c 2016-02-16 15:06:54.653635399 +0100 --- src/channel.c 2016-02-16 19:21:46.979016087 +0100 *************** *** 669,680 **** } /* ! * Set the json mode of channel "channel" to "ch_mode". */ void ! channel_set_json_mode(channel_T *channel, ch_mode_T ch_mode) { ! channel->ch_mode = ch_mode; } /* --- 669,680 ---- } /* ! * Set the mode of channel "channel" to "mode". */ void ! channel_set_mode(channel_T *channel, ch_mode_T mode) { ! channel->ch_mode = mode; } /* *************** *** 1057,1063 **** /* * Invoke a callback for channel "channel" if needed. ! * Return OK when a message was handled, there might be another one. */ static int may_invoke_callback(channel_T *channel) --- 1057,1064 ---- /* * Invoke a callback for channel "channel" if needed. ! * 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,1080 **** /* this channel is handled elsewhere (netbeans) */ return FALSE; ! if (ch_mode != MODE_RAW) { /* Get any json message in the queue. */ if (channel_get_json(channel, -1, &listtv) == FAIL) --- 1075,1081 ---- /* this channel is handled elsewhere (netbeans) */ return FALSE; ! 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,1130 **** } else if (channel_peek(channel) == NULL) { ! /* nothing to read on raw channel */ return FALSE; } else { ! /* If there is no callback, don't do anything. */ if (channel->ch_callback == NULL) return FALSE; - /* 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; } --- 1114,1164 ---- } else if (channel_peek(channel) == NULL) { ! /* nothing to read on RAW or NL channel */ return FALSE; } else { ! /* 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); argv[1].v_type = VAR_STRING; argv[1].vval.v_string = msg; } *************** *** 1276,1287 **** 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; /* append node to the tail of the queue */ node->rq_next = NULL; --- 1310,1329 ---- return FAIL; /* out of memory */ } ! 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,1590 **** } /* ! * Read from raw channel "channel". Blocks until there is something to read or ! * the timeout expires. * 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) ! { ! sock_T fd = get_read_fd(channel); - /* 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) --- 1612,1644 ---- } /* ! * 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) { ! 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) ! { ! 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; /* Wait for up to the channel timeout. */ if (fd == CHAN_FD_INVALID || channel_wait(channel, fd, channel->ch_timeout) == FAIL) *************** *** 1592,1600 **** channel_read(channel, -1, "channel_read_block"); } ! /* TODO: only get the first message */ ! ch_log(channel, "Returning readahead\n"); ! return channel_get_all(channel); } /* --- 1646,1675 ---- channel_read(channel, -1, "channel_read_block"); } ! 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; } /* *** ../vim-7.4.1335/src/structs.h 2016-02-15 21:56:42.725119689 +0100 --- src/structs.h 2016-02-16 18:26:49.949294135 +0100 *************** *** 1372,1377 **** --- 1372,1385 ---- 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 *** ../vim-7.4.1335/src/os_win32.c 2016-02-16 16:39:47.923933523 +0100 --- src/os_win32.c 2016-02-16 18:43:28.618921026 +0100 *************** *** 5034,5040 **** #if defined(FEAT_JOB) || defined(PROTO) void ! mch_start_job(char *cmd, job_T *job) { STARTUPINFO si; PROCESS_INFORMATION pi; --- 5034,5040 ---- #if defined(FEAT_JOB) || defined(PROTO) void ! mch_start_job(char *cmd, job_T *job, jobopt_T *options) { STARTUPINFO si; PROCESS_INFORMATION pi; *************** *** 5121,5126 **** --- 5121,5127 ---- 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); *** ../vim-7.4.1335/src/proto/channel.pro 2016-02-15 21:56:42.721119732 +0100 --- src/proto/channel.pro 2016-02-16 17:53:44.893894420 +0100 *************** *** 7,13 **** 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_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); --- 7,13 ---- 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_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); *** ../vim-7.4.1335/src/proto/os_unix.pro 2016-02-12 19:30:20.353885756 +0100 --- src/proto/os_unix.pro 2016-02-16 18:43:41.154790744 +0100 *************** *** 57,63 **** 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); char *mch_job_status(job_T *job); int mch_stop_job(job_T *job, char_u *how); void mch_clear_job(job_T *job); --- 57,63 ---- 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, 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); *** ../vim-7.4.1335/src/proto/os_win32.pro 2016-02-12 19:30:20.353885756 +0100 --- src/proto/os_win32.pro 2016-02-16 18:43:35.862845741 +0100 *************** *** 40,46 **** 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); char *mch_job_status(job_T *job); int mch_stop_job(job_T *job, char_u *how); void mch_clear_job(job_T *job); --- 40,46 ---- 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, 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); *** ../vim-7.4.1335/src/testdir/test_channel.vim 2016-02-16 14:07:36.190482636 +0100 --- src/testdir/test_channel.vim 2016-02-16 19:23:23.150013903 +0100 *************** *** 284,290 **** endif endfunc ! func Test_pipe() if !has('job') return endif --- 284,313 ---- endif endfunc ! 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,301 **** try let handle = job_getchannel(job) call ch_sendraw(handle, "echo something\n", 0) ! call assert_equal("something\n", ch_readraw(handle)) let reply = ch_sendraw(handle, "quit\n") ! call assert_equal("Goodbye!\n", reply) finally call job_stop(job) endtry --- 316,329 ---- try let handle = job_getchannel(job) call ch_sendraw(handle, "echo something\n", 0) ! 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!", reply) finally call job_stop(job) endtry *** ../vim-7.4.1335/src/testdir/test_channel_pipe.py 2016-02-13 17:04:08.426819018 +0100 --- src/testdir/test_channel_pipe.py 2016-02-16 19:02:36.058998429 +0100 *************** *** 21,24 **** --- 21,27 ---- 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() *** ../vim-7.4.1335/src/version.c 2016-02-16 16:39:47.923933523 +0100 --- src/version.c 2016-02-16 18:16:14.023894517 +0100 *************** *** 749,750 **** --- 749,752 ---- { /* Add new patch number below this line */ + /**/ + 1336, /**/ -- He was not in the least bit scared to be mashed into a pulp Or to have his eyes gouged out and his elbows broken; To have his kneecaps split and his body burned away And his limbs all hacked and mangled, brave Sir Robin. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///