Skip to content

Commit 9a6e33a

Browse files
committed
patch 7.4.1336
Problem: Channel NL mode is not supported yet. Solution: Add NL mode support to channels.
1 parent 5d54a04 commit 9a6e33a

9 files changed

Lines changed: 150 additions & 33 deletions

File tree

src/channel.c

Lines changed: 101 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -669,12 +669,12 @@ channel_set_job(channel_T *channel, job_T *job)
669669
}
670670

671671
/*
672-
* Set the json mode of channel "channel" to "ch_mode".
672+
* Set the mode of channel "channel" to "mode".
673673
*/
674674
void
675-
channel_set_json_mode(channel_T *channel, ch_mode_T ch_mode)
675+
channel_set_mode(channel_T *channel, ch_mode_T mode)
676676
{
677-
channel->ch_mode = ch_mode;
677+
channel->ch_mode = mode;
678678
}
679679

680680
/*
@@ -1057,7 +1057,8 @@ channel_exe_cmd(channel_T *channel, char_u *cmd, typval_T *arg2, typval_T *arg3)
10571057

10581058
/*
10591059
* Invoke a callback for channel "channel" if needed.
1060-
* Return OK when a message was handled, there might be another one.
1060+
* TODO: add "which" argument, read stderr.
1061+
* Return TRUE when a message was handled, there might be another one.
10611062
*/
10621063
static int
10631064
may_invoke_callback(channel_T *channel)
@@ -1074,7 +1075,7 @@ may_invoke_callback(channel_T *channel)
10741075
/* this channel is handled elsewhere (netbeans) */
10751076
return FALSE;
10761077

1077-
if (ch_mode != MODE_RAW)
1078+
if (ch_mode == MODE_JSON || ch_mode == MODE_JS)
10781079
{
10791080
/* Get any json message in the queue. */
10801081
if (channel_get_json(channel, -1, &listtv) == FAIL)
@@ -1113,18 +1114,51 @@ may_invoke_callback(channel_T *channel)
11131114
}
11141115
else if (channel_peek(channel) == NULL)
11151116
{
1116-
/* nothing to read on raw channel */
1117+
/* nothing to read on RAW or NL channel */
11171118
return FALSE;
11181119
}
11191120
else
11201121
{
1121-
/* If there is no callback, don't do anything. */
1122+
/* If there is no callback drop the message. */
11221123
if (channel->ch_callback == NULL)
1124+
{
1125+
while ((msg = channel_get(channel)) != NULL)
1126+
vim_free(msg);
11231127
return FALSE;
1128+
}
1129+
1130+
if (ch_mode == MODE_NL)
1131+
{
1132+
char_u *nl;
1133+
char_u *buf;
1134+
1135+
/* See if we have a message ending in NL in the first buffer. If
1136+
* not try to concatenate the first and the second buffer. */
1137+
while (TRUE)
1138+
{
1139+
buf = channel_peek(channel);
1140+
nl = vim_strchr(buf, NL);
1141+
if (nl != NULL)
1142+
break;
1143+
if (channel_collapse(channel) == FAIL)
1144+
return FALSE; /* incomplete message */
1145+
}
1146+
if (nl[1] == NUL)
1147+
/* get the whole buffer */
1148+
msg = channel_get(channel);
1149+
else
1150+
{
1151+
/* Copy the message into allocated memory and remove it from
1152+
* the buffer. */
1153+
msg = vim_strnsave(buf, (int)(nl - buf));
1154+
mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1);
1155+
}
1156+
}
1157+
else
1158+
/* For a raw channel we don't know where the message ends, just
1159+
* get everything we have. */
1160+
msg = channel_get_all(channel);
11241161

1125-
/* For a raw channel we don't know where the message ends, just get
1126-
* everything. */
1127-
msg = channel_get_all(channel);
11281162
argv[1].v_type = VAR_STRING;
11291163
argv[1].vval.v_string = msg;
11301164
}
@@ -1276,12 +1310,20 @@ channel_save(channel_T *channel, char_u *buf, int len)
12761310
return FAIL; /* out of memory */
12771311
}
12781312

