changeset 12457:dfb8254aa735 v8.0.1108

patch 8.0.1108: cannot specify mappings for the terminal window commit https://github.com/vim/vim/commit/69fbc9e1dab176f345719436cd89d854df0a2abd Author: Bram Moolenaar <Bram@vim.org> Date: Thu Sep 14 20:37:57 2017 +0200 patch 8.0.1108: cannot specify mappings for the terminal window Problem: Cannot specify mappings for the terminal window. Solution: Add the :tmap command and associated code. (Jacob Askeland, closes #2073)
author Christian Brabandt <cb@256bit.org>
date Thu, 14 Sep 2017 20:45:05 +0200
parents bc590831aac5
children a99b6c31b925
files runtime/doc/map.txt runtime/doc/terminal.txt src/evalfunc.c src/ex_cmdidxs.h src/ex_cmds.h src/ex_docmd.c src/getchar.c src/gui.c src/main.c src/proto/terminal.pro src/terminal.c src/testdir/test_terminal.vim src/version.c src/vim.h
diffstat 14 files changed, 127 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -55,6 +55,7 @@ modes.
 :im[ap]	{lhs} {rhs}		|mapmode-i|		*:im* *:imap*
 :lm[ap]	{lhs} {rhs}		|mapmode-l|		*:lm* *:lmap*
 :cm[ap]	{lhs} {rhs}		|mapmode-c|		*:cm* *:cmap*
+:tm[ap]	{lhs} {rhs}		|mapmode-t|		*:tm* *:tmap*
 			Map the key sequence {lhs} to {rhs} for the modes
 			where the map command applies.  The result, including
 			{rhs}, is then further scanned for mappings.  This
@@ -71,6 +72,7 @@ modes.
 :ino[remap] {lhs} {rhs}		|mapmode-i|	*:ino* *:inoremap*
 :ln[oremap] {lhs} {rhs}		|mapmode-l|	*:ln*  *:lnoremap*
 :cno[remap] {lhs} {rhs}		|mapmode-c|	*:cno* *:cnoremap*
+:tno[remap] {lhs} {rhs}		|mapmode-t|	*:tno* *:tnoremap*
 			Map the key sequence {lhs} to {rhs} for the modes
 			where the map command applies.  Disallow mapping of
 			{rhs}, to avoid nested and recursive mappings.  Often
@@ -87,6 +89,7 @@ modes.
 :iu[nmap] {lhs}			|mapmode-i|		*:iu*   *:iunmap*
 :lu[nmap] {lhs}			|mapmode-l|		*:lu*   *:lunmap*
 :cu[nmap] {lhs}			|mapmode-c|		*:cu*   *:cunmap*
+:tu[nmap] {lhs}			|mapmode-t|		*:tu*   *:tunmap*
 			Remove the mapping of {lhs} for the modes where the
 			map command applies.  The mapping may remain defined
 			for other modes where it applies.
@@ -105,6 +108,7 @@ modes.
 :imapc[lear]			|mapmode-i|		*:imapc*  *:imapclear*
 :lmapc[lear]			|mapmode-l|		*:lmapc*  *:lmapclear*
 :cmapc[lear]			|mapmode-c|		*:cmapc*  *:cmapclear*
+:tmapc[lear]			|mapmode-t|		*:tmapc*  *:tmapclear*
 			Remove ALL mappings for the modes where the map
 			command applies.  {not in Vi}
 			Use the <buffer> argument to remove buffer-local
@@ -121,6 +125,7 @@ modes.
 :im[ap]				|mapmode-i|
 :lm[ap]				|mapmode-l|
 :cm[ap]				|mapmode-c|
+:tm[ap]				|mapmode-t|
 			List all key mappings for the modes where the map
 			command applies.  Note that ":map" and ":map!" are
 			used most often, because they include the other modes.
@@ -135,6 +140,7 @@ modes.
 :im[ap] {lhs}			|mapmode-i|		*:imap_l*
 :lm[ap] {lhs}			|mapmode-l|		*:lmap_l*
 :cm[ap] {lhs}			|mapmode-c|		*:cmap_l*
+:tm[ap] {lhs}			|mapmode-t|		*:tmap_l*
 			List the key mappings for the key sequences starting
 			with {lhs} in the modes where the map command applies.
 			{not in Vi}
@@ -318,6 +324,7 @@ Overview of which map command works in w
 :imap  :inoremap :iunmap    Insert
 :lmap  :lnoremap :lunmap    Insert, Command-line, Lang-Arg
 :cmap  :cnoremap :cunmap    Command-line
