Mercurial > vim
comparison src/terminal.c @ 12393:128cd982c7b8 v8.0.1076
patch 8.0.1076: term_start() does not take callbacks
commit https://github.com/vim/vim/commit/3c518400d1a51929572dd9fcf77dba94d78d7545
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Sep 8 20:47:00 2017 +0200
patch 8.0.1076: term_start() does not take callbacks
Problem: term_start() does not take callbacks. When using two terminals
without a job only one is read from. A terminal without a window
returns the wrong pty.
Solution: Support "callback", "out_cb" and "err_cb". Fix terminal without a
window. Fix reading from multiple channels.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 08 Sep 2017 21:00:04 +0200 |
parents | 438c64b76eef |
children | eb8d5c4936f1 |
comparison
equal
deleted
inserted
replaced
12392:e70744183d63 | 12393:128cd982c7b8 |
---|---|
243 opt->jo_term_rows = rows; | 243 opt->jo_term_rows = rows; |
244 if ((opt->jo_set2 & JO2_TERM_COLS) == 0) | 244 if ((opt->jo_set2 & JO2_TERM_COLS) == 0) |
245 opt->jo_term_cols = cols; | 245 opt->jo_term_cols = cols; |
246 } | 246 } |
247 | 247 |
248 static void | 248 /* |
249 * Start a terminal window and return its buffer. | |
250 * Returns NULL when failed. | |
251 */ | |
252 static buf_T * | |
249 term_start(typval_T *argvar, jobopt_T *opt, int forceit) | 253 term_start(typval_T *argvar, jobopt_T *opt, int forceit) |
250 { | 254 { |
251 exarg_T split_ea; | 255 exarg_T split_ea; |
252 win_T *old_curwin = curwin; | 256 win_T *old_curwin = curwin; |
253 term_T *term; | 257 term_T *term; |
254 buf_T *old_curbuf = NULL; | 258 buf_T *old_curbuf = NULL; |
255 int res; | 259 int res; |
260 buf_T *newbuf; | |
256 | 261 |
257 if (check_restricted() || check_secure()) | 262 if (check_restricted() || check_secure()) |
258 return; | 263 return NULL; |
259 | 264 |
260 if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO)) | 265 if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO)) |
261 == (JO_IN_IO + JO_OUT_IO + JO_ERR_IO) | 266 == (JO_IN_IO + JO_OUT_IO + JO_ERR_IO) |
262 || (!(opt->jo_set & JO_OUT_IO) && (opt->jo_set & JO_OUT_BUF)) | 267 || (!(opt->jo_set & JO_OUT_IO) && (opt->jo_set & JO_OUT_BUF)) |
263 || (!(opt->jo_set & JO_ERR_IO) && (opt->jo_set & JO_ERR_BUF))) | 268 || (!(opt->jo_set & JO_ERR_IO) && (opt->jo_set & JO_ERR_BUF))) |
264 { | 269 { |
265 EMSG(_(e_invarg)); | 270 EMSG(_(e_invarg)); |
266 return; | 271 return NULL; |
267 } | 272 } |
268 | 273 |
269 term = (term_T *)alloc_clear(sizeof(term_T)); | 274 term = (term_T *)alloc_clear(sizeof(term_T)); |
270 if (term == NULL) | 275 if (term == NULL) |
271 return; | 276 return NULL; |
272 term->tl_dirty_row_end = MAX_ROW; | 277 term->tl_dirty_row_end = MAX_ROW; |
273 term->tl_cursor_visible = TRUE; | 278 term->tl_cursor_visible = TRUE; |
274 term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK; | 279 term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK; |
275 term->tl_finish = opt->jo_term_finish; | 280 term->tl_finish = opt->jo_term_finish; |
276 ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300); | 281 ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300); |
281 /* Create a new buffer in the current window. */ | 286 /* Create a new buffer in the current window. */ |
282 if (!can_abandon(curbuf, forceit)) | 287 if (!can_abandon(curbuf, forceit)) |
283 { | 288 { |
284 no_write_message(); | 289 no_write_message(); |
285 vim_free(term); | 290 vim_free(term); |
286 return; | 291 return NULL; |
287 } | 292 } |
288 if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE, | 293 if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE, |
289 ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) | 294 ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL) |
290 { | 295 { |
291 vim_free(term); | 296 vim_free(term); |
292 return; | 297 return NULL; |
293 } | 298 } |
294 } | 299 } |
295 else if (opt->jo_hidden) | 300 else if (opt->jo_hidden) |
296 { | 301 { |
297 buf_T *buf; | 302 buf_T *buf; |
301 buf = buflist_new((char_u *)"", NULL, (linenr_T)0, | 306 buf = buflist_new((char_u *)"", NULL, (linenr_T)0, |
302 BLN_NEW | BLN_LISTED); | 307 BLN_NEW | BLN_LISTED); |
303 if (buf == NULL || ml_open(buf) == FAIL) | 308 if (buf == NULL || ml_open(buf) == FAIL) |
304 { | 309 { |
305 vim_free(term); | 310 vim_free(term); |
306 return; | 311 return NULL; |
307 } | 312 } |
308 old_curbuf = curbuf; | 313 old_curbuf = curbuf; |
309 --curbuf->b_nwindows; | 314 --curbuf->b_nwindows; |
310 curbuf = buf; | 315 curbuf = buf; |
311 curwin->w_buffer = buf; | 316 curwin->w_buffer = buf; |
331 ex_splitview(&split_ea); | 336 ex_splitview(&split_ea); |
332 if (curwin == old_curwin) | 337 if (curwin == old_curwin) |
333 { | 338 { |
334 /* split failed */ | 339 /* split failed */ |
335 vim_free(term); | 340 vim_free(term); |
336 return; | 341 return NULL; |
337 } | 342 } |
338 } | 343 } |
339 term->tl_buffer = curbuf; | 344 term->tl_buffer = curbuf; |
340 curbuf->b_term = term; | 345 curbuf->b_term = term; |
341 | 346 |
417 && STRCMP(argvar->vval.v_string, "NONE") == 0) | 422 && STRCMP(argvar->vval.v_string, "NONE") == 0) |
418 res = create_pty_only(term, opt); | 423 res = create_pty_only(term, opt); |
419 else | 424 else |
420 res = term_and_job_init(term, argvar, opt); | 425 res = term_and_job_init(term, argvar, opt); |
421 | 426 |
427 newbuf = curbuf; | |
422 if (res == OK) | 428 if (res == OK) |
423 { | 429 { |
424 /* Get and remember the size we ended up with. Update the pty. */ | 430 /* Get and remember the size we ended up with. Update the pty. */ |
425 vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols); | 431 vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols); |
426 term_report_winsize(term, term->tl_rows, term->tl_cols); | 432 term_report_winsize(term, term->tl_rows, term->tl_cols); |
451 } | 457 } |
452 | 458 |
453 /* Wiping out the buffer will also close the window and call | 459 /* Wiping out the buffer will also close the window and call |
454 * free_terminal(). */ | 460 * free_terminal(). */ |
455 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE); | 461 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE); |
456 } | 462 return NULL; |
463 } | |
464 return newbuf; | |
457 } | 465 } |
458 | 466 |
459 /* | 467 /* |
460 * ":terminal": open a terminal window and execute a job in it. | 468 * ":terminal": open a terminal window and execute a job in it. |
461 */ | 469 */ |
686 if (buffer == curbuf) | 694 if (buffer == curbuf) |
687 { | 695 { |
688 update_screen(0); | 696 update_screen(0); |
689 update_cursor(term, TRUE); | 697 update_cursor(term, TRUE); |
690 } | 698 } |
691 else | 699 else if (buffer->b_nwindows > 0) |
692 redraw_after_callback(TRUE); | 700 redraw_after_callback(TRUE); |
693 } | 701 } |
694 } | 702 } |
695 | 703 |
696 /* | 704 /* |
877 && (term->tl_job->jv_status == JOB_STARTED | 885 && (term->tl_job->jv_status == JOB_STARTED |
878 || term->tl_job->jv_channel->ch_keep_open); | 886 || term->tl_job->jv_channel->ch_keep_open); |
879 } | 887 } |
880 | 888 |
881 /* | 889 /* |
890 * Return TRUE if "term" has an active channel and used ":term NONE". | |
891 */ | |
892 int | |
893 term_none_open(term_T *term) | |
894 { | |
895 /* Also consider the job finished when the channel is closed, to avoid a | |
896 * race condition when updating the title. */ | |
897 return term != NULL | |
898 && term->tl_job != NULL | |
899 && channel_is_open(term->tl_job->jv_channel) | |
900 && term->tl_job->jv_channel->ch_keep_open; | |
901 } | |
902 | |
903 /* | |
882 * Add the last line of the scrollback buffer to the buffer in the window. | 904 * Add the last line of the scrollback buffer to the buffer in the window. |
883 */ | 905 */ |
884 static void | 906 static void |
885 add_scrollback_line_to_buffer(term_T *term, char_u *text, int len) | 907 add_scrollback_line_to_buffer(term_T *term, char_u *text, int len) |
886 { | 908 { |
2377 else | 2399 else |
2378 txt = (char_u *)_("Terminal-finished"); | 2400 txt = (char_u *)_("Terminal-finished"); |
2379 } | 2401 } |
2380 else if (term->tl_title != NULL) | 2402 else if (term->tl_title != NULL) |
2381 txt = term->tl_title; | 2403 txt = term->tl_title; |
2404 else if (term_none_open(term)) | |
2405 txt = (char_u *)_("active"); | |
2382 else if (term_job_running(term)) | 2406 else if (term_job_running(term)) |
2383 txt = (char_u *)_("running"); | 2407 txt = (char_u *)_("running"); |
2384 else | 2408 else |
2385 txt = (char_u *)_("finished"); | 2409 txt = (char_u *)_("finished"); |
2386 len = 9 + STRLEN(term->tl_buffer->b_fname) + STRLEN(txt); | 2410 len = 9 + STRLEN(term->tl_buffer->b_fname) + STRLEN(txt); |
2856 */ | 2880 */ |
2857 void | 2881 void |
2858 f_term_start(typval_T *argvars, typval_T *rettv) | 2882 f_term_start(typval_T *argvars, typval_T *rettv) |
2859 { | 2883 { |
2860 jobopt_T opt; | 2884 jobopt_T opt; |
2885 buf_T *buf; | |
2861 | 2886 |
2862 init_job_options(&opt); | 2887 init_job_options(&opt); |
2863 if (argvars[1].v_type != VAR_UNKNOWN | 2888 if (argvars[1].v_type != VAR_UNKNOWN |
2864 && get_job_options(&argvars[1], &opt, | 2889 && get_job_options(&argvars[1], &opt, |
2865 JO_TIMEOUT_ALL + JO_STOPONEXIT | 2890 JO_TIMEOUT_ALL + JO_STOPONEXIT |
2891 + JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK | |
2866 + JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO, | 2892 + JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO, |
2867 JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD | 2893 JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD |
2868 + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN | 2894 + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN |
2869 + JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL) | 2895 + JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL) |
2870 return; | 2896 return; |
2871 | 2897 |
2872 if (opt.jo_vertical) | 2898 if (opt.jo_vertical) |
2873 cmdmod.split = WSP_VERT; | 2899 cmdmod.split = WSP_VERT; |
2874 term_start(&argvars[0], &opt, FALSE); | 2900 buf = term_start(&argvars[0], &opt, FALSE); |
2875 | 2901 |
2876 if (curbuf->b_term != NULL) | 2902 if (buf != NULL && buf->b_term != NULL) |
2877 rettv->vval.v_number = curbuf->b_fnum; | 2903 rettv->vval.v_number = buf->b_fnum; |
2878 } | 2904 } |
2879 | 2905 |
2880 /* | 2906 /* |
2881 * "term_wait" function | 2907 * "term_wait" function |
2882 */ | 2908 */ |
3357 } | 3383 } |
3358 | 3384 |
3359 static int | 3385 static int |
3360 create_pty_only(term_T *term, jobopt_T *opt) | 3386 create_pty_only(term_T *term, jobopt_T *opt) |
3361 { | 3387 { |
3362 int ret; | |
3363 | |
3364 create_vterm(term, term->tl_rows, term->tl_cols); | 3388 create_vterm(term, term->tl_rows, term->tl_cols); |
3365 | 3389 |
3366 term->tl_job = job_alloc(); | 3390 term->tl_job = job_alloc(); |
3367 if (term->tl_job == NULL) | 3391 if (term->tl_job == NULL) |
3368 return FAIL; | 3392 return FAIL; |
3369 ++term->tl_job->jv_refcount; | 3393 ++term->tl_job->jv_refcount; |
3370 | 3394 |
3371 /* behave like the job is already finished */ | 3395 /* behave like the job is already finished */ |
3372 term->tl_job->jv_status = JOB_FINISHED; | 3396 term->tl_job->jv_status = JOB_FINISHED; |
3373 | 3397 |
3374 ret = mch_create_pty_channel(term->tl_job, opt); | 3398 return mch_create_pty_channel(term->tl_job, opt); |
3375 | |
3376 return ret; | |
3377 } | 3399 } |
3378 | 3400 |
3379 /* | 3401 /* |
3380 * Free the terminal emulator part of "term". | 3402 * Free the terminal emulator part of "term". |
3381 */ | 3403 */ |