changeset 11684:1ce1376fbbf8 v8.0.0725

patch 8.0.0725: a terminal window does not handle keyboard input commit https://github.com/vim/vim/commit/938783d0ab5678c259ceb62b15be72abe69362fa Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 16 20:13:26 2017 +0200 patch 8.0.0725: a terminal window does not handle keyboard input Problem: A terminal window does not handle keyboard input. Solution: Add terminal_loop(). ":term bash -i" sort of works now.
author Christian Brabandt <cb@256bit.org>
date Sun, 16 Jul 2017 20:15:03 +0200
parents 0cc8e85e29d4
children 50455b3aeae5
files src/main.c src/normal.c src/proto/terminal.pro src/terminal.c src/version.c
diffstat 5 files changed, 122 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/main.c
+++ b/src/main.c
@@ -1354,7 +1354,14 @@ main_loop(
 	    do_exmode(exmode_active == EXMODE_VIM);
 	}
 	else
+	{
+#ifdef FEAT_TERMINAL
+	    if (curbuf->b_term != NULL && oa.op_type == OP_NOP
+							  && oa.regname == NUL)
+		terminal_loop();
+#endif
 	    normal_cmd(&oa, TRUE);
+	}
     }
 }
 
--- a/src/normal.c
+++ b/src/normal.c
@@ -7846,7 +7846,10 @@ n_start_visual_mode(int c)
 nv_window(cmdarg_T *cap)
 {
 #ifdef FEAT_WINDOWS
-    if (!checkclearop(cap->oap))
+    if (cap->nchar == ':')
+	/* "CTRL-W :" is the same as typing ":"; useful in a terminal window */
+	nv_colon(cap);
+    else if (!checkclearop(cap->oap))
 	do_window(cap->nchar, cap->count0, NUL); /* everything is in window.c */
 #else
     (void)checkclearop(cap->oap);
--- a/src/proto/terminal.pro
+++ b/src/proto/terminal.pro
@@ -2,4 +2,5 @@
 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);
+void terminal_loop(void);
 /* vim: set ft=c : */
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -15,7 +15,7 @@
  *
  * The VTerm invokes callbacks when its screen contents changes.  The line
  * range is stored in tl_dirty_row_start and tl_dirty_row_end.  Once in a
- * while, if the window is visible, the screen contents is drawn.
+ * while, if the terminal window is visible, the screen contents is drawn.
  *
  * If the terminal window has keyboard focus, typed keys are converted to the
  * terminal encoding and writting to the job over a channel.
@@ -24,13 +24,21 @@
  * This will result in screen updates.
  *
  * TODO:
+ * - pressing Enter sends two CR and/or NL characters to "bash -i"?
  * - free b_term when closing terminal.
  * - 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)
+ * - when closing window and job ended, delete the terminal
+ * - when closing window and job has not ended, make terminal hidden?
+ * - Use a pty for I/O with the job.
+ * - Windows implementation:
+ *   (WiP): https://github.com/mattn/vim/tree/terminal
+ *	src/os_win32.c  mch_open_terminal()
+     Using winpty ?
+ * - command line completion for :terminal
  * - support fixed size when 'termsize' is "rowsXcols".
  * - support minimal size when 'termsize' is "rows*cols".
  * - support minimal size when 'termsize' is empty.
@@ -157,6 +165,7 @@ ex_terminal(exarg_T *eap)
     vterm_screen_reset(screen, 1 /* hard */);
 
     /* By default NL means CR-NL. */
+    /* TODO: this causes two prompts when using ":term bash -i". */
     vterm_input_write(vterm, "\x1b[20h", 5);
 
     argvars[0].v_type = VAR_STRING;
