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 */