+:tmap  :tnoremap :tunmap    Terminal-Job
 
 
     COMMANDS				      MODES ~
@@ -358,6 +365,10 @@ Therefore the ":map" and ":map!" command
 several modes.  In Vim you can use the ":nmap", ":vmap", ":omap", ":cmap" and
 ":imap" commands to enter mappings for each mode separately.
 
+							*mapmode-t*
+The terminal mappings are used in a terminal window, when typing keys for the
+job running in the terminal.  See |terminal-typing|.
+
 							*omap-info*
 Operator-pending mappings can be used to define a movement command that can be
 used with any operator.  Simple example: ":omap { w" makes "y{" work like "yw"
@@ -418,6 +429,7 @@ When listing mappings the characters in 
 	i	Insert
 	l	":lmap" mappings for Insert, Command-line and Lang-Arg
 	c	Command-line
+        t       Terminal-Job
 
 Just before the {rhs} a special character can appear:
 	*	indicates that it is not remappable
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -1,4 +1,4 @@
-*terminal.txt*	For Vim version 8.0.  Last change: 2017 Sep 13
+*terminal.txt*	For Vim version 8.0.  Last change: 2017 Sep 14
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -38,7 +38,7 @@ output from the job, also while editing 
 
 
 Typing ~
-
+							*terminal-typing*
 When the keyboard focus is in the terminal window, typed keys will be sent to
 the job.  This uses a pty when possible.  You can click outside of the
 terminal window to move keyboard focus elsewhere.
@@ -79,6 +79,10 @@ do.  For simple commands this causes a S
 would end it.  Other commands may ignore the SIGINT or handle the CTRL-C
 themselves (like Vim does).
 
+To change the keys you type use terminal mode mappings, see |:tmap|.
+These are defined like any mapping, but apply only when typing keys that are
+sent to the job running in the terminal.
+
 
 Size and color ~
 
@@ -221,6 +225,10 @@ mode.
 Use CTRL-W N (or 'termkey' N) to switch to Terminal-Normal mode.  Now the
 contents of the terminal window is under control of Vim, the job output is
 suspended.  CTRL-\ CTRL-N does the same.
+
+Terminal-Job mode is where |tmap| mappings are applied. Keys sent by
+|term_sendkeys()| are not subject to tmap, but keys from |feedkeys()| are.
+
 							*E946*
 In Terminal-Normal mode you can move the cursor around with the usual Vim
 commands, Visually mark text, yank text, etc.  But you cannot change the
@@ -301,7 +309,7 @@ inspects the resulting screen state.
 
 Functions ~
 
-term_sendkeys()		send keystrokes to a terminal
+term_sendkeys()		send keystrokes to a terminal (not subject to tmap)
 term_wait()		wait for screen to be updated
 term_scrape()		inspect terminal screen
 
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -3259,11 +3259,18 @@ f_feedkeys(typval_T *argvars, typval_T *
 		/* Avoid a 1 second delay when the keys start Insert mode. */
 		msg_scroll = FALSE;
 
-		if (!dangerous)
-		    ++ex_normal_busy;
-		exec_normal(TRUE);
-		if (!dangerous)
-		    --ex_normal_busy;
+#ifdef FEAT_TERMINAL
+		if (term_use_loop())
+		    terminal_loop(FALSE);
+		else
+#endif
+		{
+		    if (!dangerous)
+			++ex_normal_busy;
+		    exec_normal(TRUE);
+		    if (!dangerous)
+			--ex_normal_busy;
+		}
 		msg_scroll |= save_msg_scroll;
 	    }
 	}
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -25,12 +25,12 @@ static const unsigned short cmdidxs1[26]
   /* r */ 351,
   /* s */ 370,
   /* t */ 437,
