# HG changeset patch # User Christian Brabandt # Date 1505414705 -7200 # Node ID dfb8254aa73533a9a1fda18a78cc175bad000c52 # Parent bc590831aac529ace97e35b43e973dc7844ae167 patch 8.0.1108: cannot specify mappings for the terminal window commit https://github.com/vim/vim/commit/69fbc9e1dab176f345719436cd89d854df0a2abd Author: Bram Moolenaar 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) diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt --- 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 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 diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt --- 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 diff --git a/src/evalfunc.c b/src/evalfunc.c --- 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; } } diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h --- 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; diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- 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), diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- 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; diff --git a/src/getchar.c b/src/getchar.c --- 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; diff --git a/src/gui.c b/src/gui.c --- 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 diff --git a/src/main.c b/src/main.c --- 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 diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro --- 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); diff --git a/src/terminal.c b/src/terminal.c --- 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; diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/vim.h b/src/vim.h --- 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