# HG changeset patch # User Christian Brabandt # Date 1512843305 -3600 # Node ID c522585ce88d61ab95ba166992c4d943f421d100 # Parent 59e53800d1fa9610f23aa6243e1a0eda6200e1bc patch 8.0.1381: ch_readraw() waits for NL if channel mode is NL commit https://github.com/vim/vim/commit/620ca2da372dc9c892022faff83d363c67cc5c45 Author: Bram Moolenaar Date: Sat Dec 9 19:13:13 2017 +0100 patch 8.0.1381: ch_readraw() waits for NL if channel mode is NL Problem: ch_readraw() waits for NL if channel mode is NL. Solution: Pass a "raw" flag to channel_read_block(). (Yasuhiro Matsumoto) diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -3313,11 +3313,12 @@ channel_read(channel_T *channel, ch_part /* * Read from RAW or NL "channel"/"part". Blocks until there is something to * read or the timeout expires. + * When "raw" is TRUE don't block waiting on a NL. * Returns what was read in allocated memory. * Returns NULL in case of error or timeout. */ - char_u * -channel_read_block(channel_T *channel, ch_part_T part, int timeout) + static char_u * +channel_read_block(channel_T *channel, ch_part_T part, int timeout, int raw) { char_u *buf; char_u *msg; @@ -3327,7 +3328,7 @@ channel_read_block(channel_T *channel, c readq_T *node; ch_log(channel, "Blocking %s read, timeout: %d msec", - mode == MODE_RAW ? "RAW" : "NL", timeout); + mode == MODE_RAW ? "RAW" : "NL", timeout); while (TRUE) { @@ -3340,6 +3341,10 @@ channel_read_block(channel_T *channel, c break; if (channel_collapse(channel, part, mode == MODE_NL) == OK) continue; + /* If not blocking or nothing more is coming then return what we + * have. */ + if (raw || fd == INVALID_FD) + break; } /* Wait for up to the channel timeout. */ @@ -3366,11 +3371,16 @@ channel_read_block(channel_T *channel, c nl = channel_first_nl(node); /* Convert NUL to NL, the internal representation. */ - for (p = buf; p < nl && p < buf + node->rq_buflen; ++p) + for (p = buf; (nl == NULL || p < nl) && p < buf + node->rq_buflen; ++p) if (*p == NUL) *p = NL; - if (nl + 1 == buf + node->rq_buflen) + if (nl == NULL) + { + /* must be a closed channel with missing NL */ + msg = channel_get(channel, part); + } + else if (nl + 1 == buf + node->rq_buflen) { /* get the whole buffer */ msg = channel_get(channel, part); @@ -3513,7 +3523,8 @@ common_channel_read(typval_T *argvars, t timeout = opt.jo_timeout; if (raw || mode == MODE_RAW || mode == MODE_NL) - rettv->vval.v_string = channel_read_block(channel, part, timeout); + rettv->vval.v_string = channel_read_block(channel, part, + timeout, raw); else { if (opt.jo_set & JO_ID) @@ -3955,7 +3966,8 @@ ch_raw_common(typval_T *argvars, typval_ timeout = opt.jo_timeout; else timeout = channel_get_timeout(channel, part_read); - rettv->vval.v_string = channel_read_block(channel, part_read, timeout); + rettv->vval.v_string = channel_read_block(channel, part_read, + timeout, TRUE); } free_job_options(&opt); } diff --git a/src/proto/channel.pro b/src/proto/channel.pro --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -31,7 +31,6 @@ void channel_close(channel_T *channel, i void channel_close_in(channel_T *channel); void channel_clear(channel_T *channel); void channel_free_all(void); -char_u *channel_read_block(channel_T *channel, ch_part_T part, int timeout); void common_channel_read(typval_T *argvars, typval_T *rettv, int raw); channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp); void channel_handle_events(int only_keep_open); diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -515,7 +515,7 @@ func Test_nl_pipe() call assert_equal("AND this", ch_readraw(handle)) call ch_sendraw(handle, "split this line\n") - call assert_equal("this linethis linethis line", ch_readraw(handle)) + call assert_equal("this linethis linethis line", ch_read(handle)) let reply = ch_evalraw(handle, "quit\n") call assert_equal("Goodbye!", reply) @@ -1266,6 +1266,31 @@ func Test_read_in_close_cb() endtry endfunc +" Use channel in NL mode but received text does not end in NL. +func Test_read_in_close_cb_incomplete() + if !has('job') + return + endif + call ch_log('Test_read_in_close_cb_incomplete()') + + let g:Ch_received = '' + func! CloseHandler(chan) + while ch_status(a:chan, {'part': 'out'}) == 'buffered' + let g:Ch_received .= ch_read(a:chan) + endwhile + endfunc + let job = job_start(s:python . " test_channel_pipe.py incomplete", + \ {'close_cb': 'CloseHandler'}) + call assert_equal("run", job_status(job)) + try + call WaitFor('g:Ch_received != ""') + call assert_equal('incomplete', g:Ch_received) + finally + call job_stop(job) + delfunc CloseHandler + endtry +endfunc + func Test_out_cb_lambda() if !has('job') return diff --git a/src/testdir/test_channel_pipe.py b/src/testdir/test_channel_pipe.py --- a/src/testdir/test_channel_pipe.py +++ b/src/testdir/test_channel_pipe.py @@ -14,6 +14,10 @@ if __name__ == "__main__": if sys.argv[1].startswith("err"): print(sys.argv[1], file=sys.stderr) sys.stderr.flush() + elif sys.argv[1].startswith("incomplete"): + print(sys.argv[1], end='') + sys.stdout.flush() + sys.exit(0) else: print(sys.argv[1]) sys.stdout.flush() diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -772,7 +772,9 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ - 1390, + 1381, +/**/ + 1380, /**/ 1379, /**/