Mercurial > vim
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) |