-  /* u */ 473,
-  /* v */ 484,
-  /* w */ 502,
-  /* x */ 517,
-  /* y */ 526,
-  /* z */ 527
+  /* u */ 477,
+  /* v */ 488,
+  /* w */ 506,
+  /* x */ 521,
+  /* y */ 530,
+  /* z */ 531
 };
 
 /*
@@ -60,7 +60,7 @@ static const unsigned char cmdidxs2[26][
   /* q */ {  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
   /* r */ {  0,  0,  0,  0,  0,  0,  0,  0, 11,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 13, 18,  0,  0,  0,  0 },
   /* s */ {  2,  6, 15,  0, 18, 22,  0, 24, 25,  0,  0, 28, 30, 34, 38, 40,  0, 48,  0, 49,  0, 61, 62,  0, 63,  0 },
-  /* t */ {  2,  0, 19,  0, 22, 24,  0, 25,  0, 26,  0, 27, 28, 29, 30, 31,  0, 32, 34,  0, 35,  0,  0,  0,  0,  0 },
+  /* t */ {  2,  0, 19,  0, 22, 24,  0, 25,  0, 26,  0, 27, 28, 31, 33, 34,  0, 35, 37,  0, 38,  0,  0,  0,  0,  0 },
   /* u */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
   /* v */ {  0,  0,  0,  0,  1,  0,  0,  0,  4,  0,  0,  0,  9, 12,  0,  0,  0,  0, 15,  0, 16,  0,  0,  0,  0,  0 },
   /* w */ {  2,  0,  0,  0,  0,  0,  0,  3,  4,  0,  0,  0,  0,  8,  0,  9, 10,  0, 12,  0, 13, 14,  0,  0,  0,  0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][
   /* z */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }
 };
 
