To: vim_dev@googlegroups.com Subject: Patch 8.0.1801 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1801 Problem: MS-Windows: redirecting terminal output does not work. Solution: Intercept the text written to the terminal and write it to the file. Files: src/terminal.c, src/testdir/test_terminal.vim *** ../vim-8.0.1800/src/terminal.c 2018-05-06 16:40:12.239619606 +0200 --- src/terminal.c 2018-05-06 21:44:39.219762827 +0200 *************** *** 38,53 **** * in tl_scrollback are no longer used. * * TODO: ! * - Win32: Make terminal used for :!cmd in the GUI work better. Allow for ! * redirection. Probably in call to channel_set_pipes(). ! * - Win32: Redirecting output does not work, Test_terminal_redir_file() * is disabled. * - Copy text in the vterm to the Vim buffer once in a while, so that * completion works. * - When the job only outputs lines, we could handle resizing the terminal * better: store lines separated by line breaks, instead of screen lines, * then when the window is resized redraw those lines. ! * - Redrawing is slow with Athena and Motif. Also other GUI? (Ramel Eshed) * - For the GUI fill termios with default values, perhaps like pangoterm: * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 * - When 'encoding' is not utf-8, or the job is using another encoding, setup --- 38,54 ---- * in tl_scrollback are no longer used. * * TODO: ! * - Win32: Redirecting input does not work, half of Test_terminal_redir_file() * is disabled. + * - Win32: Redirecting output works but includes escape sequences. + * - Win32: Make terminal used for :!cmd in the GUI work better. Allow for + * redirection. * - Copy text in the vterm to the Vim buffer once in a while, so that * completion works. * - When the job only outputs lines, we could handle resizing the terminal * better: store lines separated by line breaks, instead of screen lines, * then when the window is resized redraw those lines. ! * - Redrawing is slow with Athena and Motif. (Ramel Eshed) * - For the GUI fill termios with default values, perhaps like pangoterm: * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 * - When 'encoding' is not utf-8, or the job is using another encoding, setup *************** *** 99,109 **** /* Set when setting the size of a vterm, reset after redrawing. */ int tl_vterm_size_changed; - /* used when tl_job is NULL and only a pty was created */ - int tl_tty_fd; - char_u *tl_tty_in; - char_u *tl_tty_out; - int tl_normal_mode; /* TRUE: Terminal-Normal mode */ int tl_channel_closed; int tl_finish; --- 100,105 ---- *************** *** 117,122 **** --- 113,120 ---- #ifdef WIN3264 void *tl_winpty_config; void *tl_winpty; + + FILE *tl_out_fd; #endif #if defined(FEAT_SESSION) char_u *tl_command; *************** *** 169,175 **** /* * Functions with separate implementation for MS-Windows and Unix-like systems. */ ! static int term_and_job_init(term_T *term, typval_T *argvar, char **argv, jobopt_T *opt); static int create_pty_only(term_T *term, jobopt_T *opt); static void term_report_winsize(term_T *term, int rows, int cols); static void term_free_vterm(term_T *term); --- 167,173 ---- /* * Functions with separate implementation for MS-Windows and Unix-like systems. */ ! static int term_and_job_init(term_T *term, typval_T *argvar, char **argv, jobopt_T *opt, jobopt_T *orig_opt); static int create_pty_only(term_T *term, jobopt_T *opt); static void term_report_winsize(term_T *term, int rows, int cols); static void term_free_vterm(term_T *term); *************** *** 283,289 **** --- 281,291 ---- static void setup_job_options(jobopt_T *opt, int rows, int cols) { + #ifndef WIN3264 + /* Win32: Redirecting the job output won't work, thus always connect stdout + * here. */ if (!(opt->jo_set & JO_OUT_IO)) + #endif { /* Connect stdout to the terminal. */ opt->jo_io[PART_OUT] = JIO_BUFFER; *************** *** 292,298 **** --- 294,304 ---- opt->jo_set |= JO_OUT_IO + JO_OUT_BUF + JO_OUT_MODIFIABLE; } + #ifndef WIN3264 + /* Win32: Redirecting the job output won't work, thus always connect stderr + * here. */ if (!(opt->jo_set & JO_ERR_IO)) + #endif { /* Connect stderr to the terminal. */ opt->jo_io[PART_ERR] = JIO_BUFFER; *************** *** 350,355 **** --- 356,362 ---- int res; buf_T *newbuf; int vertical = opt->jo_vertical || (cmdmod.split & WSP_VERT); + jobopt_T orig_opt; // only partly filled if (check_restricted() || check_secure()) return NULL; *************** *** 517,522 **** --- 524,532 ---- curbuf->b_p_ma = FALSE; set_term_and_win_size(term); + #ifdef WIN3264 + mch_memmove(orig_opt.jo_io, opt->jo_io, sizeof(orig_opt.jo_io)); + #endif setup_job_options(opt, term->tl_rows, term->tl_cols); if (flags & TERM_START_NOJOB) *************** *** 582,588 **** && STRCMP(argvar->vval.v_string, "NONE") == 0) res = create_pty_only(term, opt); else ! res = term_and_job_init(term, argvar, argv, opt); newbuf = curbuf; if (res == OK) --- 592,598 ---- && STRCMP(argvar->vval.v_string, "NONE") == 0) res = create_pty_only(term, opt); else ! res = term_and_job_init(term, argvar, argv, opt, &orig_opt); newbuf = curbuf; if (res == OK) *************** *** 823,828 **** --- 833,842 ---- vim_free(term->tl_status_text); vim_free(term->tl_opencmd); vim_free(term->tl_eof_chars); + #ifdef WIN3264 + if (term->tl_out_fd != NULL) + fclose(term->tl_out_fd); + #endif if (desired_cursor_color == term->tl_cursor_color) desired_cursor_color = (char_u *)""; vim_free(term->tl_cursor_color); *************** *** 918,923 **** --- 932,948 ---- size_t len = STRLEN(msg); term_T *term = buffer->b_term; + #ifdef WIN3264 + /* Win32: Cannot redirect output of the job, intercept it here and write to + * the file. */ + if (term->tl_out_fd != NULL) + { + ch_log(channel, "Writing %d bytes to output file", (int)len); + fwrite(msg, len, 1, term->tl_out_fd); + return; + } + #endif + if (term->tl_vterm == NULL) { ch_log(channel, "NOT writing %d bytes to terminal", (int)len); *************** *** 4740,4753 **** case 0: if (buf->b_term->tl_job != NULL) p = buf->b_term->tl_job->jv_tty_out; - else - p = buf->b_term->tl_tty_out; break; case 1: if (buf->b_term->tl_job != NULL) p = buf->b_term->tl_job->jv_tty_in; - else - p = buf->b_term->tl_tty_in; break; default: EMSG2(_(e_invarg2), get_tv_string(&argvars[1])); --- 4765,4774 ---- *************** *** 5239,5245 **** term_T *term, typval_T *argvar, char **argv UNUSED, ! jobopt_T *opt) { WCHAR *cmd_wchar = NULL; WCHAR *cwd_wchar = NULL; --- 5260,5267 ---- term_T *term, typval_T *argvar, char **argv UNUSED, ! jobopt_T *opt, ! jobopt_T *orig_opt) { WCHAR *cmd_wchar = NULL; WCHAR *cwd_wchar = NULL; *************** *** 5393,5398 **** --- 5415,5433 ---- ++job->jv_refcount; term->tl_job = job; + /* Redirecting stdout and stderr doesn't work at the job level. Instead + * open the file here and handle it in. opt->jo_io was changed in + * setup_job_options(), use the original flags here. */ + if (orig_opt->jo_io[PART_OUT] == JIO_FILE) + { + char_u *fname = opt->jo_io_name[PART_OUT]; + + ch_log(channel, "Opening output file %s", fname); + term->tl_out_fd = mch_fopen((char *)fname, WRITEBIN); + if (term->tl_out_fd == NULL) + EMSG2(_(e_notopen), fname); + } + return OK; failed: *************** *** 5546,5552 **** term_T *term, typval_T *argvar, char **argv, ! jobopt_T *opt) { create_vterm(term, term->tl_rows, term->tl_cols); --- 5581,5588 ---- term_T *term, typval_T *argvar, char **argv, ! jobopt_T *opt, ! jobopt_T *orig_opt UNUSED) { create_vterm(term, term->tl_rows, term->tl_cols); *** ../vim-8.0.1800/src/testdir/test_terminal.vim 2018-05-03 20:40:15.714154543 +0200 --- src/testdir/test_terminal.vim 2018-05-06 21:12:06.003573297 +0200 *************** *** 675,692 **** endfunc func Test_terminal_redir_file() ! " TODO: this should work on MS-Window ! if has('unix') ! let cmd = Get_cat_123_cmd() ! let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'}) ! call term_wait(buf) ! call WaitForAssert({-> assert_notequal(0, len(readfile("Xfile")))}) ! call assert_match('123', readfile('Xfile')[0]) ! let g:job = term_getjob(buf) ! call WaitForAssert({-> assert_equal("dead", job_status(g:job))}) ! call delete('Xfile') ! bwipe ! endif if has('unix') call writefile(['one line'], 'Xfile') --- 675,689 ---- endfunc func Test_terminal_redir_file() ! let cmd = Get_cat_123_cmd() ! let buf = term_start(cmd, {'out_io': 'file', 'out_name': 'Xfile'}) ! call term_wait(buf) ! call WaitForAssert({-> assert_notequal(0, len(readfile("Xfile")))}) ! call assert_match('123', readfile('Xfile')[0]) ! let g:job = term_getjob(buf) ! call WaitForAssert({-> assert_equal("dead", job_status(g:job))}) ! call delete('Xfile') ! bwipe if has('unix') call writefile(['one line'], 'Xfile') *** ../vim-8.0.1800/src/version.c 2018-05-06 19:19:32.382254324 +0200 --- src/version.c 2018-05-06 21:11:40.931724251 +0200 *************** *** 763,764 **** --- 763,766 ---- { /* Add new patch number below this line */ + /**/ + 1801, /**/ -- ARTHUR: Shut up! Will you shut up! DENNIS: Ah, now we see the violence inherent in the system. ARTHUR: Shut up! DENNIS: Oh! Come and see the violence inherent in the system! HELP! HELP! I'm being repressed! The Quest for the Holy Grail (Monty Python) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///