Mercurial > vim
comparison src/channel.c @ 8267:108d30ed34ba v7.4.1426
commit https://github.com/vim/vim/commit/187db50d0499aecf4cfd42fb4db0a1bebf61c8cd
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Feb 27 14:44:26 2016 +0100
patch 7.4.1426
Problem: The "out-io" option for jobs is not implemented yet.
Solution: Implement the "buffer" value: append job output to a buffer.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 27 Feb 2016 14:45:05 +0100 |
parents | a412b466bedc |
children | ac0c43e7af20 |
comparison
equal
deleted
inserted
replaced
8266:62545a8dec53 | 8267:108d30ed34ba |
---|---|
50 # define fd_read(fd, buf, len) read(fd, buf, len) | 50 # define fd_read(fd, buf, len) read(fd, buf, len) |
51 # define fd_write(sd, buf, len) write(sd, buf, len) | 51 # define fd_write(sd, buf, len) write(sd, buf, len) |
52 # define fd_close(sd) close(sd) | 52 # define fd_close(sd) close(sd) |
53 #endif | 53 #endif |
54 | 54 |
55 /* Whether a redraw is needed for appending a line to a buffer. */ | |
56 static int channel_need_redraw = FALSE; | |
57 | |
58 | |
55 #ifdef WIN32 | 59 #ifdef WIN32 |
56 static int | 60 static int |
57 fd_read(sock_T fd, char *buf, size_t len) | 61 fd_read(sock_T fd, char *buf, size_t len) |
58 { | 62 { |
59 HANDLE h = (HANDLE)fd; | 63 HANDLE h = (HANDLE)fd; |
340 */ | 344 */ |
341 void | 345 void |
342 channel_free(channel_T *channel) | 346 channel_free(channel_T *channel) |
343 { | 347 { |
344 channel_close(channel, TRUE); | 348 channel_close(channel, TRUE); |
349 channel_clear(channel); | |
345 if (channel->ch_next != NULL) | 350 if (channel->ch_next != NULL) |
346 channel->ch_next->ch_prev = channel->ch_prev; | 351 channel->ch_next->ch_prev = channel->ch_prev; |
347 if (channel->ch_prev == NULL) | 352 if (channel->ch_prev == NULL) |
348 first_channel = channel->ch_next; | 353 first_channel = channel->ch_next; |
349 else | 354 else |
775 { | 780 { |
776 channel->ch_job = job; | 781 channel->ch_job = job; |
777 } | 782 } |
778 | 783 |
779 /* | 784 /* |
785 * Find a buffer matching "name" or create a new one. | |
786 */ | |
787 static buf_T * | |
788 find_buffer(char_u *name) | |
789 { | |
790 buf_T *buf = buflist_findname(name); | |
791 buf_T *save_curbuf = curbuf; | |
792 | |
793 if (buf == NULL) | |
794 { | |
795 buf = buflist_new(name, NULL, (linenr_T)0, BLN_LISTED); | |
796 buf_copy_options(buf, BCO_ENTER); | |
797 #ifdef FEAT_QUICKFIX | |
798 clear_string_option(&buf->b_p_bt); | |
799 buf->b_p_bt = vim_strsave((char_u *)"nofile"); | |
800 clear_string_option(&buf->b_p_bh); | |
801 buf->b_p_bh = vim_strsave((char_u *)"hide"); | |
802 #endif | |
803 curbuf = buf; | |
804 ml_open(curbuf); | |
805 ml_replace(1, (char_u *)"Reading from channel output...", TRUE); | |
806 changed_bytes(1, 0); | |
807 curbuf = save_curbuf; | |
808 } | |
809 | |
810 return buf; | |
811 } | |
812 | |
813 /* | |
780 * Set various properties from an "opt" argument. | 814 * Set various properties from an "opt" argument. |
781 */ | 815 */ |
782 void | 816 void |
783 channel_set_options(channel_T *channel, jobopt_T *opt) | 817 channel_set_options(channel_T *channel, jobopt_T *opt) |
784 { | 818 { |
836 vim_free(*cbp); | 870 vim_free(*cbp); |
837 if (opt->jo_close_cb != NULL && *opt->jo_close_cb != NUL) | 871 if (opt->jo_close_cb != NULL && *opt->jo_close_cb != NUL) |
838 *cbp = vim_strsave(opt->jo_close_cb); | 872 *cbp = vim_strsave(opt->jo_close_cb); |
839 else | 873 else |
840 *cbp = NULL; | 874 *cbp = NULL; |
875 } | |
876 | |
877 if ((opt->jo_set & JO_OUT_IO) && opt->jo_io[PART_OUT] == JIO_BUFFER) | |
878 { | |
879 /* writing output to a buffer. Force mode to NL. */ | |
880 channel->ch_part[PART_OUT].ch_mode = MODE_NL; | |
881 channel->ch_part[PART_OUT].ch_buffer = | |
882 find_buffer(opt->jo_io_name[PART_OUT]); | |
883 ch_logs(channel, "writing to buffer %s", | |
884 (char *)channel->ch_part[PART_OUT].ch_buffer->b_ffname); | |
841 } | 885 } |
842 } | 886 } |
843 | 887 |
844 /* | 888 /* |
845 * Set the callback for "channel"/"part" for the response with "id". | 889 * Set the callback for "channel"/"part" for the response with "id". |
1301 typval_T *listtv = NULL; | 1345 typval_T *listtv = NULL; |
1302 typval_T argv[CH_JSON_MAX_ARGS]; | 1346 typval_T argv[CH_JSON_MAX_ARGS]; |
1303 int seq_nr = -1; | 1347 int seq_nr = -1; |
1304 ch_mode_T ch_mode = channel->ch_part[part].ch_mode; | 1348 ch_mode_T ch_mode = channel->ch_part[part].ch_mode; |
1305 char_u *callback = NULL; | 1349 char_u *callback = NULL; |
1350 buf_T *buffer = NULL; | |
1306 | 1351 |
1307 if (channel->ch_nb_close_cb != NULL) | 1352 if (channel->ch_nb_close_cb != NULL) |
1308 /* this channel is handled elsewhere (netbeans) */ | 1353 /* this channel is handled elsewhere (netbeans) */ |
1309 return FALSE; | 1354 return FALSE; |
1310 | 1355 |
1311 if (channel->ch_part[part].ch_callback != NULL) | 1356 if (channel->ch_part[part].ch_callback != NULL) |
1312 callback = channel->ch_part[part].ch_callback; | 1357 callback = channel->ch_part[part].ch_callback; |
1313 else | 1358 else |
1314 callback = channel->ch_callback; | 1359 callback = channel->ch_callback; |
1360 buffer = channel->ch_part[part].ch_buffer; | |
1315 | 1361 |
1316 if (ch_mode == MODE_JSON || ch_mode == MODE_JS) | 1362 if (ch_mode == MODE_JSON || ch_mode == MODE_JS) |
1317 { | 1363 { |
1318 listitem_T *item; | 1364 listitem_T *item; |
1319 int argc = 0; | 1365 int argc = 0; |
1359 /* nothing to read on RAW or NL channel */ | 1405 /* nothing to read on RAW or NL channel */ |
1360 return FALSE; | 1406 return FALSE; |
1361 } | 1407 } |
1362 else | 1408 else |
1363 { | 1409 { |
1364 /* If there is no callback drop the message. */ | 1410 /* If there is no callback or buffer drop the message. */ |
1365 if (callback == NULL) | 1411 if (callback == NULL && buffer == NULL) |
1366 { | 1412 { |
1367 while ((msg = channel_get(channel, part)) != NULL) | 1413 while ((msg = channel_get(channel, part)) != NULL) |
1368 vim_free(msg); | 1414 vim_free(msg); |
1369 return FALSE; | 1415 return FALSE; |
1370 } | 1416 } |
1384 break; | 1430 break; |
1385 if (channel_collapse(channel, part) == FAIL) | 1431 if (channel_collapse(channel, part) == FAIL) |
1386 return FALSE; /* incomplete message */ | 1432 return FALSE; /* incomplete message */ |
1387 } | 1433 } |
1388 if (nl[1] == NUL) | 1434 if (nl[1] == NUL) |
1389 /* get the whole buffer */ | 1435 { |
1436 /* get the whole buffer, drop the NL */ | |
1390 msg = channel_get(channel, part); | 1437 msg = channel_get(channel, part); |
1438 *nl = NUL; | |
1439 } | |
1391 else | 1440 else |
1392 { | 1441 { |
1393 /* Copy the message into allocated memory and remove it from | 1442 /* Copy the message into allocated memory and remove it from |
1394 * the buffer. */ | 1443 * the buffer. */ |
1395 msg = vim_strnsave(buf, (int)(nl - buf)); | 1444 msg = vim_strnsave(buf, (int)(nl - buf)); |
1429 item = item->cq_next; | 1478 item = item->cq_next; |
1430 } | 1479 } |
1431 if (!done) | 1480 if (!done) |
1432 ch_log(channel, "Dropping message without callback"); | 1481 ch_log(channel, "Dropping message without callback"); |
1433 } | 1482 } |
1434 else if (callback != NULL) | 1483 else if (callback != NULL || buffer != NULL) |
1435 { | 1484 { |
1436 /* invoke the channel callback */ | 1485 if (buffer != NULL) |
1437 ch_log(channel, "Invoking channel callback"); | 1486 { |
1438 invoke_callback(channel, callback, argv); | 1487 buf_T *save_curbuf = curbuf; |
1488 linenr_T lnum = buffer->b_ml.ml_line_count; | |
1489 | |
1490 /* Append to the buffer */ | |
1491 ch_logn(channel, "appending line %d to buffer", (int)lnum + 1); | |
1492 | |
1493 curbuf = buffer; | |
1494 u_sync(TRUE); | |
1495 u_save(lnum, lnum + 1); | |
1496 | |
1497 ml_append(lnum, msg, 0, FALSE); | |
1498 appended_lines_mark(lnum, 1L); | |
1499 curbuf = save_curbuf; | |
1500 | |
1501 if (buffer->b_nwindows > 0) | |
1502 { | |
1503 win_T *wp; | |
1504 win_T *save_curwin; | |
1505 | |
1506 FOR_ALL_WINDOWS(wp) | |
1507 { | |
1508 if (wp->w_buffer == buffer | |
1509 && wp->w_cursor.lnum == lnum | |
1510 && wp->w_cursor.col == 0) | |
1511 { | |
1512 ++wp->w_cursor.lnum; | |
1513 save_curwin = curwin; | |
1514 curwin = wp; | |
1515 curbuf = curwin->w_buffer; | |
1516 scroll_cursor_bot(0, FALSE); | |
1517 curwin = save_curwin; | |
1518 curbuf = curwin->w_buffer; | |
1519 } | |
1520 } | |
1521 redraw_buf_later(buffer, VALID); | |
1522 channel_need_redraw = TRUE; | |
1523 } | |
1524 } | |
1525 if (callback != NULL) | |
1526 { | |
1527 /* invoke the channel callback */ | |
1528 ch_log(channel, "Invoking channel callback"); | |
1529 invoke_callback(channel, callback, argv); | |
1530 } | |
1439 } | 1531 } |
1440 else | 1532 else |
1441 ch_log(channel, "Dropping message"); | 1533 ch_log(channel, "Dropping message"); |
1442 | 1534 |
1443 if (listtv != NULL) | 1535 if (listtv != NULL) |
1491 } | 1583 } |
1492 | 1584 |
1493 /* | 1585 /* |
1494 * Close channel "channel". | 1586 * Close channel "channel". |
1495 * Trigger the close callback if "invoke_close_cb" is TRUE. | 1587 * Trigger the close callback if "invoke_close_cb" is TRUE. |
1588 * Does not clear the buffers. | |
1496 */ | 1589 */ |
1497 void | 1590 void |
1498 channel_close(channel_T *channel, int invoke_close_cb) | 1591 channel_close(channel_T *channel, int invoke_close_cb) |
1499 { | 1592 { |
1500 ch_log(channel, "Closing channel"); | 1593 ch_log(channel, "Closing channel"); |
1546 vim_free(channel->ch_close_cb); | 1639 vim_free(channel->ch_close_cb); |
1547 channel->ch_close_cb = NULL; | 1640 channel->ch_close_cb = NULL; |
1548 } | 1641 } |
1549 | 1642 |
1550 channel->ch_nb_close_cb = NULL; | 1643 channel->ch_nb_close_cb = NULL; |
1551 channel_clear(channel); | |
1552 } | 1644 } |
1553 | 1645 |
1554 /* | 1646 /* |
1555 * Return the first buffer from "channel"/"part" without removing it. | 1647 * Return the first buffer from "channel"/"part" without removing it. |
1556 * Returns NULL if there is nothing. | 1648 * Returns NULL if there is nothing. |
2158 return ret; | 2250 return ret; |
2159 } | 2251 } |
2160 # endif /* !WIN32 && HAVE_SELECT */ | 2252 # endif /* !WIN32 && HAVE_SELECT */ |
2161 | 2253 |
2162 /* | 2254 /* |
2255 * Return TRUE if "channel" has JSON or other typeahead. | |
2256 */ | |
2257 static int | |
2258 channel_has_readahead(channel_T *channel, int part) | |
2259 { | |
2260 ch_mode_T ch_mode = channel->ch_part[part].ch_mode; | |
2261 | |
2262 if (ch_mode == MODE_JSON || ch_mode == MODE_JS) | |
2263 { | |
2264 jsonq_T *head = &channel->ch_part[part].ch_json_head; | |
2265 jsonq_T *item = head->jq_next; | |
2266 | |
2267 return item != NULL; | |
2268 } | |
2269 return channel_peek(channel, part) != NULL; | |
2270 } | |
2271 | |
2272 /* | |
2163 * Execute queued up commands. | 2273 * Execute queued up commands. |
2164 * Invoked from the main loop when it's safe to execute received commands. | 2274 * Invoked from the main loop when it's safe to execute received commands. |
2165 * Return TRUE when something was done. | 2275 * Return TRUE when something was done. |
2166 */ | 2276 */ |
2167 int | 2277 int |
2170 channel_T *channel = first_channel; | 2280 channel_T *channel = first_channel; |
2171 int ret = FALSE; | 2281 int ret = FALSE; |
2172 int r; | 2282 int r; |
2173 int part = PART_SOCK; | 2283 int part = PART_SOCK; |
2174 | 2284 |
2285 ch_log(NULL, "looking for messages on channels"); | |
2175 while (channel != NULL) | 2286 while (channel != NULL) |
2176 { | 2287 { |
2177 if (channel->ch_refcount == 0 && !channel_still_useful(channel)) | 2288 if (channel->ch_refcount == 0 && !channel_still_useful(channel)) |
2178 { | 2289 { |
2179 /* channel is no longer useful, free it */ | 2290 /* channel is no longer useful, free it */ |
2180 channel_free(channel); | 2291 channel_free(channel); |
2181 channel = first_channel; | 2292 channel = first_channel; |
2182 part = PART_SOCK; | 2293 part = PART_SOCK; |
2183 continue; | 2294 continue; |
2184 } | 2295 } |
2185 if (channel->ch_part[part].ch_fd != INVALID_FD) | 2296 if (channel->ch_part[part].ch_fd != INVALID_FD |
2297 || channel_has_readahead(channel, part)) | |
2186 { | 2298 { |
2187 /* Increase the refcount, in case the handler causes the channel | 2299 /* Increase the refcount, in case the handler causes the channel |
2188 * to be unreferenced or closed. */ | 2300 * to be unreferenced or closed. */ |
2189 ++channel->ch_refcount; | 2301 ++channel->ch_refcount; |
2190 r = may_invoke_callback(channel, part); | 2302 r = may_invoke_callback(channel, part); |
2206 { | 2318 { |
2207 channel = channel->ch_next; | 2319 channel = channel->ch_next; |
2208 part = PART_SOCK; | 2320 part = PART_SOCK; |
2209 } | 2321 } |
2210 } | 2322 } |
2323 | |
2324 if (channel_need_redraw && must_redraw) | |
2325 { | |
2326 channel_need_redraw = FALSE; | |
2327 update_screen(0); | |
2328 setcursor(); | |
2329 cursor_on(); | |
2330 out_flush(); | |
2331 } | |
2332 | |
2211 return ret; | 2333 return ret; |
2212 } | 2334 } |
2213 | 2335 |
2214 /* | 2336 /* |
2215 * Mark references to lists used in channels. | 2337 * Mark references to lists used in channels. |