comparison src/terminal.c @ 13860:7f892e37b017 v8.0.1801

patch 8.0.1801: MS-Windows: redirecting terminal output does not work commit https://github.com/vim/vim/commit/f25329cb94e481999e8b08d886cc0f0169e2020c Author: Bram Moolenaar <Bram@vim.org> Date: Sun May 6 21:49:32 2018 +0200 patch 8.0.1801: MS-Windows: redirecting terminal output does not work Problem: MS-Windows: redirecting terminal output does not work. Solution: Intercept the text written to the terminal and write it to the file.
author Christian Brabandt <cb@256bit.org>
date Sun, 06 May 2018 22:00:07 +0200
parents 3edac4cd1c0a
children b201372b91a4
comparison
equal deleted inserted replaced
13859:be340a68650d 13860:7f892e37b017
36 * that buffer, attributes come from the scrollback buffer tl_scrollback. 36 * that buffer, attributes come from the scrollback buffer tl_scrollback.
37 * When the buffer is changed it is turned into a normal buffer, the attributes 37 * When the buffer is changed it is turned into a normal buffer, the attributes
38 * in tl_scrollback are no longer used. 38 * in tl_scrollback are no longer used.
39 * 39 *
40 * TODO: 40 * TODO:
41 * - Win32: Redirecting input does not work, half of Test_terminal_redir_file()
42 * is disabled.
43 * - Win32: Redirecting output works but includes escape sequences.
41 * - Win32: Make terminal used for :!cmd in the GUI work better. Allow for 44 * - Win32: Make terminal used for :!cmd in the GUI work better. Allow for
42 * redirection. Probably in call to channel_set_pipes(). 45 * redirection.
43 * - Win32: Redirecting output does not work, Test_terminal_redir_file()
44 * is disabled.
45 * - Copy text in the vterm to the Vim buffer once in a while, so that 46 * - Copy text in the vterm to the Vim buffer once in a while, so that
46 * completion works. 47 * completion works.
47 * - When the job only outputs lines, we could handle resizing the terminal 48 * - When the job only outputs lines, we could handle resizing the terminal
48 * better: store lines separated by line breaks, instead of screen lines, 49 * better: store lines separated by line breaks, instead of screen lines,
49 * then when the window is resized redraw those lines. 50 * then when the window is resized redraw those lines.
50 * - Redrawing is slow with Athena and Motif. Also other GUI? (Ramel Eshed) 51 * - Redrawing is slow with Athena and Motif. (Ramel Eshed)
51 * - For the GUI fill termios with default values, perhaps like pangoterm: 52 * - For the GUI fill termios with default values, perhaps like pangoterm:
52 * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 53 * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134
53 * - When 'encoding' is not utf-8, or the job is using another encoding, setup 54 * - When 'encoding' is not utf-8, or the job is using another encoding, setup
54 * conversions. 55 * conversions.
55 * - Termdebug does not work when Vim build with mzscheme: gdb hangs just after 56 * - Termdebug does not work when Vim build with mzscheme: gdb hangs just after
96 int tl_toprow; /* row with first line of system terminal */ 97 int tl_toprow; /* row with first line of system terminal */
97 #endif 98 #endif
98 99
99 /* Set when setting the size of a vterm, reset after redrawing. */ 100 /* Set when setting the size of a vterm, reset after redrawing. */
100 int tl_vterm_size_changed; 101 int tl_vterm_size_changed;
101
102 /* used when tl_job is NULL and only a pty was created */
103 int tl_tty_fd;
104 char_u *tl_tty_in;
105 char_u *tl_tty_out;
106 102
107 int tl_normal_mode; /* TRUE: Terminal-Normal mode */ 103 int tl_normal_mode; /* TRUE: Terminal-Normal mode */
108 int tl_channel_closed; 104 int tl_channel_closed;
109 int tl_finish; 105 int tl_finish;
110 #define TL_FINISH_UNSET NUL 106 #define TL_FINISH_UNSET NUL
115 char_u *tl_eof_chars; 111 char_u *tl_eof_chars;
116 112
117 #ifdef WIN3264 113 #ifdef WIN3264
118 void *tl_winpty_config; 114 void *tl_winpty_config;
119 void *tl_winpty; 115 void *tl_winpty;
116
117 FILE *tl_out_fd;
120 #endif 118 #endif
121 #if defined(FEAT_SESSION) 119 #if defined(FEAT_SESSION)
122 char_u *tl_command; 120 char_u *tl_command;
123 #endif 121 #endif
124 char_u *tl_kill; 122 char_u *tl_kill;
167 #define KEY_BUF_LEN 200 165 #define KEY_BUF_LEN 200
168 166
169 /* 167 /*
170 * Functions with separate implementation for MS-Windows and Unix-like systems. 168 * Functions with separate implementation for MS-Windows and Unix-like systems.
171 */ 169 */
172 static int term_and_job_init(term_T *term, typval_T *argvar, char **argv, jobopt_T *opt); 170 static int term_and_job_init(term_T *term, typval_T *argvar, char **argv, jobopt_T *opt, jobopt_T *orig_opt);
173 static int create_pty_only(term_T *term, jobopt_T *opt); 171 static int create_pty_only(term_T *term, jobopt_T *opt);
174 static void term_report_winsize(term_T *term, int rows, int cols); 172 static void term_report_winsize(term_T *term, int rows, int cols);
175 static void term_free_vterm(term_T *term); 173 static void term_free_vterm(term_T *term);
176 #ifdef FEAT_GUI 174 #ifdef FEAT_GUI
177 static void update_system_term(term_T *term); 175 static void update_system_term(term_T *term);
281 * Set job options mandatory for a terminal job. 279 * Set job options mandatory for a terminal job.
282 */ 280 */
283 static void 281 static void
284 setup_job_options(jobopt_T *opt, int rows, int cols) 282 setup_job_options(jobopt_T *opt, int rows, int cols)
285 { 283 {
284 #ifndef WIN3264
285 /* Win32: Redirecting the job output won't work, thus always connect stdout
286 * here. */
286 if (!(opt->jo_set & JO_OUT_IO)) 287 if (!(opt->jo_set & JO_OUT_IO))
288 #endif
287 { 289 {
288 /* Connect stdout to the terminal. */ 290 /* Connect stdout to the terminal. */
289 opt->jo_io[PART_OUT] = JIO_BUFFER; 291 opt->jo_io[PART_OUT] = JIO_BUFFER;
290 opt->jo_io_buf[PART_OUT] = curbuf->b_fnum; 292 opt->jo_io_buf[PART_OUT] = curbuf->b_fnum;
291 opt->jo_modifiable[PART_OUT] = 0; 293 opt->jo_modifiable[PART_OUT] = 0;
292 opt->jo_set |= JO_OUT_IO + JO_OUT_BUF + JO_OUT_MODIFIABLE; 294 opt->jo_set |= JO_OUT_IO + JO_OUT_BUF + JO_OUT_MODIFIABLE;
293 } 295 }
294 296
297 #ifndef WIN3264
298 /* Win32: Redirecting the job output won't work, thus always connect stderr
299 * here. */
295 if (!(opt->jo_set & JO_ERR_IO)) 300 if (!(opt->jo_set & JO_ERR_IO))
301 #endif
296 { 302 {
297 /* Connect stderr to the terminal. */ 303 /* Connect stderr to the terminal. */
298 opt->jo_io[PART_ERR] = JIO_BUFFER; 304 opt->jo_io[PART_ERR] = JIO_BUFFER;
299 opt->jo_io_buf[PART_ERR] = curbuf->b_fnum; 305 opt->jo_io_buf[PART_ERR] = curbuf->b_fnum;
300 opt->jo_modifiable[PART_ERR] = 0; 306 opt->jo_modifiable[PART_ERR] = 0;
348 term_T *term; 354 term_T *term;
349 buf_T *old_curbuf = NULL; 355 buf_T *old_curbuf = NULL;
350 int res; 356 int res;
351 buf_T *newbuf; 357 buf_T *newbuf;
352 int vertical = opt->jo_vertical || (cmdmod.split & WSP_VERT); 358 int vertical = opt->jo_vertical || (cmdmod.split & WSP_VERT);
359 jobopt_T orig_opt; // only partly filled
353 360
354 if (check_restricted() || check_secure()) 361 if (check_restricted() || check_secure())
355 return NULL; 362 return NULL;
356 363
357 if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO)) 364 if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO))
515 /* Mark the buffer as not modifiable. It can only be made modifiable after 522 /* Mark the buffer as not modifiable. It can only be made modifiable after
516 * the job finished. */ 523 * the job finished. */
517 curbuf->b_p_ma = FALSE; 524 curbuf->b_p_ma = FALSE;
518 525
519 set_term_and_win_size(term); 526 set_term_and_win_size(term);
527 #ifdef WIN3264
528 mch_memmove(orig_opt.jo_io, opt->jo_io, sizeof(orig_opt.jo_io));
529 #endif
520 setup_job_options(opt, term->tl_rows, term->tl_cols); 530 setup_job_options(opt, term->tl_rows, term->tl_cols);
521 531
522 if (flags & TERM_START_NOJOB) 532 if (flags & TERM_START_NOJOB)
523 return curbuf; 533 return curbuf;
524 534
580 && argvar->v_type == VAR_STRING 590 && argvar->v_type == VAR_STRING
581 && argvar->vval.v_string != NULL 591 && argvar->vval.v_string != NULL
582 && STRCMP(argvar->vval.v_string, "NONE") == 0) 592 && STRCMP(argvar->vval.v_string, "NONE") == 0)
583 res = create_pty_only(term, opt); 593 res = create_pty_only(term, opt);
584 else 594 else
585 res = term_and_job_init(term, argvar, argv, opt); 595 res = term_and_job_init(term, argvar, argv, opt, &orig_opt);
586 596
587 newbuf = curbuf; 597 newbuf = curbuf;
588 if (res == OK) 598 if (res == OK)
589 { 599 {
590 /* Get and remember the size we ended up with. Update the pty. */ 600 /* Get and remember the size we ended up with. Update the pty. */
821 #endif 831 #endif
822 vim_free(term->tl_kill); 832 vim_free(term->tl_kill);
823 vim_free(term->tl_status_text); 833 vim_free(term->tl_status_text);
824 vim_free(term->tl_opencmd); 834 vim_free(term->tl_opencmd);
825 vim_free(term->tl_eof_chars); 835 vim_free(term->tl_eof_chars);
836 #ifdef WIN3264
837 if (term->tl_out_fd != NULL)
838 fclose(term->tl_out_fd);
839 #endif
826 if (desired_cursor_color == term->tl_cursor_color) 840 if (desired_cursor_color == term->tl_cursor_color)
827 desired_cursor_color = (char_u *)""; 841 desired_cursor_color = (char_u *)"";
828 vim_free(term->tl_cursor_color); 842 vim_free(term->tl_cursor_color);
829 vim_free(term); 843 vim_free(term);
830 buf->b_term = NULL; 844 buf->b_term = NULL;
915 void 929 void
916 write_to_term(buf_T *buffer, char_u *msg, channel_T *channel) 930 write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
917 { 931 {
918 size_t len = STRLEN(msg); 932 size_t len = STRLEN(msg);
919 term_T *term = buffer->b_term; 933 term_T *term = buffer->b_term;
934
935 #ifdef WIN3264
936 /* Win32: Cannot redirect output of the job, intercept it here and write to
937 * the file. */
938 if (term->tl_out_fd != NULL)
939 {
940 ch_log(channel, "Writing %d bytes to output file", (int)len);
941 fwrite(msg, len, 1, term->tl_out_fd);
942 return;
943 }
944 #endif
920 945
921 if (term->tl_vterm == NULL) 946 if (term->tl_vterm == NULL)
922 { 947 {
923 ch_log(channel, "NOT writing %d bytes to terminal", (int)len); 948 ch_log(channel, "NOT writing %d bytes to terminal", (int)len);
924 return; 949 return;
4738 switch (num) 4763 switch (num)
4739 { 4764 {
4740 case 0: 4765 case 0:
4741 if (buf->b_term->tl_job != NULL) 4766 if (buf->b_term->tl_job != NULL)
4742 p = buf->b_term->tl_job->jv_tty_out; 4767 p = buf->b_term->tl_job->jv_tty_out;
4743 else
4744 p = buf->b_term->tl_tty_out;
4745 break; 4768 break;
4746 case 1: 4769 case 1:
4747 if (buf->b_term->tl_job != NULL) 4770 if (buf->b_term->tl_job != NULL)
4748 p = buf->b_term->tl_job->jv_tty_in; 4771 p = buf->b_term->tl_job->jv_tty_in;
4749 else
4750 p = buf->b_term->tl_tty_in;
4751 break; 4772 break;
4752 default: 4773 default:
4753 EMSG2(_(e_invarg2), get_tv_string(&argvars[1])); 4774 EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
4754 return; 4775 return;
4755 } 4776 }
5237 static int 5258 static int
5238 term_and_job_init( 5259 term_and_job_init(
5239 term_T *term, 5260 term_T *term,
5240 typval_T *argvar, 5261 typval_T *argvar,
5241 char **argv UNUSED, 5262 char **argv UNUSED,
5242 jobopt_T *opt) 5263 jobopt_T *opt,
5264 jobopt_T *orig_opt)
5243 { 5265 {
5244 WCHAR *cmd_wchar = NULL; 5266 WCHAR *cmd_wchar = NULL;
5245 WCHAR *cwd_wchar = NULL; 5267 WCHAR *cwd_wchar = NULL;
5246 WCHAR *env_wchar = NULL; 5268 WCHAR *env_wchar = NULL;
5247 channel_T *channel = NULL; 5269 channel_T *channel = NULL;
5391 job->jv_tty_out = utf16_to_enc( 5413 job->jv_tty_out = utf16_to_enc(
5392 (short_u*)winpty_conout_name(term->tl_winpty), NULL); 5414 (short_u*)winpty_conout_name(term->tl_winpty), NULL);
5393 ++job->jv_refcount; 5415 ++job->jv_refcount;
5394 term->tl_job = job; 5416 term->tl_job = job;
5395 5417
5418 /* Redirecting stdout and stderr doesn't work at the job level. Instead
5419 * open the file here and handle it in. opt->jo_io was changed in
5420 * setup_job_options(), use the original flags here. */
5421 if (orig_opt->jo_io[PART_OUT] == JIO_FILE)
5422 {
5423 char_u *fname = opt->jo_io_name[PART_OUT];
5424
5425 ch_log(channel, "Opening output file %s", fname);
5426 term->tl_out_fd = mch_fopen((char *)fname, WRITEBIN);
5427 if (term->tl_out_fd == NULL)
5428 EMSG2(_(e_notopen), fname);
5429 }
5430
5396 return OK; 5431 return OK;
5397 5432
5398 failed: 5433 failed:
5399 ga_clear(&ga_cmd); 5434 ga_clear(&ga_cmd);
5400 ga_clear(&ga_env); 5435 ga_clear(&ga_env);
5544 static int 5579 static int
5545 term_and_job_init( 5580 term_and_job_init(
5546 term_T *term, 5581 term_T *term,
5547 typval_T *argvar, 5582 typval_T *argvar,
5548 char **argv, 5583 char **argv,
5549 jobopt_T *opt) 5584 jobopt_T *opt,
5585 jobopt_T *orig_opt UNUSED)
5550 { 5586 {
5551 create_vterm(term, term->tl_rows, term->tl_cols); 5587 create_vterm(term, term->tl_rows, term->tl_cols);
5552 5588
5553 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) 5589 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
5554 if (opt->jo_set2 & JO2_ANSI_COLORS) 5590 if (opt->jo_set2 & JO2_ANSI_COLORS)