<Cmd> is not highlighted in vimscript:

четверг, 12 ноября 2020 г. в 16:22:44 UTC+3, Bram Moolenaar: 

>
> Patch 8.2.1978
> Problem: Making a mapping work in all modes is complicated.
> Solution: Add the <Cmd> special key. (Yegappan Lakshmanan, closes #7282,
> closes 4784, based on patch by Bjorn Linse)
> Files: runtime/doc/autocmd.txt, runtime/doc/eval.txt,
> runtime/doc/map.txt, src/edit.c, src/errors.h, src/ex_docmd.c,
> src/ex_getln.c, src/getchar.c, src/insexpand.c, src/keymap.h,
> src/map.c, src/misc2.c, src/normal.c, src/ops.c,
> src/proto/getchar.pro, src/screen.c, src/terminal.c,
> src/testdir/test_mapping.vim
>
>
> *** ../vim-8.2.1977/runtime/doc/autocmd.txt 2020-10-21 12:19:50.080854732 
> +0200
> --- runtime/doc/autocmd.txt 2020-11-12 13:28:53.302992440 +0100
> ***************
> *** 551,562 ****
> *CmdlineEnter*
> CmdlineEnter After moving the cursor to the command line,
> where the user can type a command or search
> ! string.
> <afile> is set to a single character,
> indicating the type of command-line.
> |cmdwin-char|
> *CmdlineLeave*
> ! CmdlineLeave Before leaving the command line.
> Also when abandoning the command line, after
> typing CTRL-C or <Esc>.
> When the commands result in an error the
> --- 551,565 ----
> *CmdlineEnter*
> CmdlineEnter After moving the cursor to the command line,
> where the user can type a command or search
> ! string; including non-interactive use of ":"
> ! in a mapping, but not when using |<Cmd>|.
> <afile> is set to a single character,
> indicating the type of command-line.
> |cmdwin-char|
> *CmdlineLeave*
> ! CmdlineLeave Before leaving the command line; including
> ! non-interactive use of ":" in a mapping, but
> ! not when using |<Cmd>|.
> Also when abandoning the command line, after
> typing CTRL-C or <Esc>.
> When the commands result in an error the
> *** ../vim-8.2.1977/runtime/doc/eval.txt 2020-11-09 18:31:30.544791868 
> +0100
> --- runtime/doc/eval.txt 2020-11-12 13:23:14.947599257 +0100
> ***************
> *** 8592,8597 ****
> --- 8662,8668 ----
> the following mappings: >
> nnoremap <expr> GG ":echom ".screencol()."\n"
> nnoremap <silent> GG :echom screencol()<CR>
> + nnoremap GG <Cmd>echom screencol()<CR>
> <
> screenpos({winid}, {lnum}, {col}) *screenpos()*
> The result is a Dict with the screen position of the text
> *** ../vim-8.2.1977/runtime/doc/map.txt 2020-10-07 17:28:47.473370302 +0200
> --- runtime/doc/map.txt 2020-11-12 13:56:22.455089311 +0100
> ***************
> *** 254,260 ****
> - The |:normal| command.
> - Moving the cursor is allowed, but it is restored afterwards.
> If you want the mapping to do any of these let the returned characters do
> ! that.
>
> You can use getchar(), it consumes typeahead if there is any. E.g., if you
> have these mappings: >
> --- 271,277 ----
> - The |:normal| command.
> - Moving the cursor is allowed, but it is restored afterwards.
> If you want the mapping to do any of these let the returned characters do
> ! that, or use a |<Cmd>| mapping instead.
>
> You can use getchar(), it consumes typeahead if there is any. E.g., if you
> have these mappings: >
> ***************
> *** 283,297 ****
> CTRL-L inserts the next number, CTRL-R resets the count. CTRL-R returns an
> empty string, so that nothing is inserted.
>
> ! Note that there are some tricks to make special keys work and escape CSI 
> bytes
> ! in the text. The |:map| command also does this, thus you must avoid that 
> it
> ! is done twice. This does not work: >
> ! :imap <expr> <F3> "<Char-0x611B>"
> ! Because the <Char- sequence is escaped for being a |:imap| argument and 
> then
> ! again for using <expr>. This does work: >
> ! :imap <expr> <F3> "\u611B"
> ! Using 0x80 as a single byte before other text does not work, it will be 
> seen
> ! as a special key.
>
>
> 1.3 MAPPING AND MODES *:map-modes*
> --- 300,341 ----
> CTRL-L inserts the next number, CTRL-R resets the count. CTRL-R returns an
> empty string, so that nothing is inserted.
>
> ! Note that using 0x80 as a single byte before other text does not work, 
> it will
> ! be seen as a special key.
> ! 
> ! *<Cmd>* *:map-cmd*
> ! The special text <Cmd> begins a "command mapping", it executes the 
> command
> ! directly without changing modes. Where you might use ":...<CR>" in the
> ! {rhs} of a mapping, you can instead use "<Cmd>...<CR>".
> ! Example: >
> ! noremap x <Cmd>echo mode(1)<CR>
> ! <
> ! This is more flexible than `:<C-U>` in Visual and Operator-pending mode, 
> or
> ! `<C-O>:` in Insert mode, because the commands are executed directly in 
> the
> ! current mode, instead of always going to Normal mode. Visual mode is
> ! preserved, so tricks with |gv| are not needed. Commands can be invoked
> ! directly in Command-line mode (which would otherwise require timer 
> hacks).
> ! Example of using <Cmd> halfway Insert mode: >
> ! nnoremap <F3> aText <Cmd>echo mode(1)<CR> Added<Esc>
> ! 
> ! Unlike <expr> mappings, there are no special restrictions on the <Cmd>
> ! command: it is executed as if an (unrestricted) |autocmd| was invoked.
> ! 
> ! Note:
> ! - Because <Cmd> avoids mode-changes it does not trigger |CmdlineEnter| 
> and
> ! |CmdlineLeave| events, because no user interaction is expected.
> ! - For the same reason, |keycodes| like <C-R><C-W> are interpreted as 
> plain,
> ! unmapped keys.
> ! - In Select mode, |:map| and |:vmap| command mappings are executed in
> ! Visual mode. Use |:smap| to handle Select mode differently.
> ! 
> ! *E1135* *E1136*
> ! <Cmd> commands must terminate, that is, they must be followed by <CR> in 
> the
> ! {rhs} of the mapping definition. |Command-line| mode is never entered.
> ! 
> ! *E1137*
> ! <Cmd> commands can have only normal characters and cannot contain special
> ! characters like function keys.
>
>
> 1.3 MAPPING AND MODES *:map-modes*
> *** ../vim-8.2.1977/src/edit.c 2020-11-11 20:52:36.970181354 +0100
> --- src/edit.c 2020-11-12 13:56:56.759026220 +0100
> ***************
> *** 1031,1036 ****
> --- 1031,1040 ----
> case K_IGNORE: // Something mapped to nothing
> break;
>
> + case K_COMMAND: // <Cmd>command<CR>
> + do_cmdline(NULL, getcmdkeycmd, NULL, 0);
> + break;
> + 
> case K_CURSORHOLD: // Didn't type something for a while.
> ins_apply_autocmds(EVENT_CURSORHOLDI);
> did_cursorhold = TRUE;
> *** ../vim-8.2.1977/src/errors.h 2020-11-12 12:08:47.982254065 +0100
> --- src/errors.h 2020-11-12 13:59:27.146751553 +0100
> ***************
> *** 295,297 ****
> --- 295,303 ----
> EXTERN char e_using_string_as_bool_str[]
> INIT(= N_("E1135: Using a String as a Bool: \"%s\""));
> #endif
> + EXTERN char e_cmd_mapping_must_end_with_cr[]
> + INIT(=N_("E1135: <Cmd> mapping must end with <CR>"));
> + EXTERN char e_cmd_mapping_must_end_with_cr_before_second_cmd[]
> + INIT(=N_("E1136: <Cmd> mapping must end with <CR> before second <Cmd>"));
> + EXTERN char e_cmd_maping_must_not_include_str_key[]
> + INIT(= N_("E1137: <Cmd> mapping must not include %s key"));
> *** ../vim-8.2.1977/src/ex_docmd.c 2020-11-07 18:40:47.132725219 +0100
> --- src/ex_docmd.c 2020-11-12 13:23:14.955599247 +0100
> ***************
> *** 8148,8153 ****
> --- 8148,8156 ----
> restart_edit = 'i';
> curwin->w_curswant = 0; // avoid MAXCOL
> }
> + 
> + if (VIsual_active)
> + showmode();
> }
>
> /*
> *** ../vim-8.2.1977/src/ex_getln.c 2020-10-24 20:49:37.494683051 +0200
> --- src/ex_getln.c 2020-11-12 14:00:20.286655120 +0100
> ***************
> *** 1711,1716 ****
> --- 1711,1720 ----
> c = safe_vgetc();
> while (c == K_IGNORE || c == K_NOP);
>
> + if (c == K_COMMAND
> + && do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT) == OK)
> + goto cmdline_changed;
> + 
> if (KeyTyped)
> {
> some_key_typed = TRUE;
> *** ../vim-8.2.1977/src/getchar.c 2020-11-04 11:03:08.376891850 +0100
> --- src/getchar.c 2020-11-12 14:04:36.753604783 +0100
> ***************
> *** 3619,3621 ****
> --- 3619,3714 ----
> );
> }
> #endif
> + 
> + /*
> + * Function passed to do_cmdline() to get the command after a <Cmd> key 
> from
> + * typeahead.
> + */
> + char_u *
> + getcmdkeycmd(
> + int promptc UNUSED,
> + void *cookie UNUSED,
> + int indent UNUSED,
> + getline_opt_T do_concat UNUSED)
> + {
> + garray_T line_ga;
> + int c1 = -1;
> + int c2;
> + int cmod = 0;
> + int aborted = FALSE;
> + 
> + ga_init2(&line_ga, 1, 32);
> + 
> + // no mapping for these characters
> + no_mapping++;
> + 
> + got_int = FALSE;
> + while (c1 != NUL && !aborted)
> + {
> + ga_grow(&line_ga, 32);
> + 
> + if (vgetorpeek(FALSE) == NUL)
> + {
> + // incomplete <Cmd> is an error, because there is not much the user
> + // could do in this state.
> + emsg(_(e_cmd_mapping_must_end_with_cr));
> + aborted = TRUE;
> + break;
> + }
> + 
> + // Get one character at a time.
> + c1 = vgetorpeek(TRUE);
> + 
> + // Get two extra bytes for special keys
> + if (c1 == K_SPECIAL)
> + {
> + c1 = vgetorpeek(TRUE);
> + c2 = vgetorpeek(TRUE);
> + if (c1 == KS_MODIFIER)
> + {
> + cmod = c2;
> + continue;
> + }
> + c1 = TO_SPECIAL(c1, c2);
> + }
> + 
> + if (got_int)
> + aborted = TRUE;
> + else if (c1 == '\r' || c1 == '\n')
> + c1 = NUL; // end the line
> + else if (c1 == ESC)
> + aborted = TRUE;
> + else if (c1 == K_COMMAND)
> + {
> + // give a nicer error message for this special case
> + emsg(_(e_cmd_mapping_must_end_with_cr_before_second_cmd));
> + aborted = TRUE;
> + }
> + else if (IS_SPECIAL(c1))
> + {
> + if (c1 == K_SNR)
> + {
> + ga_append(&line_ga, (char)K_SPECIAL);
> + ga_append(&line_ga, (char)KS_EXTRA);
> + ga_append(&line_ga, (char)KE_SNR);
> + }
> + else
> + {
> + semsg(e_cmd_maping_must_not_include_str_key,
> + get_special_key_name(c1, cmod));
> + aborted = TRUE;
> + }
> + }
> + else
> + ga_append(&line_ga, (char)c1);
> + 
> + cmod = 0;
> + }
> + 
> + no_mapping--;
> + 
> + if (aborted)
> + ga_clear(&line_ga);
> + 
> + return (char_u *)line_ga.ga_data;
> + }
> *** ../vim-8.2.1977/src/insexpand.c 2020-10-28 20:19:56.372057081 +0100
> --- src/insexpand.c 2020-11-12 13:23:14.959599239 +0100
> ***************
> *** 1822,1828 ****
>
> // Ignore end of Select mode mapping and mouse scroll buttons.
> if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
> ! || c == K_MOUSELEFT || c == K_MOUSERIGHT)
> return retval;
>
> #ifdef FEAT_PROP_POPUP
> --- 1822,1828 ----
>
> // Ignore end of Select mode mapping and mouse scroll buttons.
> if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
> ! || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_COMMAND)
> return retval;
>
> #ifdef FEAT_PROP_POPUP
> *** ../vim-8.2.1977/src/keymap.h 2019-11-30 18:40:33.000000000 +0100
> --- src/keymap.h 2020-11-12 14:05:18.421372489 +0100
> ***************
> *** 274,279 ****
> --- 274,280 ----
> , KE_FOCUSLOST = 99 // focus lost
> , KE_MOUSEMOVE = 100 // mouse moved with no button down
> , KE_CANCEL = 101 // return from vgetc()
> + , KE_COMMAND = 102 // <Cmd> special key
> };
>
> /*
> ***************
> *** 449,459 ****
> #define K_RIGHTMOUSE TERMCAP2KEY(KS_EXTRA, KE_RIGHTMOUSE)
> #define K_RIGHTDRAG TERMCAP2KEY(KS_EXTRA, KE_RIGHTDRAG)
> #define K_RIGHTRELEASE TERMCAP2KEY(KS_EXTRA, KE_RIGHTRELEASE)
> ! #define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
> ! #define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
> #define K_X1DRAG TERMCAP2KEY(KS_EXTRA, KE_X1DRAG)
> #define K_X1RELEASE TERMCAP2KEY(KS_EXTRA, KE_X1RELEASE)
> ! #define K_X2MOUSE TERMCAP2KEY(KS_EXTRA, KE_X2MOUSE)
> #define K_X2DRAG TERMCAP2KEY(KS_EXTRA, KE_X2DRAG)
> #define K_X2RELEASE TERMCAP2KEY(KS_EXTRA, KE_X2RELEASE)
>
> --- 450,460 ----
> #define K_RIGHTMOUSE TERMCAP2KEY(KS_EXTRA, KE_RIGHTMOUSE)
> #define K_RIGHTDRAG TERMCAP2KEY(KS_EXTRA, KE_RIGHTDRAG)
> #define K_RIGHTRELEASE TERMCAP2KEY(KS_EXTRA, KE_RIGHTRELEASE)
> ! #define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
> ! #define K_X1MOUSE TERMCAP2KEY(KS_EXTRA, KE_X1MOUSE)
> #define K_X1DRAG TERMCAP2KEY(KS_EXTRA, KE_X1DRAG)
> #define K_X1RELEASE TERMCAP2KEY(KS_EXTRA, KE_X1RELEASE)
> ! #define K_X2MOUSE TERMCAP2KEY(KS_EXTRA, KE_X2MOUSE)
> #define K_X2DRAG TERMCAP2KEY(KS_EXTRA, KE_X2DRAG)
> #define K_X2RELEASE TERMCAP2KEY(KS_EXTRA, KE_X2RELEASE)
>
> ***************
> *** 477,482 ****
> --- 478,485 ----
>
> #define K_CURSORHOLD TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
>
> + #define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
> + 
> // Bits for modifier mask
> // 0x01 cannot be used, because the modifier must be 0x02 or higher
> #define MOD_MASK_SHIFT 0x02
> *** ../vim-8.2.1977/src/map.c 2020-10-01 21:37:17.798009505 +0200
> --- src/map.c 2020-11-12 13:23:14.963599234 +0100
> ***************
> *** 1639,1646 ****
> * Returns NULL when out of memory.
> */
> char_u *
> ! vim_strsave_escape_csi(
> ! char_u *p)
> {
> char_u *res;
> char_u *s, *d;
> --- 1639,1645 ----
> * Returns NULL when out of memory.
> */
> char_u *
> ! vim_strsave_escape_csi(char_u *p)
> {
> char_u *res;
> char_u *s, *d;
> *** ../vim-8.2.1977/src/misc2.c 2020-10-28 13:53:46.549128959 +0100
> --- src/misc2.c 2020-11-12 13:23:14.963599234 +0100
> ***************
> *** 2530,2535 ****
> --- 2530,2536 ----
> {K_PLUG, (char_u *)"Plug"},
> {K_CURSORHOLD, (char_u *)"CursorHold"},
> {K_IGNORE, (char_u *)"Ignore"},
> + {K_COMMAND, (char_u *)"Cmd"},
> {0, NULL}
> // NOTE: When adding a long name update MAX_KEY_NAME_LEN.
> };
> *** ../vim-8.2.1977/src/normal.c 2020-10-28 20:19:56.376057067 +0100
> --- src/normal.c 2020-11-12 13:23:14.967599227 +0100
> ***************
> *** 375,380 ****
> --- 375,381 ----
> #endif
> {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG, 0},
> {K_PS, nv_edit, 0, 0},
> + {K_COMMAND, nv_colon, 0, 0},
> };
>
> // Number of commands in nv_cmds[].
> ***************
> *** 3312,3321 ****
> static void
> nv_colon(cmdarg_T *cap)
> {
> ! int old_p_im;
> ! int cmd_result;
>
> ! if (VIsual_active)
> nv_operator(cap);
> else
> {
> --- 3313,3323 ----
> static void
> nv_colon(cmdarg_T *cap)
> {
> ! int old_p_im;
> ! int cmd_result;
> ! int is_cmdkey = cap->cmdchar == K_COMMAND;
>
> ! if (VIsual_active && !is_cmdkey)
> nv_operator(cap);
> else
> {
> ***************
> *** 3325,3331 ****
> cap->oap->motion_type = MCHAR;
> cap->oap->inclusive = FALSE;
> }
> ! else if (cap->count0)
> {
> // translate "count:" into ":.,.+(count - 1)"
> stuffcharReadbuff('.');
> --- 3327,3333 ----
> cap->oap->motion_type = MCHAR;
> cap->oap->inclusive = FALSE;
> }
> ! else if (cap->count0 && !is_cmdkey)
> {
> // translate "count:" into ":.,.+(count - 1)"
> stuffcharReadbuff('.');
> ***************
> *** 3343,3349 ****
> old_p_im = p_im;
>
> // get a command line and execute it
> ! cmd_result = do_cmdline(NULL, getexline, NULL,
> cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
>
> // If 'insertmode' changed, enter or exit Insert mode
> --- 3345,3351 ----
> old_p_im = p_im;
>
> // get a command line and execute it
> ! cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
> cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
>
> // If 'insertmode' changed, enter or exit Insert mode
> *** ../vim-8.2.1977/src/ops.c 2020-10-24 20:49:37.498683038 +0200
> --- src/ops.c 2020-11-12 13:23:14.967599227 +0100
> ***************
> *** 3490,3496 ****
> AppendToRedobuffLit(cap->searchbuf, -1);
> AppendToRedobuff(NL_STR);
> }
> ! else if (cap->cmdchar == ':')
> {
> // do_cmdline() has stored the first typed line in
> // "repeat_cmdline". When several lines are typed repeating
> --- 3490,3496 ----
> AppendToRedobuffLit(cap->searchbuf, -1);
> AppendToRedobuff(NL_STR);
> }
> ! else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND)
> {
> // do_cmdline() has stored the first typed line in
> // "repeat_cmdline". When several lines are typed repeating
> *** ../vim-8.2.1977/src/proto/getchar.pro 2020-06-06 22:36:20.464116743 
> +0200
> --- src/proto/getchar.pro 2020-11-12 14:05:48.405211967 +0100
> ***************
> *** 51,54 ****
> --- 51,55 ----
> void vungetc(int c);
> int fix_input_buffer(char_u *buf, int len);
> int input_available(void);
> + char_u *getcmdkeycmd(int promptc, void *cookie, int indent, 
> getline_opt_T do_concat);
> /* vim: set ft=c : */
> *** ../vim-8.2.1977/src/screen.c 2020-11-06 17:58:31.727138982 +0100
> --- src/screen.c 2020-11-12 13:23:14.971599222 +0100
> ***************
> *** 4192,4198 ****
> #endif
> msg_puts_attr(_(" INSERT"), attr);
> }
> ! else if (restart_edit == 'I' || restart_edit == 'A')
> msg_puts_attr(_(" (insert)"), attr);
> else if (restart_edit == 'R')
> msg_puts_attr(_(" (replace)"), attr);
> --- 4192,4199 ----
> #endif
> msg_puts_attr(_(" INSERT"), attr);
> }
> ! else if (restart_edit == 'I' || restart_edit == 'i' ||
> ! restart_edit == 'a' || restart_edit == 'A')
> msg_puts_attr(_(" (insert)"), attr);
> else if (restart_edit == 'R')
> msg_puts_attr(_(" (replace)"), attr);
> *** ../vim-8.2.1977/src/terminal.c 2020-11-06 17:58:31.727138982 +0100
> --- src/terminal.c 2020-11-12 13:23:14.975599214 +0100
> ***************
> *** 2180,2185 ****
> --- 2180,2189 ----
> return FAIL;
> }
> }
> + break;
> + 
> + case K_COMMAND:
> + return do_cmdline(NULL, getcmdkeycmd, NULL, 0);
> }
> if (typed)
> mouse_was_outside = FALSE;
> *** ../vim-8.2.1977/src/testdir/test_mapping.vim 2020-10-28 
> 20:19:56.376057067 +0100
> --- src/testdir/test_mapping.vim 2020-11-12 13:23:14.975599214 +0100
> ***************
> *** 3,8 ****
> --- 3,9 ----
> source shared.vim
> source check.vim
> source screendump.vim
> + source term_util.vim
>
> func Test_abbreviation()
> " abbreviation with 0x80 should work
> ***************
> *** 856,859 ****
> --- 857,1327 ----
> mapclear!
> endfunc
>
> + " Test for <Cmd> key in maps to execute commands
> + func Test_map_cmdkey()
> + new
> + 
> + " Error cases
> + let x = 0
> + noremap <F3> <Cmd><Cmd>let x = 1<CR>
> + call assert_fails('call feedkeys("\<F3>", "xt")', 'E1136:')
> + call assert_equal(0, x)
> + 
> + noremap <F3> <Cmd><F3>let x = 2<CR>
> + call assert_fails('call feedkeys("\<F3>", "xt")', 'E1137:')
> + call assert_equal(0, x)
> + 
> + noremap <F3> <Cmd>let x = 3
> + call assert_fails('call feedkeys("\<F3>", "xt!")', 'E1135:')
> + call assert_equal(0, x)
> + 
> + " works in various modes and sees the correct mode()
> + noremap <F3> <Cmd>let m = mode(1)<CR>
> + noremap! <F3> <Cmd>let m = mode(1)<CR>
> + 
> + " normal mode
> + call feedkeys("\<F3>", 'xt')
> + call assert_equal('n', m)
> + 
> + " visual mode
> + call feedkeys("v\<F3>", 'xt!')
> + call assert_equal('v', m)
> + " shouldn't leave the visual mode
> + call assert_equal('v', mode(1))
> + call feedkeys("\<Esc>", 'xt')
> + call assert_equal('n', mode(1))
> + 
> + " visual mapping in select mode
> + call feedkeys("gh\<F3>", 'xt!')
> + call assert_equal('v', m)
> + " shouldn't leave select mode
> + call assert_equal('s', mode(1))
> + call feedkeys("\<Esc>", 'xt')
> + call assert_equal('n', mode(1))
> + 
> + " select mode mapping
> + snoremap <F3> <Cmd>let m = mode(1)<cr>
> + call feedkeys("gh\<F3>", 'xt!')
> + call assert_equal('s', m)
> + " shouldn't leave select mode
> + call assert_equal('s', mode(1))
> + call feedkeys("\<Esc>", 'xt')
> + call assert_equal('n', mode(1))
> + 
> + " operator-pending mode
> + call feedkeys("d\<F3>", 'xt!')
> + call assert_equal('no', m)
> + " leaves the operator-pending mode
> + call assert_equal('n', mode(1))
> + 
> + " insert mode
> + call feedkeys("i\<F3>abc", 'xt')
> + call assert_equal('i', m)
> + call assert_equal('abc', getline('.'))
> + 
> + " replace mode
> + call feedkeys("0R\<F3>two", 'xt')
> + call assert_equal('R', m)
> + call assert_equal('two', getline('.'))
> + 
> + " virtual replace mode
> + call setline('.', "one\ttwo")
> + call feedkeys("4|gR\<F3>xxx", 'xt')
> + call assert_equal('Rv', m)
> + call assert_equal("onexxx\ttwo", getline('.'))
> + 
> + " cmdline mode
> + call feedkeys(":\<F3>\"xxx\<CR>", 'xt!')
> + call assert_equal('c', m)
> + call assert_equal('"xxx', @:)
> + 
> + " terminal mode
> + if CanRunVimInTerminal()
> + tnoremap <F3> <Cmd>let m = mode(1)<CR>
> + let buf = Run_shell_in_terminal({})
> + call feedkeys("\<F3>", 'xt')
> + call assert_equal('t', m)
> + call assert_equal('t', mode(1))
> + call StopShellInTerminal(buf)
> + call TermWait(buf)
> + close!
> + tunmap <F3>
> + endif
> + 
> + " invoke cmdline mode recursively
> + noremap! <F2> <Cmd>norm! :foo<CR>
> + %d
> + call setline(1, ['some short lines', 'of test text'])
> + call feedkeys(":bar\<F2>x\<C-B>\"\r", 'xt')
> + call assert_equal('"barx', @:)
> + unmap! <F2>
> + 
> + " test for calling a <SID> function
> + let lines =<< trim END
> + map <F2> <Cmd>call <SID>do_it()<CR>
> + func s:do_it()
> + let g:x = 32
> + endfunc
> + END
> + call writefile(lines, 'Xscript')
> + source Xscript
> + call feedkeys("\<F2>", 'xt')
> + call assert_equal(32, g:x)
> + call delete('Xscript')
> + 
> + unmap <F3>
> + unmap! <F3>
> + %bw!
> + endfunc
> + 
> + " text object enters visual mode
> + func TextObj()
> + if mode() !=# "v"
> + normal! v
> + end
> + call cursor(1, 3)
> + normal! o
> + call cursor(2, 4)
> + endfunc
> + 
> + func s:cmdmap(lhs, rhs)
> + exe 'noremap ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
> + exe 'noremap! ' .. a:lhs .. ' <Cmd>' .. a:rhs .. '<CR>'
> + endfunc
> + 
> + func s:cmdunmap(lhs)
> + exe 'unmap ' .. a:lhs
> + exe 'unmap! ' .. a:lhs
> + endfunc
> + 
> + " Map various <Fx> keys used by the <Cmd> key tests
> + func s:setupMaps()
> + call s:cmdmap('<F3>', 'let m = mode(1)')
> + call s:cmdmap('<F4>', 'normal! ww')
> + call s:cmdmap('<F5>', 'normal! "ay')
> + call s:cmdmap('<F6>', 'throw "very error"')
> + call s:cmdmap('<F7>', 'call TextObj()')
> + call s:cmdmap('<F8>', 'startinsert')
> + call s:cmdmap('<F9>', 'stopinsert')
> + endfunc
> + 
> + " Remove the mappings setup by setupMaps()
> + func s:cleanupMaps()
> + call s:cmdunmap('<F3>')
> + call s:cmdunmap('<F4>')
> + call s:cmdunmap('<F5>')
> + call s:cmdunmap('<F6>')
> + call s:cmdunmap('<F7>')
> + call s:cmdunmap('<F8>')
> + call s:cmdunmap('<F9>')
> + endfunc
> + 
> + " Test for <Cmd> mapping in normal mode
> + func Test_map_cmdkey_normal_mode()
> + new
> + call s:setupMaps()
> + 
> + " check v:count and v:register works
> + call s:cmdmap('<F2>', 'let s = [mode(1), v:count, v:register]')
> + call feedkeys("\<F2>", 'xt')
> + call assert_equal(['n', 0, '"'], s)
> + call feedkeys("7\<F2>", 'xt')
> + call assert_equal(['n', 7, '"'], s)
> + call feedkeys("\"e\<F2>", 'xt')
> + call assert_equal(['n', 0, 'e'], s)
> + call feedkeys("5\"k\<F2>", 'xt')
> + call assert_equal(['n', 5, 'k'], s)
> + call s:cmdunmap('<F2>')
> + 
> + call setline(1, ['some short lines', 'of test text'])
> + call feedkeys("\<F7>y", 'xt')
> + call assert_equal("me short lines\nof t", @")
> + call assert_equal('v', getregtype('"'))
> + call assert_equal([0, 1, 3, 0], getpos("'<"))
> + call assert_equal([0, 2, 4, 0], getpos("'>"))
> + 
> + " startinsert
> + %d
> + call feedkeys("\<F8>abc", 'xt')
> + call assert_equal('abc', getline(1))
> + 
> + " feedkeys are not executed immediately
> + noremap ,a <Cmd>call feedkeys("aalpha") \| let g:a = getline(2)<CR>
> + %d
> + call setline(1, ['some short lines', 'of test text'])
> + call cursor(2, 3)
> + call feedkeys(",a\<F3>", 'xt')
> + call assert_equal('of test text', g:a)
> + call assert_equal('n', m)
> + call assert_equal(['some short lines', 'of alphatest text'], getline(1, 
> '$'))
> + nunmap ,a
> + 
> + " feedkeys(..., 'x') is executed immediately, but insert mode is aborted
> + noremap ,b <Cmd>call feedkeys("abeta", 'x') \| let g:b = getline(2)<CR>
> + call feedkeys(",b\<F3>", 'xt')
> + call assert_equal('n', m)
> + call assert_equal('of alphabetatest text', g:b)
> + nunmap ,b
> + 
> + call s:cleanupMaps()
> + %bw!
> + endfunc
> + 
> + " Test for <Cmd> mapping with the :normal command
> + func Test_map_cmdkey_normal_cmd()
> + new
> + noremap ,x <Cmd>call append(1, "xx") \| call append(1, "aa")<CR>
> + noremap ,f <Cmd>nosuchcommand<CR>
> + noremap ,e <Cmd>throw "very error" \| call append(1, "yy")<CR>
> + noremap ,m <Cmd>echoerr "The message." \| call append(1, "zz")<CR>
> + noremap ,w <Cmd>for i in range(5) \| if i==1 \| echoerr "Err" \| endif 
> \| call append(1, i) \| endfor<CR>
> + 
> + call setline(1, ['some short lines', 'of test text'])
> + exe "norm ,x\r"
> + call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], 
> getline(1, '$'))
> + 
> + call assert_fails('norm ,f', 'E492:')
> + call assert_fails('norm ,e', 'very error')
> + call assert_fails('norm ,m', 'The message.')
> + call assert_equal(['some short lines', 'aa', 'xx', 'of test text'], 
> getline(1, '$'))
> + 
> + %d
> + let caught_err = 0
> + try
> + exe "normal ,w"
> + catch /Vim(echoerr):Err/
> + let caught_err = 1
> + endtry
> + call assert_equal(1, caught_err)
> + call assert_equal(['', '0'], getline(1, '$'))
> + 
> + %d
> + call assert_fails('normal ,w', 'Err')
> + call assert_equal(['', '4', '3', '2' ,'1', '0'], getline(1, '$'))
> + call assert_equal(1, line('.'))
> + 
> + nunmap ,x
> + nunmap ,f
> + nunmap ,e
> + nunmap ,m
> + nunmap ,w
> + %bw!
> + endfunc
> + 
> + " Test for <Cmd> mapping in visual mode
> + func Test_map_cmdkey_visual_mode()
> + new
> + set showmode
> + call s:setupMaps()
> + 
> + call setline(1, ['some short lines', 'of test text'])
> + call feedkeys("v\<F4>", 'xt!')
> + call assert_equal(['v', 1, 12], [mode(1), col('v'), col('.')])
> + 
> + " can invoke an opeartor, ending the visual mode
> + let @a = ''
> + call feedkeys("\<F5>", 'xt!')
> + call assert_equal('n', mode(1))
> + call assert_equal('some short l', @a)
> + 
> + " error doesn't interrupt visual mode
> + call assert_fails('call feedkeys("ggvw\<F6>", "xt!")', 'E605:')
> + call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
> + call feedkeys("\<F7>", 'xt!')
> + call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), 
> line('.'), col('.')])
> + 
> + " startinsert gives "-- (insert) VISUAL --" mode
> + call feedkeys("\<F8>", 'xt!')
> + call assert_equal(['v', 1, 3, 2, 4], [mode(1), line('v'), col('v'), 
> line('.'), col('.')])
> + redraw!
> + call assert_match('^-- (insert) VISUAL --', Screenline(&lines))
> + call feedkeys("\<Esc>new ", 'x')
> + call assert_equal(['some short lines', 'of new test text'], getline(1, 
> '$'))
> + 
> + call s:cleanupMaps()
> + set showmode&
> + %bw!
> + endfunc
> + 
> + " Test for <Cmd> mapping in select mode
> + func Test_map_cmdkey_select_mode()
> + new
> + set showmode
> + call s:setupMaps()
> + 
> + snoremap <F1> <cmd>throw "very error"<CR>
> + snoremap <F2> <cmd>normal! <c-g>"by<CR>
> + call setline(1, ['some short lines', 'of test text'])
> + 
> + call feedkeys("gh\<F4>", "xt!")
> + call assert_equal(['s', 1, 12], [mode(1), col('v'), col('.')])
> + redraw!
> + call assert_match('^-- SELECT --', Screenline(&lines))
> + 
> + " visual mapping in select mode restarts select mode after operator
> + let @a = ''
> + call feedkeys("\<F5>", 'xt!')
> + call assert_equal('s', mode(1))
> + call assert_equal('some short l', @a)
> + 
> + " select mode mapping works, and does not restart select mode
> + let @b = ''
> + call feedkeys("\<F2>", 'xt!')
> + call assert_equal('n', mode(1))
> + call assert_equal('some short l', @b)
> + 
> + " error doesn't interrupt temporary visual mode
> + call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F6>", "xt!")', 
> 'E605:')
> + redraw!
> + call assert_match('^-- VISUAL --', Screenline(&lines))
> + " quirk: restoration of select mode is not performed
> + call assert_equal(['v', 1, 6], [mode(1), col('v'), col('.')])
> + 
> + " error doesn't interrupt select mode
> + call assert_fails('call feedkeys("\<Esc>ggvw\<C-G>\<F1>", "xt!")', 
> 'E605:')
> + redraw!
> + call assert_match('^-- SELECT --', Screenline(&lines))
> + call assert_equal(['s', 1, 6], [mode(1), col('v'), col('.')])
> + 
> + call feedkeys("\<F7>", 'xt!')
> + redraw!
> + call assert_match('^-- SELECT --', Screenline(&lines))
> + call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), 
> line('.'), col('.')])
> + 
> + " startinsert gives "-- SELECT (insert) --" mode
> + call feedkeys("\<F8>", 'xt!')
> + redraw!
> + call assert_match('^-- (insert) SELECT --', Screenline(&lines))
> + call assert_equal(['s', 1, 3, 2, 4], [mode(1), line('v'), col('v'), 
> line('.'), col('.')])
> + call feedkeys("\<Esc>new ", 'x')
> + call assert_equal(['some short lines', 'of new test text'], getline(1, 
> '$'))
> + 
> + sunmap <F1>
> + sunmap <F2>
> + call s:cleanupMaps()
> + set showmode&
> + %bw!
> + endfunc
> + 
> + " Test for <Cmd> mapping in operator-pending mode
> + func Test_map_cmdkey_op_pending_mode()
> + new
> + call s:setupMaps()
> + 
> + call setline(1, ['some short lines', 'of test text'])
> + call feedkeys("d\<F4>", 'xt')
> + call assert_equal(['lines', 'of test text'], getline(1, '$'))
> + call assert_equal(['some short '], getreg('"', 1, 1))
> + " create a new undo point
> + let &undolevels = &undolevels
> + 
> + call feedkeys(".", 'xt')
> + call assert_equal(['test text'], getline(1, '$'))
> + call assert_equal(['lines', 'of '], getreg('"', 1, 1))
> + " create a new undo point
> + let &undolevels = &undolevels
> + 
> + call feedkeys("uu", 'xt')
> + call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
> + 
> + " error aborts operator-pending, operator not performed
> + call assert_fails('call feedkeys("d\<F6>", "xt")', 'E605:')
> + call assert_equal(['some short lines', 'of test text'], getline(1, '$'))
> + 
> + call feedkeys("\"bd\<F7>", 'xt')
> + call assert_equal(['soest text'], getline(1, '$'))
> + call assert_equal(['me short lines', 'of t'], getreg('b', 1, 1))
> + 
> + " startinsert aborts operator
> + call feedkeys("d\<F8>cc", 'xt')
> + call assert_equal(['soccest text'], getline(1, '$'))
> + 
> + call s:cleanupMaps()
> + %bw!
> + endfunc
> + 
> + " Test for <Cmd> mapping in insert mode
> + func Test_map_cmdkey_insert_mode()
> + new
> + call s:setupMaps()
> + 
> + call setline(1, ['some short lines', 'of test text'])
> + " works the same as <C-O>w<C-O>w
> + call feedkeys("iindeed \<F4>little ", 'xt')
> + call assert_equal(['indeed some short little lines', 'of test text'], 
> getline(1, '$'))
> + call assert_fails('call feedkeys("i\<F6> 2", "xt")', 'E605:')
> + call assert_equal(['indeed some short little 2 lines', 'of test text'], 
> getline(1, '$'))
> + 
> + " Note when entering visual mode from InsertEnter autocmd, an async 
> event,
> + " or a <Cmd> mapping, vim ends up in undocumented "INSERT VISUAL" mode.
> + call feedkeys("i\<F7>stuff ", 'xt')
> + call assert_equal(['indeed some short little 2 lines', 'of stuff test 
> text'], getline(1, '$'))
> + call assert_equal(['v', 1, 3, 2, 9], [mode(1), line('v'), col('v'), 
> line('.'), col('.')])
> + 
> + call feedkeys("\<F5>", 'xt')
> + call assert_equal(['deed some short little 2 lines', 'of stuff '], 
> getreg('a', 1, 1))
> + 
> + " also works as part of abbreviation
> + abbr foo <Cmd>let g:y = 17<CR>bar
> + exe "normal i\<space>foo "
> + call assert_equal(17, g:y)
> + call assert_equal('in bar deed some short little 2 lines', getline(1))
> + unabbr foo
> + 
> + " :startinsert does nothing
> + call setline(1, 'foo bar')
> + call feedkeys("ggi\<F8>vim", 'xt')
> + call assert_equal('vimfoo bar', getline(1))
> + 
> + " :stopinsert works
> + call feedkeys("ggi\<F9>Abc", 'xt')
> + call assert_equal('vimfoo barbc', getline(1))
> + 
> + call s:cleanupMaps()
> + %bw!
> + endfunc
> + 
> + " Test for <Cmd> mapping in insert-completion mode
> + func Test_map_cmdkey_insert_complete_mode()
> + new
> + call s:setupMaps()
> + 
> + call setline(1, 'some short lines')
> + call feedkeys("os\<C-X>\<C-N>\<F3>\<C-N> ", 'xt')
> + call assert_equal('ic', m)
> + call assert_equal(['some short lines', 'short '], getline(1, '$'))
> + 
> + call s:cleanupMaps()
> + %bw!
> + endfunc
> + 
> + " Test for <Cmd> mapping in cmdline mode
> + func Test_map_cmdkey_cmdline_mode()
> + new
> + call s:setupMaps()
> + 
> + call setline(1, ['some short lines', 'of test text'])
> + let x = 0
> + call feedkeys(":let x\<F3>= 10\r", 'xt')
> + call assert_equal('c', m)
> + call assert_equal(10, x)
> + 
> + " exception doesn't leave cmdline mode
> + call assert_fails('call feedkeys(":let x\<F6>= 20\r", "xt")', 'E605:')
> + call assert_equal(20, x)
> + 
> + " move cursor in the buffer from cmdline mode
> + call feedkeys(":let x\<F4>= 30\r", 'xt')
> + call assert_equal(30, x)
> + call assert_equal(12, col('.'))
> + 
> + " :startinsert takes effect after leaving cmdline mode
> + call feedkeys(":let x\<F8>= 40\rnew ", 'xt')
> + call assert_equal(40, x)
> + call assert_equal('some short new lines', getline(1))
> + 
> + call s:cleanupMaps()
> + %bw!
> + endfunc
> + 
> " vim: shiftwidth=2 sts=2 expandtab
> *** ../vim-8.2.1977/src/version.c 2020-11-12 12:08:47.986254110 +0100
> --- src/version.c 2020-11-12 13:26:21.555313427 +0100
> ***************
> *** 752,753 ****
> --- 752,755 ----
> { /* Add new patch number below this line */
> + /**/
> + 1978,
> /**/
>
> -- 
> hundred-and-one symptoms of being an internet addict:
> 238. You think faxes are old-fashioned.
>
> /// Bram Moolenaar -- [email protected] -- 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 ///
>

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/e6f146d7-b6cf-4a63-82a7-a16f55a3121cn%40googlegroups.com.

Raspunde prin e-mail lui