-static const int command_count = 540;
+static const int command_count = 544;
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1484,7 +1484,7 @@ EX(CMD_tearoff,		"tearoff",	ex_tearoff,
 			NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN,
 			ADDR_LINES),
 EX(CMD_terminal,	"terminal",	ex_terminal,
-			RANGE|BANG|FILES|TRLBAR|CMDWIN,
+			RANGE|BANG|FILES|CMDWIN,
 			ADDR_LINES),
 EX(CMD_tfirst,		"tfirst",	ex_tag,
 			RANGE|NOTADR|BANG|TRLBAR|ZEROR,
@@ -1498,12 +1498,21 @@ EX(CMD_tjump,		"tjump",	ex_tag,
 EX(CMD_tlast,		"tlast",	ex_tag,
 			BANG|TRLBAR,
 			ADDR_LINES),
+EX(CMD_tmap,		"tmap",		ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+			ADDR_LINES),
+EX(CMD_tmapclear,	"tmapclear",	ex_mapclear,
+			EXTRA|TRLBAR|CMDWIN,
+			ADDR_LINES),
 EX(CMD_tmenu,		"tmenu",	ex_menu,
 			RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
 			ADDR_LINES),
 EX(CMD_tnext,		"tnext",	ex_tag,
 			RANGE|NOTADR|BANG|TRLBAR|ZEROR,
 			ADDR_LINES),
+EX(CMD_tnoremap,	"tnoremap",	ex_map,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+			ADDR_LINES),
 EX(CMD_topleft,		"topleft",	ex_wrongmodifier,
 			NEEDARG|EXTRA|NOTRLCOM,
 			ADDR_LINES),
@@ -1519,6 +1528,9 @@ EX(CMD_try,		"try",		ex_try,
 EX(CMD_tselect,		"tselect",	ex_tag,
 			BANG|TRLBAR|WORD1,
 			ADDR_LINES),
+EX(CMD_tunmap,		"tunmap",	ex_unmap,
+			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
+			ADDR_LINES),
 EX(CMD_tunmenu,		"tunmenu",	ex_menu,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
 			ADDR_LINES),
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -4209,6 +4209,7 @@ set_one_cmd_context(
 	case CMD_cmap:	    case CMD_cnoremap:
 	case CMD_lmap:	    case CMD_lnoremap:
 	case CMD_smap:	    case CMD_snoremap:
+	case CMD_tmap:	    case CMD_tnoremap:
 	case CMD_xmap:	    case CMD_xnoremap:
 	    return set_context_in_map_cmd(xp, cmd, arg, forceit,
 						     FALSE, FALSE, ea.cmdidx);
@@ -4220,6 +4221,7 @@ set_one_cmd_context(
 	case CMD_cunmap:
 	case CMD_lunmap:
 	case CMD_sunmap:
+	case CMD_tunmap:
 	case CMD_xunmap:
 	    return set_context_in_map_cmd(xp, cmd, arg, forceit,
 						      FALSE, TRUE, ea.cmdidx);
@@ -4231,6 +4233,7 @@ set_one_cmd_context(
 	case CMD_cmapclear:
 	case CMD_lmapclear:
 	case CMD_smapclear:
+	case CMD_tmapclear:
 	case CMD_xmapclear:
 	    xp->xp_context = EXPAND_MAPCLEAR;
 	    xp->xp_pattern = arg;
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -59,7 +59,7 @@ static int	block_redo = FALSE;
  * Returns a value between 0 and 255, index in maphash.
  * Put Normal/Visual mode mappings mostly separately from Insert/Cmdline mode.
  */
-#define MAP_HASH(mode, c1) (((mode) & (NORMAL + VISUAL + SELECTMODE + OP_PENDING)) ? (c1) : ((c1) ^ 0x80))
+#define MAP_HASH(mode, c1) (((mode) & (NORMAL + VISUAL + SELECTMODE + OP_PENDING + TERMINAL)) ? (c1) : ((c1) ^ 0x80))
 
 /*
  * Each mapping is put in one of the 256 hash lists, to speed up finding it.
@@ -3188,6 +3188,7 @@ input_available(void)
  * for :xmap  mode is VISUAL
  * for :smap  mode is SELECTMODE
  * for :omap  mode is OP_PENDING
+ * for :tmap  mode is TERMINAL
  *
  * for :abbr  mode is INSERT + CMDLINE
  * for :iabbr mode is INSERT
@@ -3832,6 +3833,8 @@ get_map_mode(char_u **cmdp, int forceit)
 	mode = SELECTMODE;			/* :smap */
     else if (modec == 'o')
 	mode = OP_PENDING;			/* :omap */
+    else if (modec == 't')
+	mode = TERMINAL;			/* :tmap */
     else
     {
 	--p;
@@ -4892,6 +4895,9 @@ makemap(
 		    case LANGMAP:
 			c1 = 'l';
 			break;
+		    case TERMINAL:
+			c1 = 't';
+			break;
 		    default:
 			IEMSG(_("E228: makemap: Illegal mode"));
 			return FAIL;
--- a/src/gui.c
+++ b/src/gui.c
@@ -1101,7 +1101,7 @@ gui_update_cursor(
 	 * When in a terminal window use the shape/color specified there.
 	 */
 #ifdef FEAT_TERMINAL
-	if (use_terminal_cursor())
+	if (terminal_is_active())
 	    shape = term_get_cursor_shape(&shape_fg, &shape_bg);
 	else
 #endif
--- a/src/main.c
+++ b/src/main.c
@@ -1363,7 +1363,7 @@ main_loop(
 		/* If terminal_loop() returns OK we got a key that is handled
 		 * in Normal model.  With FAIL we first need to position the
 		 * cursor and the screen needs to be redrawn. */
-		if (terminal_loop() == OK)
+		if (terminal_loop(TRUE) == OK)
 		    normal_cmd(&oa, TRUE);
 	    }
 	    else
--- a/src/proto/terminal.pro
+++ b/src/proto/terminal.pro
@@ -7,10 +7,10 @@ int term_none_open(term_T *term);
 int term_in_normal_mode(void);
 void term_enter_job_mode(void);
 int send_keys_to_term(term_T *term, int c, int typed);
-int use_terminal_cursor(void);
+int terminal_is_active(void);
 cursorentry_T *term_get_cursor_shape(guicolor_T *fg, guicolor_T *bg);
 int term_use_loop(void);
-int terminal_loop(void);
+int terminal_loop(int blocking);
 void term_job_ended(job_T *job);
 void term_channel_closed(channel_T *ch);
 int term_update_window(win_T *wp);
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -38,10 +38,9 @@
  * in tl_scrollback are no longer used.
  *
  * TODO:
- * - patch to add tmap, jakalope (Jacob Askeland) #2073
+ * - test_terminal_no_cmd hangs (Christian)
  * - Redirecting output does not work on MS-Windows, Test_terminal_redir_file()
  *   is disabled.
- * - test_terminal_no_cmd hangs (Christian)
  * - implement term_setsize()
  * - add test for giving error for invalid 'termsize' value.
  * - support minimal size when 'termsize' is "rows*cols".
@@ -56,7 +55,9 @@
  *   mouse in the Terminal window for copy/paste.
  * - when 'encoding' is not utf-8, or the job is using another encoding, setup
  *   conversions.
- * - In the GUI use a terminal emulator for :!cmd.
+ * - In the GUI use a terminal emulator for :!cmd.  Make the height the same as
+ *   the window and position it higher up when it gets filled, so it looks like
+ *   the text scrolls up.
  * - Copy text in the vterm to the Vim buffer once in a while, so that
  *   completion works.
  * - add an optional limit for the scrollback size.  When reaching it remove
@@ -1201,23 +1202,22 @@ term_enter_job_mode()
  * Get a key from the user without mapping.
  * Note: while waiting a terminal may be closed and freed if the channel is
  * closed and ++close was used.
- * TODO: use terminal mode mappings.
+ * Uses terminal mode mappings.
  */
     static int
 term_vgetc()
 {
     int c;
-
-    ++no_mapping;
-    ++allow_keys;
+    int save_State = State;
+
+    State = TERMINAL;
     got_int = FALSE;
 #ifdef WIN3264
     ctrl_break_was_pressed = FALSE;
 #endif
     c = vgetc();
     got_int = FALSE;
-    --no_mapping;
-    --allow_keys;
+    State = save_State;
     return c;
 }
 
@@ -1406,7 +1406,7 @@ term_paste_register(int prev_c UNUSED)
  * Return TRUE when the cursor of the terminal should be displayed.
  */
     int
-use_terminal_cursor()
+terminal_is_active()
 {
     return in_terminal_loop != NULL;
 }
@@ -1496,13 +1496,15 @@ term_use_loop(void)
 
 /*
  * Wait for input and send it to the job.
+ * When "blocking" is TRUE wait for a character to be typed.  Otherwise return
+ * when there is no more typahead.
  * Return when the start of a CTRL-W command is typed or anything else that
  * should be handled as a Normal mode command.
  * Returns OK if a typed character is to be handled in Normal mode, FAIL if
  * the terminal was closed.
  */
     int
-terminal_loop(void)
+terminal_loop(int blocking)
 {
     int		c;
     int		termkey = 0;
@@ -1539,7 +1541,7 @@ terminal_loop(void)
     }
 #endif
 
-    for (;;)
+    while (blocking || vpeekc() != NUL)
     {
 	/* TODO: skip screen update when handling a sequence of keys. */
 	/* Repeat redrawing in case a message is received while redrawing. */
@@ -1561,7 +1563,7 @@ terminal_loop(void)
 	if (ctrl_break_was_pressed)
 	    mch_signal_job(curbuf->b_term->tl_job, (char_u *)"kill");
 #endif
-
+	/* Was either CTRL-W (termkey) or CTRL-\ pressed? */
 	if (c == (termkey == 0 ? Ctrl_W : termkey) || c == Ctrl_BSL)
 	{
 	    int	    prev_c = c;
--- a/src/testdir/test_terminal.vim
+++ b/src/testdir/test_terminal.vim
@@ -620,3 +620,40 @@ func Test_terminal_redir_file()
     call delete('Xfile')
   endif
 endfunc
+
+func TerminalTmap(remap)
+  let buf = Run_shell_in_terminal({})
+  call assert_equal('t', mode())
+
+  if a:remap
+    tmap 123 456
+  else
+    tnoremap 123 456
+  endif
+  tmap 456 abcde
+  call assert_equal('456', maparg('123', 't'))
+  call assert_equal('abcde', maparg('456', 't'))
+  call feedkeys("123", 'tx')
+  call term_wait(buf)
+  let lnum = term_getcursor(buf)[0]
+  if a:remap
+    call assert_match('abcde', term_getline(buf, lnum))
+  else
+    call assert_match('456', term_getline(buf, lnum))
+  endif
+
+  call term_sendkeys(buf, "\r")
+  call Stop_shell_in_terminal(buf)
+  call term_wait(buf)
+
+  tunmap 123
+  tunmap 456
+  call assert_equal('', maparg('123', 't'))
+  close
+  unlet g:job
+endfunc
+
+func Test_terminal_tmap()
+  call TerminalTmap(1)
+  call TerminalTmap(0)
+endfunc
--- 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 */
 /**/
+    1108,
+/**/
     1107,
 /**/
     1106,
--- a/src/vim.h
+++ b/src/vim.h
@@ -716,9 +716,10 @@ extern int (*dyn_libintl_putenv)(const c
 #define SHOWMATCH	(0x700 + INSERT) /* show matching paren */
 #define CONFIRM		0x800	/* ":confirm" prompt */
 #define SELECTMODE	0x1000	/* Select mode, only for mappings */
+#define TERMINAL        0x2000  /* Terminal mode */
 
-#define MAP_ALL_MODES	(0x3f | SELECTMODE)	/* all mode bits used for
-						 * mapping */
+/* all mode bits used for mapping */
+#define MAP_ALL_MODES	(0x3f | SELECTMODE | TERMINAL)
 
 /* directions */
 #define FORWARD			1