@@ -302,17 +311,104 @@ handle_resize(int rows, int cols, void *
 
 /* TODO: Use win_del_lines() to make scroll up efficient. */
 
-/* TODO: function to update the window.
- * Get the screen contents from vterm with vterm_screen_get_cell().
- * put in current_ScreenLine and call screen_line().
+
+/*
+ * Wait for input and send it to the job.
+ * Return when a CTRL-W command is typed that moves to another window.
  */
+    void
+terminal_loop(void)
+{
+    VTerm   *vterm = curbuf->b_term->tl_vterm;
+    char    buf[200];
+
+    for (;;)
+    {
+	int c;
+	VTermKey key = VTERM_KEY_NONE;
+	VTermModifier mod = VTERM_MOD_NONE;
+	size_t len;
+
+	update_screen(0);
+	setcursor();
+	out_flush();
+
+	c = vgetc();
+	switch (c)
+	{
+	    case Ctrl_W:
+		stuffcharReadbuff(Ctrl_W);
+		return;
 
-/* TODO: function to wait for input and send it to the job.
- * Return when a CTRL-W command is typed that moves to another window.
- * Convert special keys to vterm keys:
- * - Write keys to vterm: vterm_keyboard_key()
- * - read the output (xterm escape sequences): vterm_output_read()
- * - Write output to channel.
- */
+	    case CAR:		key = VTERM_KEY_ENTER; break;
+	    case ESC:		key = VTERM_KEY_ESCAPE; break;
+	    case K_BS:		key = VTERM_KEY_BACKSPACE; break;
+	    case K_DEL:		key = VTERM_KEY_DEL; break;
+	    case K_DOWN:	key = VTERM_KEY_DOWN; break;
+	    case K_END:		key = VTERM_KEY_END; break;
+	    case K_F10:		key = VTERM_KEY_FUNCTION(10); break;
+	    case K_F11:		key = VTERM_KEY_FUNCTION(11); break;
+	    case K_F12:		key = VTERM_KEY_FUNCTION(12); break;
+	    case K_F1:		key = VTERM_KEY_FUNCTION(1); break;
+	    case K_F2:		key = VTERM_KEY_FUNCTION(2); break;
+	    case K_F3:		key = VTERM_KEY_FUNCTION(3); break;
+	    case K_F4:		key = VTERM_KEY_FUNCTION(4); break;
+	    case K_F5:		key = VTERM_KEY_FUNCTION(5); break;
+	    case K_F6:		key = VTERM_KEY_FUNCTION(6); break;
+	    case K_F7:		key = VTERM_KEY_FUNCTION(7); break;
+	    case K_F8:		key = VTERM_KEY_FUNCTION(8); break;
+	    case K_F9:		key = VTERM_KEY_FUNCTION(9); break;
+	    case K_HOME:	key = VTERM_KEY_HOME; break;
+	    case K_INS:		key = VTERM_KEY_INS; break;
+	    case K_K0:		key = VTERM_KEY_KP_0; break;
+	    case K_K1:		key = VTERM_KEY_KP_1; break;
+	    case K_K2:		key = VTERM_KEY_KP_2; break;
+	    case K_K3:		key = VTERM_KEY_KP_3; break;
+	    case K_K4:		key = VTERM_KEY_KP_4; break;
+	    case K_K5:		key = VTERM_KEY_KP_5; break;
+	    case K_K6:		key = VTERM_KEY_KP_6; break;
+	    case K_K7:		key = VTERM_KEY_KP_7; break;
+	    case K_K8:		key = VTERM_KEY_KP_8; break;
+	    case K_K9:		key = VTERM_KEY_KP_9; break;
+	    case K_KDEL:	key = VTERM_KEY_DEL; break; /* TODO */
+	    case K_KDIVIDE:	key = VTERM_KEY_KP_DIVIDE; break;
+	    case K_KEND:	key = VTERM_KEY_KP_1; break; /* TODO */
+	    case K_KENTER:	key = VTERM_KEY_KP_ENTER; break;
+	    case K_KHOME:	key = VTERM_KEY_KP_7; break; /* TODO */
+	    case K_KINS:	key = VTERM_KEY_KP_0; break; /* TODO */
+	    case K_KMINUS:	key = VTERM_KEY_KP_MINUS; break;
+	    case K_KMULTIPLY:	key = VTERM_KEY_KP_MULT; break;
+	    case K_KPAGEDOWN:	key = VTERM_KEY_KP_3; break; /* TODO */
+	    case K_KPAGEUP:	key = VTERM_KEY_KP_9; break; /* TODO */
+	    case K_KPLUS:	key = VTERM_KEY_KP_PLUS; break;
+	    case K_KPOINT:	key = VTERM_KEY_KP_PERIOD; break;
+	    case K_LEFT:	key = VTERM_KEY_LEFT; break;
+	    case K_PAGEDOWN:	key = VTERM_KEY_PAGEDOWN; break;
+	    case K_PAGEUP:	key = VTERM_KEY_PAGEUP; break;
+	    case K_RIGHT:	key = VTERM_KEY_RIGHT; break;
+	    case K_UP:		key = VTERM_KEY_UP; break;
+	    case TAB:		key = VTERM_KEY_TAB; break;
+	}
+
+	/*
+	 * Convert special keys to vterm keys:
+	 * - Write keys to vterm: vterm_keyboard_key()
+	 * - Write output to channel.
+	 */
+	if (key != VTERM_KEY_NONE)
+	    /* Special key, let vterm convert it. */
+	    vterm_keyboard_key(vterm, key, mod);
+	else
+	    /* Normal character, let vterm convert it. */
+	    vterm_keyboard_unichar(vterm, c, mod);
+
+	/* Read back the converted escape sequence. */
+	len = vterm_output_read(vterm, buf, sizeof(buf));
+
+	/* TODO: if FAIL is returned, stop? */
+	channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN,
+						     (char_u *)buf, len, NULL);
+    }
+}
 
 #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 */
 /**/
+    725,
+/**/
     724,
 /**/
     723,