1279-
/* TODO: don't strip CR when channel is in raw mode */
1280-
p = node->rq_buffer;
1281-
for (i = 0; i < len; ++i)
1282-
if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL)
1283-
*p++ = buf[i];
1284-
*p = NUL;
1313+
if (channel->ch_mode == MODE_NL)
1314+
{
1315+
/* Drop any CR before a NL. */
1316+
p = node->rq_buffer;
1317+
for (i = 0; i < len; ++i)
1318+
if (buf[i] != CAR || i + 1 >= len || buf[i + 1] != NL)
1319+
*p++ = buf[i];
1320+
*p = NUL;
1321+
}
1322+
else
1323+
{
1324+
mch_memmove(node->rq_buffer, buf, len);
1325+
node->rq_buffer[len] = NUL;
1326+
}
12851327

12861328
/* append node to the tail of the queue */
12871329
node->rq_next = NULL;
@@ -1570,31 +1612,64 @@ channel_read(channel_T *channel, int which, char *func)
15701612
}
15711613

15721614
/*
1573-
* Read from raw channel "channel". Blocks until there is something to read or
1574-
* the timeout expires.
1615+
* Read from RAW or NL channel "channel". Blocks until there is something to
1616+
* read or the timeout expires.
1617+
* TODO: add "which" argument and read from stderr.
15751618
* Returns what was read in allocated memory.
15761619
* Returns NULL in case of error or timeout.
15771620
*/
15781621
char_u *
15791622
channel_read_block(channel_T *channel)
15801623
{
1581-
ch_log(channel, "Reading raw\n");
1582-
if (channel_peek(channel) == NULL)
1624+
char_u *buf;
1625+
char_u *msg;
1626+
ch_mode_T mode = channel->ch_mode;
1627+
sock_T fd = get_read_fd(channel);
1628+
char_u *nl;
1629+
1630+
ch_logsn(channel, "Blocking %s read, timeout: %d msec\n",
1631+
mode == MODE_RAW ? "RAW" : "NL", channel->ch_timeout);
1632+
1633+
while (TRUE)
15831634
{
1584-
sock_T fd = get_read_fd(channel);
1635+
buf = channel_peek(channel);
1636+
if (buf != NULL && (mode == MODE_RAW
1637+
|| (mode == MODE_NL && vim_strchr(buf, NL) != NULL)))
1638+
break;
1639+
if (buf != NULL && channel_collapse(channel) == OK)
1640+
continue;
15851641

1586-
/* TODO: read both out and err if they are different */
1587-
ch_log(channel, "No readahead\n");
15881642
/* Wait for up to the channel timeout. */
15891643
if (fd == CHAN_FD_INVALID
15901644
|| channel_wait(channel, fd, channel->ch_timeout) == FAIL)
15911645
return NULL;
15921646
channel_read(channel, -1, "channel_read_block");
15931647
}
15941648

1595-
/* TODO: only get the first message */
1596-
ch_log(channel, "Returning readahead\n");
1597-
return channel_get_all(channel);
1649+
if (mode == MODE_RAW)
1650+
{
1651+
msg = channel_get_all(channel);
1652+
}
1653+
else
1654+
{
1655+
nl = vim_strchr(buf, NL);
1656+
if (nl[1] == NUL)
1657+
{
1658+
/* get the whole buffer */
1659+
msg = channel_get(channel);
1660+
*nl = NUL;
1661+
}
1662+
else
1663+
{
1664+
/* Copy the message into allocated memory and remove it from the
1665+
* buffer. */
1666+
msg = vim_strnsave(buf, (int)(nl - buf));
1667+
mch_memmove(buf, nl + 1, STRLEN(nl + 1) + 1);
1668+
}
1669+
}
1670+
if (log_fd != NULL)
1671+
ch_logn(channel, "Returning %d bytes\n", (int)STRLEN(msg));
1672+
return msg;
15981673
}
15991674

