Patch 8.2.4099
Problem:    Vim9: cannot use Vim9 syntax in mapping.
Solution:   Add <ScriptCmd> to use the script context for a command.
Files:      runtime/doc/map.txt, src/normal.c, src/getchar.c,
            src/proto/getchar.pro, src/ex_getln.c, src/edit.c, src/terminal.c,
            src/keymap.h, src/insexpand.c, src/misc2.c, src/ops.c,
            src/testdir/test_vim9_import.vim


*** ../vim-8.2.4098/runtime/doc/map.txt 2021-11-18 22:08:52.007682711 +0000
--- runtime/doc/map.txt 2022-01-15 18:13:21.243740342 +0000
***************
*** 335,358 ****
  Unlike <expr> mappings, there are no special restrictions on the <Cmd>
  command: it is executed as if an (unrestricted) |autocommand| 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.
  - The command is not echo'ed, no need for <silent>.
  - In Visual mode  you can use `line('v')` and `col('v')` to get one end of the
    Visual area, the cursor is at the other end.
  - 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*
--- 346,387 ----
  Unlike <expr> mappings, there are no special restrictions on the <Cmd>
  command: it is executed as if an (unrestricted) |autocommand| was invoked.
  
+                                               *<ScriptCmd>*
+ <ScriptCmd> is like <Cmd> but sets the context to the script the mapping was
+ defined in, for the duration of the command execution.  This is especially
+ useful for |Vim9| script.  It also works to access an import, which is useful
+ in a plugin using an autoload script: >
+       vim9script
+       import autoload 'implementation.vim' as impl
+       nnoremap <silent> <F4> <ScriptCmd>impl.DoTheWork()<CR>
+ 
+ No matter where <F4> is typed, the "impl" import will be found in the script
+ context of where the mapping was defined.  And since it's an autoload import,
+ the "implementation.vim" script will only be loaded once <F4> is typed, not
+ when the mapping is defined.
+ 
  Note:
! - Because <Cmd> and <ScriptCmd> avoid 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.
  - The command is not echo'ed, no need for <silent>.
+ - The {rhs} is not subject to abbreviations nor to other mappings, even if the
+   mapping is recursive.
  - In Visual mode  you can use `line('v')` and `col('v')` to get one end of the
    Visual area, the cursor is at the other end.
  - In Select mode, |:map| and |:vmap| command mappings are executed in
    Visual mode.  Use |:smap| to handle Select mode differently.
  
!                                                       *E1255* *E1136*
! <Cmd> and <ScriptCmd> 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> and <ScriptCmd> commands can have only normal characters and cannot
! contain special characters like function keys.
  
  
  1.3 MAPPING AND MODES                                 *:map-modes*
*** ../vim-8.2.4098/src/normal.c        2022-01-04 21:30:43.541800349 +0000
--- src/normal.c        2022-01-15 17:49:10.142598871 +0000
***************
*** 373,378 ****
--- 373,379 ----
      {K_CURSORHOLD, nv_cursorhold, NV_KEEPREG,         0},
      {K_PS,    nv_edit,        0,                      0},
      {K_COMMAND,       nv_colon,       0,                      0},
+     {K_SCRIPT_COMMAND, nv_colon, 0,                   0},
  };
  
  // Number of commands in nv_cmds[].
