changeset 11670:3b2afa2b77b3 v8.0.0718

patch 8.0.0718: output of job in terminal is not displayed commit https://github.com/vim/vim/commit/cb8bbe9bf3214d07580d6b43d6539416884153bd Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 16 13:48:22 2017 +0200 patch 8.0.0718: output of job in terminal is not displayed Problem: Output of job in terminal is not displayed. Solution: Connect the job output to the terminal.
author Christian Brabandt <cb@256bit.org>
date Sun, 16 Jul 2017 14:00:03 +0200
parents 20bedd70c837
children 3b498e41d760
files src/channel.c src/evalfunc.c src/proto/channel.pro src/proto/screen.pro src/proto/terminal.pro src/screen.c src/terminal.c src/version.c
diffstat 8 files changed, 176 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -171,7 +171,7 @@ ch_log(channel_T *ch, char *msg)
     }
 }
 
-    static void
+    void
 ch_logn(channel_T *ch, char *msg, int nr)
 {
     if (log_fd != NULL)
@@ -2656,7 +2656,12 @@ may_invoke_callback(channel_T *channel, 
 		/* 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 (buffer->b_term != NULL)
+		    write_to_term(buffer, msg, channel);
+		else
+		    append_to_buffer(buffer, msg, channel, part);
+	    }
 	}
 
 	if (callback != NULL)
@@ -4889,7 +4894,7 @@ job_check_ended(void)
  * "job_start()" function
  */
     job_T *
-job_start(typval_T *argvars)
+job_start(typval_T *argvars, jobopt_T *opt_arg)
 {
     job_T	*job;
     char_u	*cmd = NULL;
@@ -4912,13 +4917,18 @@ job_start(typval_T *argvars)
     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,
+    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)
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -6745,7 +6745,7 @@ f_job_start(typval_T *argvars, typval_T 
     rettv->v_type = VAR_JOB;
     if (check_restricted() || check_secure())
 	return;
-    rettv->vval.v_job = job_start(argvars);
+    rettv->vval.v_job = job_start(argvars, NULL);
 }
 
 /*
--- a/src/proto/channel.pro
+++ b/src/proto/channel.pro
@@ -2,6 +2,7 @@
 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,7 +64,7 @@ void job_set_options(job_T *job, jobopt_
 void job_stop_on_exit(void);
 int has_pending_job(void);
 void job_check_ended(void);
-job_T *job_start(typval_T *argvars);
+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);
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -16,6 +16,8 @@ void conceal_check_cursur_line(void);
 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);
--- a/src/proto/terminal.pro
+++ b/src/proto/terminal.pro
@@ -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 : */
--- a/src/screen.c
+++ b/src/screen.c
@@ -126,13 +126,6 @@ static void copy_text_attr(int off, char
 #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
@@ -411,7 +404,7 @@ redraw_asap(int type)
 				screenline2 + r * cols,
 				(size_t)cols * sizeof(schar_T));
 #endif
-		SCREEN_LINE(cmdline_row + r, 0, cols, cols, FALSE);
+		screen_line(cmdline_row + r, 0, cols, cols, FALSE);
 	    }
 	    ret = 4;
 	}
@@ -1192,6 +1185,17 @@ win_update(win_T *wp)
     }
 #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,7 +2890,7 @@ fold_line(
     }
 #endif
 
-    SCREEN_LINE(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp),
+    screen_line(row + W_WINROW(wp), W_WINCOL(wp), (int)W_WIDTH(wp),
 						     (int)W_WIDTH(wp), FALSE);
 
     /*
@@ -3996,7 +4000,7 @@ win_line(
 #endif
 		)
 	{
-	    SCREEN_LINE(screen_row, W_WINCOL(wp), col, -(int)W_WIDTH(wp),
+	    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,7 +5447,7 @@ win_line(
 	    }
 #endif
 
-	    SCREEN_LINE(screen_row, W_WINCOL(wp), col,
+	    screen_line(screen_row, W_WINCOL(wp), col,
 						(int)W_WIDTH(wp), wp->w_p_rl);
 	    row++;
 
@@ -5749,11 +5753,11 @@ win_line(
 		)
 	{
 #ifdef FEAT_CONCEAL
-	    SCREEN_LINE(screen_row, W_WINCOL(wp), col - boguscols,
+	    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,
+	    screen_line(screen_row, W_WINCOL(wp), col,
 						(int)W_WIDTH(wp), wp->w_p_rl);
 #endif
 	    ++row;
@@ -5959,6 +5963,17 @@ char_needs_redraw(int off_from, int off_
     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,16 +5985,13 @@ char_needs_redraw(int off_from, int off_
  *    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
+    void
 screen_line(
     int	    row,
     int	    coloff,
     int	    endcol,
-    int	    clear_width
-#ifdef FEAT_RIGHTLEFT
-    , int   rlflag
-#endif
-    )
+    int	    clear_width,
+    int	    rlflag UNUSED)
 {
     unsigned	    off_from;
     unsigned	    off_to;
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -28,6 +28,8 @@
  * - 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,6 +42,7 @@
  * - implement term_scrape()		inspect terminal screen
  * - implement term_open()		open terminal window
  * - implement term_getjob()
+ * - implement 'termkey'
  */
 
 #include "vim.h"
@@ -54,6 +57,7 @@ struct terminal_S {
 
     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,6 +103,7 @@ ex_terminal(exarg_T *eap)
     term_T	*term;
     VTerm	*vterm;
     VTermScreen *screen;
+    jobopt_T	opt;
 
     if (check_restricted() || check_secure())
 	return;
@@ -120,6 +125,7 @@ ex_terminal(exarg_T *eap)
 	vim_free(term);
 	return;
     }
+    term->tl_buffer = curbuf;
 
     curbuf->b_term = term;
     term->tl_next = first_term;
@@ -145,14 +151,94 @@ ex_terminal(exarg_T *eap)
     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;
-    argvars[1].v_type = VAR_UNKNOWN;
-    term->tl_job = job_start(argvars);
+
+    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();
+}
 
-    /* TODO: setup channels to/from job */
-    /* Setup pty, see mch_call_shell(). */
+/*
+ * 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
@@ -162,27 +248,55 @@ handle_damage(VTermRect rect, void *user
 
     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)
 {
-    /* TODO: handle moving the cursor. */
+    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,10 +315,4 @@ handle_resize(int rows, int cols, void *
  * - 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 */
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    718,
+/**/
     717,
 /**/
     716,