16001675
/*

src/os_win32.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5034,7 +5034,7 @@ mch_call_shell(
50345034

50355035
#if defined(FEAT_JOB) || defined(PROTO)
50365036
void
5037-
mch_start_job(char *cmd, job_T *job)
5037+
mch_start_job(char *cmd, job_T *job, jobopt_T *options)
50385038
{
50395039
STARTUPINFO si;
50405040
PROCESS_INFORMATION pi;
@@ -5121,6 +5121,7 @@ mch_start_job(char *cmd, job_T *job)
51215121
job->jv_channel = channel;
51225122
channel_set_pipes(channel, (sock_T)ifd[1], (sock_T)ofd[0], (sock_T)efd[0]);
51235123
channel_set_job(channel, job);
5124+
channel_set_mode(channel, options->jo_mode);
51245125

51255126
# ifdef FEAT_GUI
51265127
channel_gui_register(channel);

src/proto/channel.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ void channel_gui_register_all(void);
77
channel_T *channel_open(char *hostname, int port_in, int waittime, void (*close_cb)(void));
88
void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
99
void channel_set_job(channel_T *channel, job_T *job);
10-
void channel_set_json_mode(channel_T *channel, ch_mode_T ch_mode);
10+
void channel_set_mode(channel_T *channel, ch_mode_T ch_mode);
1111
void channel_set_timeout(channel_T *channel, int timeout);
1212
void channel_set_callback(channel_T *channel, char_u *callback);
1313
void channel_set_req_callback(channel_T *channel, char_u *callback, int id);

src/proto/os_unix.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void mch_set_shellsize(void);
5757
void mch_new_shellsize(void);
5858
int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
5959
int mch_call_shell(char_u *cmd, int options);
60-
void mch_start_job(char **argv, job_T *job);
60+
void mch_start_job(char **argv, job_T *job, jobopt_T *options);
6161
char *mch_job_status(job_T *job);
6262
int mch_stop_job(job_T *job, char_u *how);
6363
void mch_clear_job(job_T *job);

src/proto/os_win32.pro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ void mch_set_shellsize(void);
4040
void mch_new_shellsize(void);
4141
void mch_set_winsize_now(void);
4242
int mch_call_shell(char_u *cmd, int options);
43-
void mch_start_job(char *cmd, job_T *job);
43+
void mch_start_job(char *cmd, job_T *job, jobopt_T *options);
4444
char *mch_job_status(job_T *job);
4545
int mch_stop_job(job_T *job, char_u *how);
4646
void mch_clear_job(job_T *job);

src/structs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,14 @@ struct channel_S {
13721372
int ch_refcount; /* reference count */
13731373
};
13741374

1375+
/*
1376+
* Options for job commands.
1377+
*/
1378+
typedef struct
1379+
{
1380+
ch_mode_T jo_mode;
1381+
} jobopt_T;
1382+
13751383

13761384
/* structure used for explicit stack while garbage collecting hash tables */
13771385
typedef struct ht_stack_S

src/testdir/test_channel.vim

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,30 @@ func Test_connect_waittime()
284284
endif
285285
endfunc
286286

287-
func Test_pipe()
287+
func Test_raw_pipe()
288+
if !has('job')
289+
return
290+
endif
291+
let job = job_start(s:python . " test_channel_pipe.py", {'mode': 'raw'})
292+
call assert_equal("run", job_status(job))
293+
try
294+
let handle = job_getchannel(job)
295+
call ch_sendraw(handle, "echo something\n", 0)
296+
let msg = ch_readraw(handle)
297+
call assert_equal("something\n", substitute(msg, "\r", "", 'g'))
298+
299+
call ch_sendraw(handle, "double this\n", 0)
300+
let msg = ch_readraw(handle)
301+
call assert_equal("this\nAND this\n", substitute(msg, "\r", "", 'g'))
302+
303+
let reply = ch_sendraw(handle, "quit\n")
304+
call assert_equal("Goodbye!\n", substitute(reply, "\r", "", 'g'))
305+
finally
306+
call job_stop(job)
307+
endtry
308+
endfunc
309+
310+
func Test_nl_pipe()
288311
if !has('job')
289312
return
290313
endif
@@ -293,9 +316,14 @@ func Test_pipe()
293316
try
294317
let handle = job_getchannel(job)
295318
call ch_sendraw(handle, "echo something\n", 0)
296-
call assert_equal("something\n", ch_readraw(handle))
319+
call assert_equal("something", ch_readraw(handle))
320+
321+
call ch_sendraw(handle, "double this\n", 0)
322+
call assert_equal("this", ch_readraw(handle))
323+
call assert_equal("AND this", ch_readraw(handle))
324+
297325
let reply = ch_sendraw(handle, "quit\n")
298-
call assert_equal("Goodbye!\n", reply)
326+
call assert_equal("Goodbye!", reply)
299327
finally
300328
call job_stop(job)
301329
endtry

src/testdir/test_channel_pipe.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,7 @@
2121
if typed.startswith("echo"):
2222
print(typed[5:-1])
2323
sys.stdout.flush()
24+
if typed.startswith("double"):
25+
print(typed[7:-1] + "\nAND " + typed[7:-1])
26+
sys.stdout.flush()
2427

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,8 @@ static char *(features[]) =
747747

748748
static int included_patches[] =
749749
{ /* Add new patch number below this line */
750+
/**/
751+
1336,
750752
/**/
751753
1335,
752754
/**/

0 commit comments

Comments
 (0)