***************
*** 3429,3435 ****
  {
      int       old_p_im;
      int       cmd_result;
!     int       is_cmdkey = cap->cmdchar == K_COMMAND;
  
      if (VIsual_active && !is_cmdkey)
        nv_operator(cap);
--- 3430,3438 ----
  {
      int       old_p_im;
      int       cmd_result;
!     int       is_cmdkey = cap->cmdchar == K_COMMAND
!                                          || cap->cmdchar == K_SCRIPT_COMMAND;
!     int       flags;
  
      if (VIsual_active && !is_cmdkey)
        nv_operator(cap);
***************
*** 3459,3466 ****
        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
        if (p_im != old_p_im)
--- 3462,3472 ----
        old_p_im = p_im;
  
        // get a command line and execute it
!       flags = cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0;
!       if (is_cmdkey)
!           cmd_result = do_cmdkey_command(cap->cmdchar, flags);
!       else
!           cmd_result = do_cmdline(NULL, getexline, NULL, flags);
  
        // If 'insertmode' changed, enter or exit Insert mode
        if (p_im != old_p_im)
*** ../vim-8.2.4098/src/getchar.c       2022-01-11 11:58:14.920745981 +0000
--- src/getchar.c       2022-01-15 18:01:26.929136912 +0000
***************
*** 83,88 ****
--- 83,92 ----
  
  static int    last_recorded_len = 0;  // number of last recorded chars
  
+ #ifdef FEAT_EVAL
+ mapblock_T    *last_used_map = NULL;
+ #endif
+ 
  static int    read_readbuf(buffheader_T *buf, int advance);
  static void   init_typebuf(void);
  static void   may_sync_undo(void);
***************
*** 2893,2898 ****
--- 2897,2903 ----
  #ifdef FEAT_EVAL
            if (save_m_expr)
                vim_free(map_str);
+           last_used_map = mp;
  #endif
        }
  #ifdef FEAT_EVAL
***************
*** 3708,3714 ****
   * Function passed to do_cmdline() to get the command after a <Cmd> key from
   * typeahead.
   */
!     char_u *
  getcmdkeycmd(
        int             promptc UNUSED,
        void            *cookie UNUSED,
--- 3713,3719 ----
   * Function passed to do_cmdline() to get the command after a <Cmd> key from
   * typeahead.
   */
!     static char_u *
  getcmdkeycmd(
        int             promptc UNUSED,
        void            *cookie UNUSED,
***************
*** 3774,3780 ****
            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));
--- 3779,3785 ----
            c1 = NUL;  // end the line
        else if (c1 == ESC)
            aborted = TRUE;
!       else if (c1 == K_COMMAND || c1 == K_SCRIPT_COMMAND)
        {
            // give a nicer error message for this special case
            emsg(_(e_cmd_mapping_must_end_with_cr_before_second_cmd));
***************
*** 3804,3806 ****
--- 3809,3843 ----
  
      return (char_u *)line_ga.ga_data;
  }
+ 
+     int
+ do_cmdkey_command(int key, int flags)
+ {
+     int           res;
+ #ifdef FEAT_EVAL
+     sctx_T  save_current_sctx = {0, 0, 0, 0};
+ 
+     if (key == K_SCRIPT_COMMAND && last_used_map != NULL)
+     {
+       save_current_sctx = current_sctx;
+       current_sctx = last_used_map->m_script_ctx;
+     }
+ #endif
+ 
+     res = do_cmdline(NULL, getcmdkeycmd, NULL, flags);
+ 
+ #ifdef FEAT_EVAL
+     if (save_current_sctx.sc_sid > 0)
+       current_sctx = save_current_sctx;
+ #endif
+ 
+     return res;
+ }
+ 
+ #if defined(FEAT_EVAL) || defined(PROTO)
+     void
+ reset_last_used_map(void)
+ {
+     last_used_map = NULL;
+ }
+ #endif
*** ../vim-8.2.4098/src/proto/getchar.pro       2022-01-03 13:47:45.956911773 
+0000
--- src/proto/getchar.pro       2022-01-15 17:38:39.929473812 +0000
***************
*** 52,56 ****
  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 : */
--- 52,57 ----
  void vungetc(int c);
  int fix_input_buffer(char_u *buf, int len);
  int input_available(void);
! int do_cmdkey_command(int key, int flags);
! void reset_last_used_map(void);
  /* vim: set ft=c : */
*** ../vim-8.2.4098/src/ex_getln.c      2022-01-08 18:43:36.877446896 +0000
--- src/ex_getln.c      2022-01-15 17:03:45.661878223 +0000
***************
*** 1772,1782 ****
            c = safe_vgetc();
        } while (c == K_IGNORE || c == K_NOP);
  
!       if (c == K_COMMAND)
        {
            int     clen = ccline.cmdlen;
  
!           if (do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT) == OK)
            {
                if (clen == ccline.cmdlen)
                    trigger_cmdlinechanged = FALSE;
--- 1772,1782 ----
            c = safe_vgetc();
        } while (c == K_IGNORE || c == K_NOP);
  
