To: vim_dev@googlegroups.com Subject: Patch 8.0.0718 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.0718 Problem: Output of job in terminal is not displayed. Solution: Connect the job output to the terminal. Files: src/channel.c, src/proto/channel.pro, src/terminal.c, src/proto/terminal.pro, src/channel.c, src/proto/channel.pro, src/evalfunc.c, src/screen.c, src/proto/screen.pro *** ../vim-8.0.0717/src/channel.c 2017-07-15 17:01:50.350726204 +0200 --- src/channel.c 2017-07-15 22:18:35.029671290 +0200 *************** *** 171,177 **** } } ! static void ch_logn(channel_T *ch, char *msg, int nr) { if (log_fd != NULL) --- 171,177 ---- } } ! void ch_logn(channel_T *ch, char *msg, int nr) { if (log_fd != NULL) *************** *** 2656,2662 **** /* JSON or JS mode: re-encode the message. */ msg = json_encode(listtv, ch_mode); if (msg != NULL) ! append_to_buffer(buffer, msg, channel, part); } if (callback != NULL) --- 2656,2667 ---- /* JSON or JS mode: re-encode the message. */ msg = json_encode(listtv, ch_mode); if (msg != NULL) ! { ! if (buffer->b_term != NULL) ! write_to_term(buffer, msg, channel); ! else ! append_to_buffer(buffer, msg, channel, part); ! } } if (callback != NULL) *************** *** 4889,4895 **** * "job_start()" function */ job_T * ! job_start(typval_T *argvars) { job_T *job; char_u *cmd = NULL; --- 4894,4900 ---- * "job_start()" function */ job_T * ! job_start(typval_T *argvars, jobopt_T *opt_arg) { job_T *job; char_u *cmd = NULL; *************** *** 4912,4924 **** ga_init2(&ga, (int)sizeof(char*), 20); #endif ! /* Default mode is NL. */ ! clear_job_options(&opt); ! opt.jo_mode = MODE_NL; ! if (get_job_options(&argvars[1], &opt, JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL) goto theend; /* Check that when io is "file" that there is a file name. */ for (part = PART_OUT; part < PART_COUNT; ++part) --- 4917,4934 ---- ga_init2(&ga, (int)sizeof(char*), 20); #endif ! if (opt_arg != NULL) ! opt = *opt_arg; ! else ! { ! /* Default mode is NL. */ ! clear_job_options(&opt); ! opt.jo_mode = MODE_NL; ! if (get_job_options(&argvars[1], &opt, JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL) goto theend; + } /* Check that when io is "file" that there is a file name. */ for (part = PART_OUT; part < PART_COUNT; ++part) *** ../vim-8.0.0717/src/proto/channel.pro 2016-12-01 15:34:04.087413921 +0100 --- src/proto/channel.pro 2017-07-15 20:41:05.457918326 +0200 *************** *** 2,7 **** --- 2,8 ---- void ch_logfile(char_u *fname, char_u *opt); int ch_log_active(void); void ch_log(channel_T *ch, char *msg); + void ch_logn(channel_T *ch, char *msg, int nr); void ch_logs(channel_T *ch, char *msg, char *name); channel_T *add_channel(void); int has_any_channel(void); *************** *** 63,69 **** void job_stop_on_exit(void); int has_pending_job(void); void job_check_ended(void); ! job_T *job_start(typval_T *argvars); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); int job_stop(job_T *job, typval_T *argvars); --- 64,70 ---- void job_stop_on_exit(void); int has_pending_job(void); void job_check_ended(void); ! job_T *job_start(typval_T *argvars, jobopt_T *opt_arg); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); int job_stop(job_T *job, typval_T *argvars); *** ../vim-8.0.0717/src/terminal.c 2017-07-15 20:05:50.802053721 +0200 --- src/terminal.c 2017-07-15 22:53:26.785858885 +0200 *************** *** 28,33 **** --- 28,35 ---- * - remove term from first_term list when closing terminal. * - set buffer options to be scratch, hidden, nomodifiable, etc. * - set buffer name to command, add (1) to avoid duplicates. + * - if buffer is wiped, cleanup terminal, may stop job. + * - if the job ends, write "-- JOB ENDED --" in the terminal * - command line completion (command name) * - support fixed size when 'termsize' is "rowsXcols". * - support minimal size when 'termsize' is "rows*cols". *************** *** 40,45 **** --- 42,48 ---- * - implement term_scrape() inspect terminal screen * - implement term_open() open terminal window * - implement term_getjob() + * - implement 'termkey' */ #include "vim.h" *************** *** 54,59 **** --- 57,63 ---- VTerm *tl_vterm; job_T *tl_job; + buf_T *tl_buffer; /* Range of screen rows to update. Zero based. */ int tl_dirty_row_start; /* -1 if nothing dirty */ *************** *** 99,104 **** --- 103,109 ---- term_T *term; VTerm *vterm; VTermScreen *screen; + jobopt_T opt; if (check_restricted() || check_secure()) return; *************** *** 120,125 **** --- 125,131 ---- vim_free(term); return; } + term->tl_buffer = curbuf; curbuf->b_term = term; term->tl_next = first_term; *************** *** 145,160 **** term->tl_vterm = vterm; screen = vterm_obtain_screen(vterm); vterm_screen_set_callbacks(screen, &screen_callbacks, term); argvars[0].v_type = VAR_STRING; argvars[0].vval.v_string = eap->arg; - argvars[1].v_type = VAR_UNKNOWN; - term->tl_job = job_start(argvars); ! /* TODO: setup channels to/from job */ /* Setup pty, see mch_call_shell(). */ } static int handle_damage(VTermRect rect, void *user) { --- 151,246 ---- term->tl_vterm = vterm; screen = vterm_obtain_screen(vterm); vterm_screen_set_callbacks(screen, &screen_callbacks, term); + /* TODO: depends on 'encoding'. */ + vterm_set_utf8(vterm, 1); + /* Required to initialize most things. */ + vterm_screen_reset(screen, 1 /* hard */); + + /* By default NL means CR-NL. */ + vterm_input_write(vterm, "\x1b[20h", 5); argvars[0].v_type = VAR_STRING; argvars[0].vval.v_string = eap->arg; ! clear_job_options(&opt); ! opt.jo_mode = MODE_RAW; ! opt.jo_out_mode = MODE_RAW; ! opt.jo_err_mode = MODE_RAW; ! opt.jo_set = JO_MODE | JO_OUT_MODE | JO_ERR_MODE; ! opt.jo_io[PART_OUT] = JIO_BUFFER; ! opt.jo_io[PART_ERR] = JIO_BUFFER; ! opt.jo_set |= JO_OUT_IO + (JO_OUT_IO << (PART_ERR - PART_OUT)); ! opt.jo_io_buf[PART_OUT] = curbuf->b_fnum; ! opt.jo_io_buf[PART_ERR] = curbuf->b_fnum; ! opt.jo_set |= JO_OUT_BUF + (JO_OUT_BUF << (PART_ERR - PART_OUT)); ! ! term->tl_job = job_start(argvars, &opt); ! ! /* TODO: setup channel to job */ /* Setup pty, see mch_call_shell(). */ } + /* + * Invoked when "msg" output from a job was received. Write it to the terminal + * of "buffer". + */ + void + write_to_term(buf_T *buffer, char_u *msg, channel_T *channel) + { + size_t len = STRLEN(msg); + VTerm *vterm = buffer->b_term->tl_vterm; + + ch_logn(channel, "writing %d bytes to terminal", (int)len); + vterm_input_write(vterm, (char *)msg, len); + vterm_screen_flush_damage(vterm_obtain_screen(vterm)); + + /* TODO: only update once in a while. */ + update_screen(0); + setcursor(); + out_flush(); + } + + /* + * Called to update the window that contains the terminal. + */ + void + term_update_window(win_T *wp) + { + int vterm_rows; + int vterm_cols; + VTerm *vterm = wp->w_buffer->b_term->tl_vterm; + VTermScreen *screen = vterm_obtain_screen(vterm); + VTermPos pos; + + vterm_get_size(vterm, &vterm_rows, &vterm_cols); + + /* TODO: Only redraw what changed. */ + for (pos.row = 0; pos.row < wp->w_height; ++pos.row) + { + int off = screen_get_current_line_off(); + + if (pos.row < vterm_rows) + for (pos.col = 0; pos.col < wp->w_width && pos.col < vterm_cols; + ++pos.col) + { + VTermScreenCell cell; + int c; + + vterm_screen_get_cell(screen, pos, &cell); + /* TODO: use cell.attrs and colors */ + /* TODO: use cell.width */ + /* TODO: multi-byte chars */ + c = cell.chars[0]; + ScreenLines[off] = c == NUL ? ' ' : c; + ScreenAttrs[off] = 0; + ++off; + } + + screen_line(wp->w_winrow + pos.row, wp->w_wincol, pos.col, wp->w_width, + FALSE); + } + } + static int handle_damage(VTermRect rect, void *user) { *************** *** 162,188 **** term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row); term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row); return 1; } static int handle_moverect(VTermRect dest, VTermRect src, void *user) { /* TODO */ return 1; } static int handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) { ! /* TODO: handle moving the cursor. */ return 1; } static int handle_resize(int rows, int cols, void *user) { /* TODO: handle terminal resize. */ return 1; } --- 248,302 ---- term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row); term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row); + redraw_buf_later(term->tl_buffer, NOT_VALID); return 1; } static int handle_moverect(VTermRect dest, VTermRect src, void *user) { + term_T *term = (term_T *)user; + /* TODO */ + redraw_buf_later(term->tl_buffer, NOT_VALID); return 1; } static int handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user) { ! term_T *term = (term_T *)user; ! win_T *wp; ! int is_current = FALSE; ! ! FOR_ALL_WINDOWS(wp) ! { ! if (wp->w_buffer == term->tl_buffer) ! { ! /* TODO: limit to window size? */ ! wp->w_wrow = pos.row; ! wp->w_wcol = pos.col; ! if (wp == curwin) ! is_current = TRUE; ! } ! } ! ! if (is_current) ! { ! setcursor(); ! out_flush(); ! } ! return 1; } static int handle_resize(int rows, int cols, void *user) { + term_T *term = (term_T *)user; + /* TODO: handle terminal resize. */ + redraw_buf_later(term->tl_buffer, NOT_VALID); return 1; } *************** *** 201,210 **** * - Write output to channel. */ - /* TODO: function to read job output from the channel. - * write to vterm: vterm_input_write() - * This will invoke screen callbacks. - * call vterm_screen_flush_damage() - */ - #endif /* FEAT_TERMINAL */ --- 315,318 ---- *** ../vim-8.0.0717/src/proto/terminal.pro 2017-07-07 11:53:29.515876528 +0200 --- src/proto/terminal.pro 2017-07-15 21:37:51.732076242 +0200 *************** *** 1,3 **** --- 1,5 ---- /* terminal.c */ void ex_terminal(exarg_T *eap); + void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel); + void term_update_window(win_T *wp); /* vim: set ft=c : */ *** ../vim-8.0.0717/src/channel.c 2017-07-15 17:01:50.350726204 +0200 --- src/channel.c 2017-07-15 22:18:35.029671290 +0200 *************** *** 171,177 **** } } ! static void ch_logn(channel_T *ch, char *msg, int nr) { if (log_fd != NULL) --- 171,177 ---- } } ! void ch_logn(channel_T *ch, char *msg, int nr) { if (log_fd != NULL) *************** *** 2656,2662 **** /* JSON or JS mode: re-encode the message. */ msg = json_encode(listtv, ch_mode); if (msg != NULL) ! append_to_buffer(buffer, msg, channel, part); } if (callback != NULL) --- 2656,2667 ---- /* JSON or JS mode: re-encode the message. */ msg = json_encode(listtv, ch_mode); if (msg != NULL) ! { ! if (buffer->b_term != NULL) ! write_to_term(buffer, msg, channel); ! else ! append_to_buffer(buffer, msg, channel, part); ! } } if (callback != NULL) *************** *** 4889,4895 **** * "job_start()" function */ job_T * ! job_start(typval_T *argvars) { job_T *job; char_u *cmd = NULL; --- 4894,4900 ---- * "job_start()" function */ job_T * ! job_start(typval_T *argvars, jobopt_T *opt_arg) { job_T *job; char_u *cmd = NULL; *************** *** 4912,4924 **** ga_init2(&ga, (int)sizeof(char*), 20); #endif ! /* Default mode is NL. */ ! clear_job_options(&opt); ! opt.jo_mode = MODE_NL; ! if (get_job_options(&argvars[1], &opt, JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL) goto theend; /* Check that when io is "file" that there is a file name. */ for (part = PART_OUT; part < PART_COUNT; ++part) --- 4917,4934 ---- ga_init2(&ga, (int)sizeof(char*), 20); #endif ! if (opt_arg != NULL) ! opt = *opt_arg; ! else ! { ! /* Default mode is NL. */ ! clear_job_options(&opt); ! opt.jo_mode = MODE_NL; ! if (get_job_options(&argvars[1], &opt, JO_MODE_ALL + JO_CB_ALL + JO_TIMEOUT_ALL + JO_STOPONEXIT + JO_EXIT_CB + JO_OUT_IO + JO_BLOCK_WRITE) == FAIL) goto theend; + } /* Check that when io is "file" that there is a file name. */ for (part = PART_OUT; part < PART_COUNT; ++part) *** ../vim-8.0.0717/src/proto/channel.pro 2016-12-01 15:34:04.087413921 +0100 --- src/proto/channel.pro 2017-07-15 20:41:05.457918326 +0200 *************** *** 2,7 **** --- 2,8 ---- void ch_logfile(char_u *fname, char_u *opt); int ch_log_active(void); void ch_log(channel_T *ch, char *msg); + void ch_logn(channel_T *ch, char *msg, int nr); void ch_logs(channel_T *ch, char *msg, char *name); channel_T *add_channel(void); int has_any_channel(void); *************** *** 63,69 **** void job_stop_on_exit(void); int has_pending_job(void); void job_check_ended(void); ! job_T *job_start(typval_T *argvars); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); int job_stop(job_T *job, typval_T *argvars); --- 64,70 ---- void job_stop_on_exit(void); int has_pending_job(void); void job_check_ended(void); ! job_T *job_start(typval_T *argvars, jobopt_T *opt_arg); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); int job_stop(job_T *job, typval_T *argvars); *** ../vim-8.0.0717/src/evalfunc.c 2017-07-11 22:34:47.523932120 +0200 --- src/evalfunc.c 2017-07-15 20:46:46.739331963 +0200 *************** *** 6745,6751 **** rettv->v_type = VAR_JOB; if (check_restricted() || check_secure()) return; ! rettv->vval.v_job = job_start(argvars); } /* --- 6745,6751 ---- rettv->v_type = VAR_JOB; if (check_restricted() || check_secure()) return; ! rettv->vval.v_job = job_start(argvars, NULL); } /* *** ../vim-8.0.0717/src/screen.c 2017-07-12 21:12:38.336024915 +0200 --- src/screen.c 2017-07-15 22:40:33.279714955 +0200 *************** *** 126,138 **** #endif static int win_line(win_T *, linenr_T, int, int, int nochange, proftime_T *syntax_tm); static int char_needs_redraw(int off_from, int off_to, int cols); - #ifdef FEAT_RIGHTLEFT - static void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag); - # define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c), (rl)) - #else - static void screen_line(int row, int coloff, int endcol, int clear_width); - # define SCREEN_LINE(r, o, e, c, rl) screen_line((r), (o), (e), (c)) - #endif #ifdef FEAT_WINDOWS static void draw_vsep_win(win_T *wp, int row); #endif --- 126,131 ---- *************** *** 411,417 **** screenline2 + r * cols, (size_t)cols * sizeof(schar_T)); #endif ! SCREEN_LINE(cmdline_row + r, 0, cols, cols, FALSE); } ret = 4; } --- 404,410 ---- screenline2 + r * cols, (size_t)cols * sizeof(schar_T)); #endif ! screen_line(cmdline_row + r, 0, cols, cols, FALSE); } ret = 4; } *************** *** 1192,1197 **** --- 1185,1201 ---- } #endif + #ifdef FEAT_TERMINAL + if (wp->w_buffer->b_term != NULL) + { + /* This window contains a terminal, redraw works completely + * differently. */ + term_update_window(wp); + wp->w_redr_type = 0; + return; + } + #endif + #ifdef FEAT_SEARCH_EXTRA init_search_hl(wp); #endif *************** *** 2886,2892 **** } #endif ! SCREEN_LINE(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp), (int)W_WIDTH(wp), FALSE); /* --- 2890,2896 ---- } #endif ! screen_line(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp), (int)W_WIDTH(wp), FALSE); /* *************** *** 3996,4002 **** #endif ) { ! SCREEN_LINE(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp), wp->w_p_rl); /* Pretend we have finished updating the window. Except when * 'cursorcolumn' is set. */ --- 4000,4006 ---- #endif ) { ! screen_line(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp), wp->w_p_rl); /* Pretend we have finished updating the window. Except when * 'cursorcolumn' is set. */ *************** *** 5443,5449 **** } #endif ! SCREEN_LINE(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp), wp->w_p_rl); row++; --- 5447,5453 ---- } #endif ! screen_line(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp), wp->w_p_rl); row++; *************** *** 5749,5759 **** ) { #ifdef FEAT_CONCEAL ! SCREEN_LINE(screen_row, W_WINCOL(wp), col - boguscols, (int)W_WIDTH(wp), wp->w_p_rl); boguscols = 0; #else ! SCREEN_LINE(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp), wp->w_p_rl); #endif ++row; --- 5753,5763 ---- ) { #ifdef FEAT_CONCEAL ! screen_line(screen_row, W_WINCOL(wp), col - boguscols, (int)W_WIDTH(wp), wp->w_p_rl); boguscols = 0; #else ! screen_line(screen_row, W_WINCOL(wp), col, (int)W_WIDTH(wp), wp->w_p_rl); #endif ++row; *************** *** 5959,5964 **** --- 5963,5979 ---- return FALSE; } + #if defined(FEAT_TERMINAL) || defined(PROTO) + /* + * Return the index in ScreenLines[] for the current screen line. + */ + int + screen_get_current_line_off() + { + return (int)(current_ScreenLine - ScreenLines); + } + #endif + /* * Move one "cooked" screen line to the screen, but only the characters that * have actually changed. Handle insert/delete character. *************** *** 5970,5985 **** * When TRUE and "clear_width" > 0, clear columns 0 to "endcol" * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width" */ ! static void screen_line( int row, int coloff, int endcol, ! int clear_width ! #ifdef FEAT_RIGHTLEFT ! , int rlflag ! #endif ! ) { unsigned off_from; unsigned off_to; --- 5985,5997 ---- * When TRUE and "clear_width" > 0, clear columns 0 to "endcol" * When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width" */ ! void screen_line( int row, int coloff, int endcol, ! int clear_width, ! int rlflag UNUSED) { unsigned off_from; unsigned off_to; *** ../vim-8.0.0717/src/proto/screen.pro 2017-04-30 19:39:32.650857838 +0200 --- src/proto/screen.pro 2017-07-15 21:37:38.948173764 +0200 *************** *** 16,21 **** --- 16,23 ---- void update_single_line(win_T *wp, linenr_T lnum); void update_debug_sign(buf_T *buf, linenr_T lnum); void updateWindow(win_T *wp); + int screen_get_current_line_off(void); + void screen_line(int row, int coloff, int endcol, int clear_width, int rlflag); void rl_mirror(char_u *str); void status_redraw_all(void); void status_redraw_curbuf(void); *** ../vim-8.0.0717/src/version.c 2017-07-15 20:05:50.802053721 +0200 --- src/version.c 2017-07-15 22:57:06.592204161 +0200 *************** *** 771,772 **** --- 771,774 ---- { /* Add new patch number below this line */ + /**/ + 718, /**/ -- hundred-and-one symptoms of being an internet addict: 163. You go outside for the fresh air (at -30 degrees) but open the window first to hear new mail arrive. /// 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 ///