!       if (c == K_COMMAND || c == K_SCRIPT_COMMAND)
        {
            int     clen = ccline.cmdlen;
  
!           if (do_cmdkey_command(c, DOCMD_NOWAIT) == OK)
            {
                if (clen == ccline.cmdlen)
                    trigger_cmdlinechanged = FALSE;
*** ../vim-8.2.4098/src/edit.c  2022-01-08 12:41:12.200795557 +0000
--- src/edit.c  2022-01-15 17:04:11.230100606 +0000
***************
*** 1055,1062 ****
        case K_IGNORE:  // Something mapped to nothing
            break;
  
!       case K_COMMAND:         // <Cmd>command<CR>
!           do_cmdline(NULL, getcmdkeycmd, NULL, 0);
  #ifdef FEAT_TERMINAL
            if (term_use_loop())
                // Started a terminal that gets the input, exit Insert mode.
--- 1055,1063 ----
        case K_IGNORE:  // Something mapped to nothing
            break;
  
!       case K_COMMAND:             // <Cmd>command<CR>
!       case K_SCRIPT_COMMAND:      // <ScriptCmd>command<CR>
!           do_cmdkey_command(c, 0);
  #ifdef FEAT_TERMINAL
            if (term_use_loop())
                // Started a terminal that gets the input, exit Insert mode.
*** ../vim-8.2.4098/src/terminal.c      2022-01-08 16:19:18.509639849 +0000
--- src/terminal.c      2022-01-15 17:05:16.346618503 +0000
***************
*** 2229,2235 ****
            break;
  
        case K_COMMAND:
!           return do_cmdline(NULL, getcmdkeycmd, NULL, 0);
      }
      if (typed)
        mouse_was_outside = FALSE;
--- 2229,2236 ----
            break;
  
        case K_COMMAND:
!       case K_SCRIPT_COMMAND:
!           return do_cmdkey_command(c, 0);
      }
      if (typed)
        mouse_was_outside = FALSE;
*** ../vim-8.2.4098/src/keymap.h        2021-06-08 19:13:27.359916592 +0100
--- src/keymap.h        2022-01-15 17:06:35.879166599 +0000
***************
*** 276,281 ****
--- 276,282 ----
      , KE_MOUSEMOVE_XY = 101   // KE_MOUSEMOVE with coordinates
      , KE_CANCEL = 102         // return from vgetc()
      , KE_COMMAND = 103                // <Cmd> special key
+     , KE_SCRIPT_COMMAND = 104 // <ScriptCmd> special key
  };
  
  /*
***************
*** 480,485 ****
--- 481,487 ----
  #define K_CURSORHOLD  TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD)
  
  #define K_COMMAND     TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
+ #define K_SCRIPT_COMMAND TERMCAP2KEY(KS_EXTRA, KE_SCRIPT_COMMAND)
  
  // Bits for modifier mask
  // 0x01 cannot be used, because the modifier must be 0x02 or higher
*** ../vim-8.2.4098/src/insexpand.c     2022-01-08 12:41:12.204795554 +0000
--- src/insexpand.c     2022-01-15 17:07:25.155465065 +0000
***************
*** 2281,2287 ****
  
      // 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
--- 2281,2288 ----
  
      // 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 || c == K_SCRIPT_COMMAND)
        return retval;
  
  #ifdef FEAT_PROP_POPUP
*** ../vim-8.2.4098/src/misc2.c 2022-01-08 12:41:12.208795550 +0000
--- src/misc2.c 2022-01-15 17:07:46.883587568 +0000
***************
*** 1057,1062 ****
--- 1057,1063 ----
      {K_CURSORHOLD,    (char_u *)"CursorHold"},
      {K_IGNORE,                (char_u *)"Ignore"},
      {K_COMMAND,               (char_u *)"Cmd"},
+     {K_SCRIPT_COMMAND,        (char_u *)"ScriptCmd"},
      {K_FOCUSGAINED,   (char_u *)"FocusGained"},
      {K_FOCUSLOST,     (char_u *)"FocusLost"},
      {0,                       NULL}
*** ../vim-8.2.4098/src/ops.c   2022-01-08 12:41:12.208795550 +0000
--- src/ops.c   2022-01-15 17:12:50.308841347 +0000
***************
*** 3501,3506 ****
--- 3501,3514 ----
      int               rv_arg;         // extra argument
  } redo_VIsual_T;
  
+     static int
+ is_ex_cmdchar(cmdarg_T *cap)
+ {
+     return cap->cmdchar == ':'
+       || cap->cmdchar == K_COMMAND
+       || cap->cmdchar == K_SCRIPT_COMMAND;
+ }
+ 
  /*
   * Handle an operator after Visual mode or when the movement is finished.
   * "gui_yank" is true when yanking text for the clipboard.
***************
*** 3583,3590 ****
                && ((!VIsual_active || oap->motion_force)
                    // Also redo Operator-pending Visual mode mappings
                    || (VIsual_active
!                         && (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND)
!                                                 && oap->op_type != OP_COLON))
                && cap->cmdchar != 'D'
  #ifdef FEAT_FOLDING
                && oap->op_type != OP_FOLD
--- 3591,3597 ----
                && ((!VIsual_active || oap->motion_force)
                    // Also redo Operator-pending Visual mode mappings
                    || (VIsual_active
!                           && is_ex_cmdchar(cap) && oap->op_type != OP_COLON))
                && cap->cmdchar != 'D'
  #ifdef FEAT_FOLDING
                && oap->op_type != OP_FOLD
***************
*** 3608,3614 ****
                    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
--- 3615,3621 ----
                    AppendToRedobuffLit(cap->searchbuf, -1);
                AppendToRedobuff(NL_STR);
            }
!           else if (is_ex_cmdchar(cap))
            {
                // do_cmdline() has stored the first typed line in
                // "repeat_cmdline".  When several lines are typed repeating
***************
*** 3806,3812 ****
                            get_op_char(oap->op_type),
                            get_extra_op_char(oap->op_type),
                            oap->motion_force, cap->cmdchar, cap->nchar);
!               else if (cap->cmdchar != ':' && cap->cmdchar != K_COMMAND)
                {
                    int opchar = get_op_char(oap->op_type);
                    int extra_opchar = get_extra_op_char(oap->op_type);
--- 3813,3819 ----
                            get_op_char(oap->op_type),
                            get_extra_op_char(oap->op_type),
                            oap->motion_force, cap->cmdchar, cap->nchar);
!               else if (!is_ex_cmdchar(cap))
                {
                    int opchar = get_op_char(oap->op_type);
                    int extra_opchar = get_extra_op_char(oap->op_type);
*** ../vim-8.2.4098/src/testdir/test_vim9_import.vim    2022-01-13 
22:05:05.567104513 +0000
--- src/testdir/test_vim9_import.vim    2022-01-15 18:05:59.736764583 +0000
***************
*** 1337,1342 ****
--- 1337,1345 ----
        export def Toggle(): string
          return ":g:toggle_called = 'yes'\<CR>"
        enddef
+       export def Doit()
+         g:doit_called = 'yes'
+       enddef
    END
    writefile(lines, 'Xdir/autoload/toggle.vim')
  
***************
*** 1346,1351 ****
--- 1349,1356 ----
        import autoload 'toggle.vim'
  
        nnoremap <silent> <expr> tt toggle.Toggle() 
+       nnoremap <silent> xx <ScriptCmd>toggle.Doit()<CR>
+       nnoremap <silent> yy <Cmd>toggle.Doit()<CR>
    END
    CheckScriptSuccess(lines)
    assert_false(exists("g:toggle_loaded"))
***************
*** 1355,1361 ****
--- 1360,1373 ----
    assert_equal('yes', g:toggle_loaded)
    assert_equal('yes', g:toggle_called)
  
+   feedkeys("xx", 'xt')
+   assert_equal('yes', g:doit_called)
+ 
+   assert_fails('call feedkeys("yy", "xt")', 'E121: Undefined variable: 
toggle')
+ 
    nunmap tt
+   nunmap xx
+   nunmap yy
    unlet g:toggle_loaded
    unlet g:toggle_called
    delete('Xdir', 'rf')
*** ../vim-8.2.4098/src/version.c       2022-01-15 15:23:40.911170017 +0000
--- src/version.c       2022-01-15 18:06:27.872728597 +0000
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4099,
  /**/

-- 
Veni, Vidi, Video -- I came, I saw, I taped what I saw.

 /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220115182630.98CED1C03C8%40moolenaar.net.

Reply via email to