Patch 8.2.4221
Problem:    Some functions in normal.c are very long.
Solution:   Move code to separate functions. (Yegappan Lakshmanan,
            closes #9628)
Files:      src/normal.c


*** ../vim-8.2.4220/src/normal.c        2022-01-24 16:30:26.564796202 +0000
--- src/normal.c        2022-01-26 12:11:01.174012265 +0000
***************
*** 627,634 ****
   * Return the updated command index (if changed).
   */
      static int
! normal_cmd_get_more_chars(int idx, cmdarg_T *cap, int *need_flushbuf UNUSED)
  {
      int               c;
      int               *cp;
      int               repl = FALSE;   // get character for replace mode
--- 627,638 ----
   * Return the updated command index (if changed).
   */
      static int
! normal_cmd_get_more_chars(
!       int         idx_arg,
!       cmdarg_T    *cap,
!       int         *need_flushbuf UNUSED)
  {
+     int               idx = idx_arg;
      int               c;
      int               *cp;
      int               repl = FALSE;   // get character for replace mode
***************
*** 779,788 ****
  #endif
        }
  
!       /*
!        * When the next character is CTRL-\ a following CTRL-N means the
!        * command is aborted and we go to Normal mode.
!        */
        if (cp == &cap->extra_char
                && cap->nchar == Ctrl_BSL
                && (cap->extra_char == Ctrl_N || cap->extra_char == Ctrl_G))
--- 783,790 ----
  #endif
        }
  
!       // When the next character is CTRL-\ a following CTRL-N means the
!       // command is aborted and we go to Normal mode.
        if (cp == &cap->extra_char
                && cap->nchar == Ctrl_BSL
                && (cap->extra_char == Ctrl_N || cap->extra_char == Ctrl_G))
***************
*** 854,869 ****
      static int
  normal_cmd_need_to_wait_for_msg(cmdarg_T *cap, pos_T *old_pos)
  {
!     /*
!      * In Visual mode and with "^O" in Insert mode, a short message will be
!      * overwritten by the mode message.  Wait a bit, until a key is hit.
!      * In Visual mode, it's more important to keep the Visual area updated
!      * than keeping a message (e.g. from a /pat search).
!      * Only do this if the command was typed, not from a mapping.
!      * Don't wait when emsg_silent is non-zero.
!      * Also wait a bit after an error message, e.g. for "^O:".
!      * Don't redraw the screen, it would remove the message.
!      */
      return (       ((p_smd
                    && msg_silent == 0
                    && (restart_edit != 0
--- 856,869 ----
      static int
  normal_cmd_need_to_wait_for_msg(cmdarg_T *cap, pos_T *old_pos)
  {
!     // In Visual mode and with "^O" in Insert mode, a short message will be
!     // overwritten by the mode message.  Wait a bit, until a key is hit.
!     // In Visual mode, it's more important to keep the Visual area updated
!     // than keeping a message (e.g. from a /pat search).
!     // Only do this if the command was typed, not from a mapping.
!     // Don't wait when emsg_silent is non-zero.
!     // Also wait a bit after an error message, e.g. for "^O:".
!     // Don't redraw the screen, it would remove the message.
      return (       ((p_smd
                    && msg_silent == 0
                    && (restart_edit != 0
***************
*** 968,978 ****
      // remembered in "opcount".
      ca.opcount = opcount;
  
!     /*
!      * If there is an operator pending, then the command we take this time
!      * will terminate it. Finish_op tells us to finish the operation before
!      * returning this time (unless the operation was cancelled).
!      */
  #ifdef CURSOR_SHAPE
      c = finish_op;
  #endif
--- 968,976 ----
      // remembered in "opcount".
      ca.opcount = opcount;
  
!     // If there is an operator pending, then the command we take this time
!     // will terminate it. Finish_op tells us to finish the operation before
!     // returning this time (unless the operation was cancelled).
  #ifdef CURSOR_SHAPE
      c = finish_op;
  #endif
***************
*** 1030,1040 ****
      c = safe_vgetc();
      LANGMAP_ADJUST(c, get_real_state() != SELECTMODE);
  
!     /*
!      * If a mapping was started in Visual or Select mode, remember the length
!      * of the mapping.  This is used below to not return to Insert mode for as
!      * long as the mapping is being executed.
!      */
      if (restart_edit == 0)
        old_mapped_len = 0;
      else if (old_mapped_len
--- 1028,1036 ----
      c = safe_vgetc();
      LANGMAP_ADJUST(c, get_real_state() != SELECTMODE);
  
!     // If a mapping was started in Visual or Select mode, remember the length
!     // of the mapping.  This is used below to not return to Insert mode for as
!     // long as the mapping is being executed.
      if (restart_edit == 0)
        old_mapped_len = 0;
      else if (old_mapped_len
***************
*** 1044,1052 ****
      if (c == NUL)
        c = K_ZERO;
  
!     /*
!      * In Select mode, typed text replaces the selection.
!      */
      if (VIsual_active
            && VIsual_select
            && (vim_isprintc(c) || c == NL || c == CAR || c == K_KENTER))
--- 1040,1046 ----
      if (c == NUL)
        c = K_ZERO;
  
!     // In Select mode, typed text replaces the selection.
      if (VIsual_active
            && VIsual_select
            && (vim_isprintc(c) || c == NL || c == CAR || c == K_KENTER))
***************
*** 1085,1094 ****
      c = normal_cmd_get_count(&ca, c, toplevel, set_prevcount, &ctrl_w,
                                                        &need_flushbuf);
  
!     /*
!      * Find the command character in the table of commands.
!      * For CTRL-W we already got nchar when looking for a count.
!      */
      if (ctrl_w)
      {
        ca.nchar = c;
--- 1079,1086 ----
      c = normal_cmd_get_count(&ca, c, toplevel, set_prevcount, &ctrl_w,
                                                        &need_flushbuf);
  
!     // Find the command character in the table of commands.
!     // For CTRL-W we already got nchar when looking for a count.
      if (ctrl_w)
      {
        ca.nchar = c;
***************
*** 1114,1122 ****
      if ((nv_cmds[idx].cmd_flags & NV_NCW) && curbuf_locked())
        goto normal_end;
  
!     /*
!      * In Visual/Select mode, a few keys are handled in a special way.
!      */
      if (VIsual_active)
      {
        // when 'keymodel' contains "stopsel" may stop Select/Visual mode
--- 1106,1112 ----
      if ((nv_cmds[idx].cmd_flags & NV_NCW) && curbuf_locked())
        goto normal_end;
  
!     // In Visual/Select mode, a few keys are handled in a special way.
      if (VIsual_active)
      {
        // when 'keymodel' contains "stopsel" may stop Select/Visual mode
***************
*** 1177,1188 ****
        idx = normal_cmd_get_more_chars(idx, &ca, &need_flushbuf);
  
  #ifdef FEAT_CMDL_INFO
!     /*
!      * Flush the showcmd characters onto the screen so we can see them while
!      * the command is being executed.  Only do this when the shown command was
!      * actually displayed, otherwise this will slow down a lot when executing
!      * mappings.
!      */
      if (need_flushbuf)
        out_flush();
  #endif
--- 1167,1176 ----
        idx = normal_cmd_get_more_chars(idx, &ca, &need_flushbuf);
  
  #ifdef FEAT_CMDL_INFO
!     // Flush the showcmd characters onto the screen so we can see them while
!     // the command is being executed.  Only do this when the shown command was
!     // actually displayed, otherwise this will slow down a lot when executing
!     // mappings.
      if (need_flushbuf)
        out_flush();
  #endif
***************
*** 1230,1246 ****
        }
      }
  
!     /*
!      * Execute the command!
!      * Call the command function found in the commands table.
!      */
      ca.arg = nv_cmds[idx].cmd_arg;
      (nv_cmds[idx].cmd_func)(&ca);
  
!     /*
!      * If we didn't start or finish an operator, reset oap->regname, unless we
!      * need it later.
!      */
      if (!finish_op
            && !oap->op_type
            && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG)))
--- 1218,1230 ----
        }
      }
  
!     // Execute the command!
!     // Call the command function found in the commands table.
      ca.arg = nv_cmds[idx].cmd_arg;
      (nv_cmds[idx].cmd_func)(&ca);
  
!     // If we didn't start or finish an operator, reset oap->regname, unless we
!     // need it later.
      if (!finish_op
            && !oap->op_type
            && (idx < 0 || !(nv_cmds[idx].cmd_flags & NV_KEEPREG)))
***************
*** 1256,1265 ****
      if (old_mapped_len > 0)
        old_mapped_len = typebuf_maplen();
  
!     /*
!      * If an operation is pending, handle it.  But not for K_IGNORE or
!      * K_MOUSEMOVE.
!      */
      if (ca.cmdchar != K_IGNORE && ca.cmdchar != K_MOUSEMOVE)
        do_pending_operator(&ca, old_col, FALSE);
  
--- 1240,1247 ----
      if (old_mapped_len > 0)
        old_mapped_len = typebuf_maplen();
  
!     // If an operation is pending, handle it.  But not for K_IGNORE or
!     // K_MOUSEMOVE.
      if (ca.cmdchar != K_IGNORE && ca.cmdchar != K_MOUSEMOVE)
        do_pending_operator(&ca, old_col, FALSE);
  
***************
*** 1268,1356 ****
      if (normal_cmd_need_to_wait_for_msg(&ca, &old_pos))
        normal_cmd_wait_for_msg();
  
!     /*
!      * Wait for a moment when a message is displayed that will be overwritten
!      * by the mode message.
!      * In Visual mode and with "^O" in Insert mode, a short message will be
!      * overwritten by the mode message.  Wait a bit, until a key is hit.
!      * In Visual mode, it's more important to keep the Visual area updated
!      * than keeping a message (e.g. from a /pat search).
!      * Only do this if the command was typed, not from a mapping.
!      * Don't wait when emsg_silent is non-zero.
!      * Also wait a bit after an error message, e.g. for "^O:".
!      * Don't redraw the screen, it would remove the message.
!      */
!     if (       ((p_smd
!                   && msg_silent == 0
!                   && (restart_edit != 0
!                       || (VIsual_active
!                           && old_pos.lnum == curwin->w_cursor.lnum
!                           && old_pos.col == curwin->w_cursor.col)
!                      )
!                   && (clear_cmdline
!                       || redraw_cmdline)
!                   && (msg_didout || (msg_didany && msg_scroll))
!                   && !msg_nowait
!                   && KeyTyped)
!               || (restart_edit != 0
!                   && !VIsual_active
!                   && (msg_scroll
!                       || emsg_on_display)))
!           && oap->regname == 0
!           && !(ca.retval & CA_COMMAND_BUSY)
!           && stuff_empty()
!           && typebuf_typed()
!           && emsg_silent == 0
!           && !in_assert_fails
!           && !did_wait_return
!           && oap->op_type == OP_NOP)
!     {
!       int     save_State = State;
! 
!       // Draw the cursor with the right shape here
!       if (restart_edit != 0)
!           State = INSERT;
! 
!       // If need to redraw, and there is a "keep_msg", redraw before the
!       // delay
!       if (must_redraw && keep_msg != NULL && !emsg_on_display)
!       {
!           char_u      *kmsg;
! 
!           kmsg = keep_msg;
!           keep_msg = NULL;
!           // Showmode() will clear keep_msg, but we want to use it anyway.
!           // First update w_topline.
!           setcursor();
!           update_screen(0);
!           // now reset it, otherwise it's put in the history again
!           keep_msg = kmsg;
! 
!           kmsg = vim_strsave(keep_msg);
!           if (kmsg != NULL)
!           {
!               msg_attr((char *)kmsg, keep_msg_attr);
!               vim_free(kmsg);
!           }
!       }
!       setcursor();
! #ifdef CURSOR_SHAPE
!       ui_cursor_shape();              // may show different cursor shape
! #endif
!       cursor_on();
!       out_flush();
!       if (msg_scroll || emsg_on_display)
!           ui_delay(1003L, TRUE);      // wait at least one second
!       ui_delay(3003L, FALSE);         // wait up to three seconds
!       State = save_State;
! 
!       msg_scroll = FALSE;
!       emsg_on_display = FALSE;
!     }
! 
!     /*
!      * Finish up after executing a Normal mode command.
!      */
  normal_end:
  
      msg_nowait = FALSE;
--- 1250,1256 ----
      if (normal_cmd_need_to_wait_for_msg(&ca, &old_pos))
        normal_cmd_wait_for_msg();
  
!     // Finish up after executing a Normal mode command.
  normal_end:
  
      msg_nowait = FALSE;
***************
*** 1408,1418 ****
        restart_edit = 0;
  #endif
  
!     /*
!      * May restart edit(), if we got here with CTRL-O in Insert mode (but not
!      * if still inside a mapping that started in Visual mode).
!      * May switch from Visual to Select mode after CTRL-O command.
!      */
      if (       oap->op_type == OP_NOP
            && ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0)
                || restart_VIsual_select == 1)
--- 1308,1316 ----
        restart_edit = 0;
  #endif
  
!     // May restart edit(), if we got here with CTRL-O in Insert mode (but not
!     // if still inside a mapping that started in Visual mode).
!     // May switch from Visual to Select mode after CTRL-O command.
      if (       oap->op_type == OP_NOP
            && ((restart_edit != 0 && !VIsual_active && old_mapped_len == 0)
                || restart_VIsual_select == 1)
***************
*** 1510,1521 ****
  end_visual_mode_keep_button()
  {
  #ifdef FEAT_CLIPBOARD
!     /*
!      * If we are using the clipboard, then remember what was selected in case
!      * we need to paste it somewhere while we still own the selection.
!      * Only do this when the clipboard is already owned.  Don't want to grab
!      * the selection when hitting ESC.
!      */
      if (clip_star.available && clip_star.owned)
        clip_auto_select();
  
--- 1408,1417 ----
  end_visual_mode_keep_button()
  {
  #ifdef FEAT_CLIPBOARD
!     // If we are using the clipboard, then remember what was selected in case
!     // we need to paste it somewhere while we still own the selection.
!     // Only do this when the clipboard is already owned.  Don't want to grab
!     // the selection when hitting ESC.
      if (clip_star.available && clip_star.owned)
        clip_auto_select();
  
***************
*** 1678,1687 ****
      int               prevcol;
      int               bn = 0;         // bracket nesting
  
!     /*
!      * if i == 0: try to find an identifier
!      * if i == 1: try to find any non-white text
!      */
      ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
      for (i = (find_type & FIND_IDENT) ? 0 : 1;        i < 2; ++i)
      {
--- 1574,1581 ----
      int               prevcol;
      int               bn = 0;         // bracket nesting
  
!     // if i == 0: try to find an identifier
!     // if i == 1: try to find any non-white text
      ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
      for (i = (find_type & FIND_IDENT) ? 0 : 1;        i < 2; ++i)
      {
***************
*** 2200,2209 ****
        showcmd_is_clear = FALSE;
      }
  
!     /*
!      * clear the rest of an old message by outputting up to SHOWCMD_COLS
!      * spaces
!      */
      screen_puts((char_u *)"          " + len, (int)Rows - 1, sc_col + len, 0);
  
      setcursor();          // put cursor back where it belongs
--- 2094,2101 ----
        showcmd_is_clear = FALSE;
      }
  
!     // clear the rest of an old message by outputting up to SHOWCMD_COLS
!     // spaces
      screen_puts((char_u *)"          " + len, (int)Rows - 1, sc_col + len, 0);
  
      setcursor();          // put cursor back where it belongs
***************
*** 2234,2244 ****
            did_syncbind = FALSE;
        else if (curwin == old_curwin)
        {
!           /*
!            * Synchronize other windows, as necessary according to
!            * 'scrollbind'.  Don't do this after an ":edit" command, except
!            * when 'diff' is set.
!            */
            if ((curwin->w_buffer == old_buf
  #ifdef FEAT_DIFF
                        || curwin->w_p_diff
--- 2126,2134 ----
            did_syncbind = FALSE;
        else if (curwin == old_curwin)
        {
!           // Synchronize other windows, as necessary according to
!           // 'scrollbind'.  Don't do this after an ":edit" command, except
!           // when 'diff' is set.
            if ((curwin->w_buffer == old_buf
  #ifdef FEAT_DIFF
                        || curwin->w_p_diff
***************
*** 2256,2271 ****
        }
        else if (vim_strchr(p_sbo, 'j')) // jump flag set in 'scrollopt'
        {
!           /*
!            * When switching between windows, make sure that the relative
!            * vertical offset is valid for the new window.  The relative
!            * offset is invalid whenever another 'scrollbind' window has
!            * scrolled to a point that would force the current window to
!            * scroll past the beginning or end of its buffer.  When the
!            * resync is performed, some of the other 'scrollbind' windows may
!            * need to jump so that the current window's relative position is
!            * visible on-screen.
!            */
            check_scrollbind(curwin->w_topline - curwin->w_scbind_pos, 0L);
        }
        curwin->w_scbind_pos = curwin->w_topline;
--- 2146,2159 ----
        }
        else if (vim_strchr(p_sbo, 'j')) // jump flag set in 'scrollopt'
        {
!           // When switching between windows, make sure that the relative
!           // vertical offset is valid for the new window.  The relative
!           // offset is invalid whenever another 'scrollbind' window has
!           // scrolled to a point that would force the current window to
!           // scroll past the beginning or end of its buffer.  When the
!           // resync is performed, some of the other 'scrollbind' windows may
!           // need to jump so that the current window's relative position is
!           // visible on-screen.
            check_scrollbind(curwin->w_topline - curwin->w_scbind_pos, 0L);
        }
        curwin->w_scbind_pos = curwin->w_topline;
***************
*** 2298,2315 ****
      long      topline;
      long      y;
  
!     /*
!      * check 'scrollopt' string for vertical and horizontal scroll options
!      */
      want_ver = (vim_strchr(p_sbo, 'v') && topline_diff != 0);
  #ifdef FEAT_DIFF
      want_ver |= old_curwin->w_p_diff;
  #endif
      want_hor = (vim_strchr(p_sbo, 'h') && (leftcol_diff || topline_diff != 
0));
  
!     /*
!      * loop through the scrollbound windows and scroll accordingly
!      */
      VIsual_select = VIsual_active = 0;
      FOR_ALL_WINDOWS(curwin)
      {
--- 2186,2199 ----
      long      topline;
      long      y;
  
!     // check 'scrollopt' string for vertical and horizontal scroll options
      want_ver = (vim_strchr(p_sbo, 'v') && topline_diff != 0);
  #ifdef FEAT_DIFF
      want_ver |= old_curwin->w_p_diff;
  #endif
      want_hor = (vim_strchr(p_sbo, 'h') && (leftcol_diff || topline_diff != 
0));
  
!     // loop through the scrollbound windows and scroll accordingly
      VIsual_select = VIsual_active = 0;
      FOR_ALL_WINDOWS(curwin)
      {
***************
*** 2317,2325 ****
        // skip original window  and windows with 'noscrollbind'
        if (curwin != old_curwin && curwin->w_p_scb)
        {
!           /*
!            * do the vertical scroll
!            */
            if (want_ver)
            {
  #ifdef FEAT_DIFF
--- 2201,2207 ----
        // skip original window  and windows with 'noscrollbind'
        if (curwin != old_curwin && curwin->w_p_scb)
        {
!           // do the vertical scroll
            if (want_ver)
            {
  #ifdef FEAT_DIFF
***************
*** 2349,2357 ****
                curwin->w_redr_status = TRUE;
            }
  
!           /*
!            * do the horizontal scroll
!            */
            if (want_hor && curwin->w_leftcol != tgt_leftcol)
            {
                curwin->w_leftcol = tgt_leftcol;
--- 2231,2237 ----
                curwin->w_redr_status = TRUE;
            }
  
!           // do the horizontal scroll
            if (want_hor && curwin->w_leftcol != tgt_leftcol)
            {
                curwin->w_leftcol = tgt_leftcol;
***************
*** 2360,2368 ****
        }
      }
  
!     /*
!      * reset current-window
!      */
      VIsual_select = old_VIsual_select;
      VIsual_active = old_VIsual_active;
      curwin = old_curwin;
--- 2240,2246 ----
        }
      }
  
!     // reset current-window
      VIsual_select = old_VIsual_select;
      VIsual_active = old_VIsual_active;
      curwin = old_curwin;
***************
*** 2569,2579 ****
      p_ws = FALSE;     // don't wrap around end of file now
      p_scs = FALSE;    // don't switch ignorecase off now
  
!     /*
!      * With "gD" go to line 1.
!      * With "gd" Search back for the start of the current function, then go
!      * back until a blank line.  If this fails go to line 1.
!      */
      if (!locally || !findpar(&incll, BACKWARD, 1L, '{', FALSE))
      {
        setpcmark();                    // Set in findpar() otherwise
--- 2447,2455 ----
      p_ws = FALSE;     // don't wrap around end of file now
      p_scs = FALSE;    // don't switch ignorecase off now
  
!     // With "gD" go to line 1.
!     // With "gd" Search back for the start of the current function, then go
!     // back until a blank line.  If this fails go to line 1.
      if (!locally || !findpar(&incll, BACKWARD, 1L, '{', FALSE))
      {
        setpcmark();                    // Set in findpar() otherwise
***************
*** 2714,2723 ****
  
      if (curwin->w_width != 0)
      {
!       /*
!        * Instead of sticking at the last character of the buffer line we
!        * try to stick in the last column of the screen.
!        */
        if (curwin->w_curswant == MAXCOL)
        {
        atend = TRUE;
--- 2590,2597 ----
  
      if (curwin->w_width != 0)
      {
!       // Instead of sticking at the last character of the buffer line we
!       // try to stick in the last column of the screen.
        if (curwin->w_curswant == MAXCOL)
        {
        atend = TRUE;
***************
*** 2828,2838 ****
        colnr_T virtcol;
        int     c;
  
!       /*
!        * Check for landing on a character that got split at the end of the
!        * last line.  We want to advance a screenline, not end up in the same
!        * screenline or move two screenlines.
!        */
        validate_virtcol();
        virtcol = curwin->w_virtcol;
  #if defined(FEAT_LINEBREAK)
--- 2702,2710 ----
        colnr_T virtcol;
        int     c;
  
!       // Check for landing on a character that got split at the end of the
!       // last line.  We want to advance a screenline, not end up in the same
!       // screenline or move two screenlines.
        validate_virtcol();
        virtcol = curwin->w_virtcol;
  #if defined(FEAT_LINEBREAK)
***************
*** 2929,2934 ****
--- 2801,2930 ----
  }
  
  /*
+  * Get the count specified after a 'z' command. Returns TRUE to process
+  * the 'z' command and FALSE to skip it.
+  */
+     static int
+ nv_z_get_count(cmdarg_T *cap, int *nchar_arg)
+ {
+     int               nchar = *nchar_arg;
+     long      n;
+ 
+     // "z123{nchar}": edit the count before obtaining {nchar}
+     if (checkclearop(cap->oap))
+       return FALSE;
+     n = nchar - '0';
+ 
+     for (;;)
+     {
+ #ifdef USE_ON_FLY_SCROLL
+       dont_scroll = TRUE;             // disallow scrolling here
+ #endif
+       ++no_mapping;
+       ++allow_keys;   // no mapping for nchar, but allow key codes
+       nchar = plain_vgetc();
+       LANGMAP_ADJUST(nchar, TRUE);
+       --no_mapping;
+       --allow_keys;
+ #ifdef FEAT_CMDL_INFO
+       (void)add_to_showcmd(nchar);
+ #endif
+       if (nchar == K_DEL || nchar == K_KDEL)
+           n /= 10;
+       else if (VIM_ISDIGIT(nchar))
+           n = n * 10 + (nchar - '0');
+       else if (nchar == CAR)
+       {
+ #ifdef FEAT_GUI
+           need_mouse_correct = TRUE;
+ #endif
+           win_setheight((int)n);
+           break;
+       }
+       else if (nchar == 'l'
+               || nchar == 'h'
+               || nchar == K_LEFT
+               || nchar == K_RIGHT)
+       {
+           cap->count1 = n ? n * cap->count1 : cap->count1;
+           *nchar_arg = nchar;
+           return TRUE;
+       }
+       else
+       {
+           clearopbeep(cap->oap);
+           break;
+       }
+     }
+     cap->oap->op_type = OP_NOP;
+     return FALSE;
+ }
+ 
+ #ifdef FEAT_SPELL
+ /*
+  * "zug" and "zuw": undo "zg" and "zw"
+  * "zg": add good word to word list
+  * "zw": add wrong word to word list
+  * "zG": add good word to temp word list
+  * "zW": add wrong word to temp word list
+  */
+     static int
+ nv_zg_zw(cmdarg_T *cap, int nchar)
+ {
+     char_u    *ptr = NULL;
+     int               len;
+     int               undo = FALSE;
+ 
+     if (nchar == 'u')
+     {
+       ++no_mapping;
+       ++allow_keys;   // no mapping for nchar, but allow key codes
+       nchar = plain_vgetc();
+       LANGMAP_ADJUST(nchar, TRUE);
+       --no_mapping;
+       --allow_keys;
+ #ifdef FEAT_CMDL_INFO
+       (void)add_to_showcmd(nchar);
+ #endif
+       if (vim_strchr((char_u *)"gGwW", nchar) == NULL)
+       {
+           clearopbeep(cap->oap);
+           return OK;
+       }
+       undo = TRUE;
+     }
+ 
+     if (checkclearop(cap->oap))
+       return OK;
+     if (VIsual_active && get_visual_text(cap, &ptr, &len) == FAIL)
+       return FAIL;
+     if (ptr == NULL)
+     {
+       pos_T   pos = curwin->w_cursor;
+ 
+       // Find bad word under the cursor.  When 'spell' is
+       // off this fails and find_ident_under_cursor() is
+       // used below.
+       emsg_off++;
+       len = spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL);
+       emsg_off--;
+       if (len != 0 && curwin->w_cursor.col <= pos.col)
+           ptr = ml_get_pos(&curwin->w_cursor);
+       curwin->w_cursor = pos;
+     }
+ 
+     if (ptr == NULL
+               && (len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
+       return FAIL;
+     spell_add_word(ptr, len, nchar == 'w' || nchar == 'W'
+           ? SPELL_ADD_BAD : SPELL_ADD_GOOD,
+           (nchar == 'G' || nchar == 'W') ? 0 : (int)cap->count1, undo);
+ 
+     return OK;
+ }
+ #endif
+ 
+ /*
   * Commands that start with "z".
   */
      static void
***************
*** 2941,3004 ****
      long      old_fdl = curwin->w_p_fdl;
      int               old_fen = curwin->w_p_fen;
  #endif
- #ifdef FEAT_SPELL
-     int               undo = FALSE;
- #endif
      long        siso = get_sidescrolloff_value();
  
!     if (VIM_ISDIGIT(nchar))
!     {
!       /*
!        * "z123{nchar}": edit the count before obtaining {nchar}
!        */
!       if (checkclearop(cap->oap))
            return;
-       n = nchar - '0';
-       for (;;)
-       {
- #ifdef USE_ON_FLY_SCROLL
-           dont_scroll = TRUE;         // disallow scrolling here
- #endif
-           ++no_mapping;
-           ++allow_keys;   // no mapping for nchar, but allow key codes
-           nchar = plain_vgetc();
-           LANGMAP_ADJUST(nchar, TRUE);
-           --no_mapping;
-           --allow_keys;
- #ifdef FEAT_CMDL_INFO
-           (void)add_to_showcmd(nchar);
- #endif
-           if (nchar == K_DEL || nchar == K_KDEL)
-               n /= 10;
-           else if (VIM_ISDIGIT(nchar))
-               n = n * 10 + (nchar - '0');
-           else if (nchar == CAR)
-           {
- #ifdef FEAT_GUI
-               need_mouse_correct = TRUE;
- #endif
-               win_setheight((int)n);
-               break;
-           }
-           else if (nchar == 'l'
-                   || nchar == 'h'
-                   || nchar == K_LEFT
-                   || nchar == K_RIGHT)
-           {
-               cap->count1 = n ? n * cap->count1 : cap->count1;
-               goto dozet;
-           }
-           else
-           {
-               clearopbeep(cap->oap);
-               break;
-           }
-       }
-       cap->oap->op_type = OP_NOP;
-       return;
-     }
  
- dozet:
      if (
  #ifdef FEAT_FOLDING
            // "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc"
--- 2937,2947 ----
      long      old_fdl = curwin->w_p_fdl;
      int               old_fen = curwin->w_p_fen;
  #endif
      long        siso = get_sidescrolloff_value();
  
!     if (VIM_ISDIGIT(nchar) && !nv_z_get_count(cap, &nchar))
            return;
  
      if (
  #ifdef FEAT_FOLDING
            // "zf" and "zF" are always an operator, "zd", "zo", "zO", "zc"
***************
*** 3012,3021 ****
            checkclearop(cap->oap))
        return;
  
!     /*
!      * For "z+", "z<CR>", "zt", "z.", "zz", "z^", "z-", "zb":
!      * If line number given, set cursor.
!      */
      if ((vim_strchr((char_u *)"+\r\nt.z^-b", nchar) != NULL)
            && cap->count0
            && cap->count0 != curwin->w_cursor.lnum)
--- 2955,2962 ----
            checkclearop(cap->oap))
        return;
  
!     // For "z+", "z<CR>", "zt", "z.", "zz", "z^", "z-", "zb":
!     // If line number given, set cursor.
      if ((vim_strchr((char_u *)"+\r\nt.z^-b", nchar) != NULL)
            && cap->count0
            && cap->count0 != curwin->w_cursor.lnum)
***************
*** 3337,3396 ****
  
  #ifdef FEAT_SPELL
      case 'u': // "zug" and "zuw": undo "zg" and "zw"
-               ++no_mapping;
-               ++allow_keys;   // no mapping for nchar, but allow key codes
-               nchar = plain_vgetc();
-               LANGMAP_ADJUST(nchar, TRUE);
-               --no_mapping;
-               --allow_keys;
- #ifdef FEAT_CMDL_INFO
-               (void)add_to_showcmd(nchar);
- #endif
-               if (vim_strchr((char_u *)"gGwW", nchar) == NULL)
-               {
-                   clearopbeep(cap->oap);
-                   break;
-               }
-               undo = TRUE;
-               // FALLTHROUGH
- 
      case 'g': // "zg": add good word to word list
      case 'w': // "zw": add wrong word to word list
      case 'G': // "zG": add good word to temp word list
      case 'W': // "zW": add wrong word to temp word list
!               {
!                   char_u  *ptr = NULL;
!                   int     len;
! 
!                   if (checkclearop(cap->oap))
!                       break;
!                   if (VIsual_active && get_visual_text(cap, &ptr, &len)
!                                                                     == FAIL)
!                       return;
!                   if (ptr == NULL)
!                   {
!                       pos_T   pos = curwin->w_cursor;
! 
!                       // Find bad word under the cursor.  When 'spell' is
!                       // off this fails and find_ident_under_cursor() is
!                       // used below.
!                       emsg_off++;
!                       len = spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL);
!                       emsg_off--;
!                       if (len != 0 && curwin->w_cursor.col <= pos.col)
!                           ptr = ml_get_pos(&curwin->w_cursor);
!                       curwin->w_cursor = pos;
!                   }
! 
!                   if (ptr == NULL && (len = find_ident_under_cursor(&ptr,
!                                                           FIND_IDENT)) == 0)
!                       return;
!                   spell_add_word(ptr, len, nchar == 'w' || nchar == 'W'
!                                             ? SPELL_ADD_BAD : SPELL_ADD_GOOD,
!                                           (nchar == 'G' || nchar == 'W')
!                                                      ? 0 : (int)cap->count1,
!                                           undo);
!               }
                break;
  
      case '=': // "z=": suggestions for a badly spelled word
--- 3278,3289 ----
  
  #ifdef FEAT_SPELL
      case 'u': // "zug" and "zuw": undo "zg" and "zw"
      case 'g': // "zg": add good word to word list
      case 'w': // "zw": add wrong word to word list
      case 'G': // "zG": add good word to temp word list
      case 'W': // "zW": add wrong word to temp word list
!               if (nv_zg_zw(cap, nchar) == FAIL)
!                   return;
                break;
  
      case '=': // "z=": suggestions for a badly spelled word
***************
*** 3537,3545 ****
      static void
  nv_exmode(cmdarg_T *cap)
  {
!     /*
!      * Ignore 'Q' in Visual mode, just give a beep.
!      */
      if (VIsual_active)
        vim_beep(BO_EX);
      else if (!checkclearop(cap->oap))
--- 3430,3436 ----
      static void
  nv_exmode(cmdarg_T *cap)
  {
!     // Ignore 'Q' in Visual mode, just give a beep.
      if (VIsual_active)
        vim_beep(BO_EX);
      else if (!checkclearop(cap->oap))
***************
*** 3751,3756 ****
--- 3642,3723 ----
  }
  
  /*
+  * 'K' normal-mode command. Get the command to lookup the keyword under the
+  * cursor.
+  */
+     static int
+ nv_K_getcmd(
+       cmdarg_T        *cap,
+       char_u          *kp,
+       int             kp_help,
+       int             kp_ex,
+       char_u          **ptr_arg,
+       int             n,
+       char_u          *buf,
+       unsigned        buflen)
+ {
+     char_u    *ptr = *ptr_arg;
+     int               isman;
+     int               isman_s;
+ 
+     if (kp_help)
+     {
+       // in the help buffer
+       STRCPY(buf, "he! ");
+       return n;
+     }
+ 
+     if (kp_ex)
+     {
+       // 'keywordprog' is an ex command
+       if (cap->count0 != 0)
+           vim_snprintf((char *)buf, buflen, "%s %ld", kp, cap->count0);
+       else
+           STRCPY(buf, kp);
+       STRCAT(buf, " ");
+       return n;
+     }
+ 
+     // An external command will probably use an argument starting
+     // with "-" as an option.  To avoid trouble we skip the "-".
+     while (*ptr == '-' && n > 0)
+     {
+       ++ptr;
+       --n;
+     }
+     if (n == 0)
+     {
+       // found dashes only
+       emsg(_(e_no_identifier_under_cursor));
+       vim_free(buf);
+       *ptr_arg = ptr;
+       return 0;
+     }
+ 
+     // When a count is given, turn it into a range.  Is this
+     // really what we want?
+     isman = (STRCMP(kp, "man") == 0);
+     isman_s = (STRCMP(kp, "man -s") == 0);
+     if (cap->count0 != 0 && !(isman || isman_s))
+       sprintf((char *)buf, ".,.+%ld", cap->count0 - 1);
+ 
+     STRCAT(buf, "! ");
+     if (cap->count0 == 0 && isman_s)
+       STRCAT(buf, "man");
+     else
+       STRCAT(buf, kp);
+     STRCAT(buf, " ");
+     if (cap->count0 != 0 && (isman || isman_s))
+     {
+       sprintf((char *)buf + STRLEN(buf), "%ld", cap->count0);
+       STRCAT(buf, " ");
+     }
+ 
+     *ptr_arg = ptr;
+     return n;
+ }
+ 
+ /*
   * Handle the commands that use the word under the cursor.
   * [g] CTRL-] :ta to current identifier
   * [g] 'K'    run program for current identifier
***************
*** 3774,3781 ****
      int               g_cmd;          // "g" command
      int               tag_cmd = FALSE;
      char_u    *aux_ptr;
-     int               isman;
-     int               isman_s;
  
      if (cap->cmdchar == 'g')  // "g*", "g#", "g]" and "gCTRL-]"
      {
--- 3741,3746 ----
***************
*** 3791,3799 ****
      if (cmdchar == POUND)     // the pound sign, '#' for English keyboards
        cmdchar = '#';
  
!     /*
!      * The "]", "CTRL-]" and "K" commands accept an argument in Visual mode.
!      */
      if (cmdchar == ']' || cmdchar == Ctrl_RSB || cmdchar == 'K')
      {
        if (VIsual_active && get_visual_text(cap, &ptr, &n) == FAIL)
--- 3756,3762 ----
      if (cmdchar == POUND)     // the pound sign, '#' for English keyboards
        cmdchar = '#';
  
!     // The "]", "CTRL-]" and "K" commands accept an argument in Visual mode.
      if (cmdchar == ']' || cmdchar == Ctrl_RSB || cmdchar == 'K')
      {
        if (VIsual_active && get_visual_text(cap, &ptr, &n) == FAIL)
***************
*** 3832,3843 ****
      {
        case '*':
        case '#':
!           /*
!            * Put cursor at start of word, makes search skip the word
!            * under the cursor.
!            * Call setpcmark() first, so "*``" puts the cursor back where
!            * it was.
!            */
            setpcmark();
            curwin->w_cursor.col = (colnr_T) (ptr - ml_get_curline());
  
--- 3795,3804 ----
      {
        case '*':
        case '#':
!           // Put cursor at start of word, makes search skip the word
!           // under the cursor.
!           // Call setpcmark() first, so "*``" puts the cursor back where
!           // it was.
            setpcmark();
            curwin->w_cursor.col = (colnr_T) (ptr - ml_get_curline());
  
***************
*** 3847,3899 ****
            break;
  
        case 'K':
!           if (kp_help)
!               STRCPY(buf, "he! ");
!           else if (kp_ex)
!           {
!               if (cap->count0 != 0)
!                   vim_snprintf((char *)buf, buflen, "%s %ld",
!                                                            kp, cap->count0);
!               else
!                   STRCPY(buf, kp);
!               STRCAT(buf, " ");
!           }
!           else
!           {
!               // An external command will probably use an argument starting
!               // with "-" as an option.  To avoid trouble we skip the "-".
!               while (*ptr == '-' && n > 0)
!               {
!                   ++ptr;
!                   --n;
!               }
!               if (n == 0)
!               {
!                   // found dashes only
!                   emsg(_(e_no_identifier_under_cursor));
!                   vim_free(buf);
!                   return;
!               }
! 
!               // When a count is given, turn it into a range.  Is this
!               // really what we want?
!               isman = (STRCMP(kp, "man") == 0);
!               isman_s = (STRCMP(kp, "man -s") == 0);
!               if (cap->count0 != 0 && !(isman || isman_s))
!                   sprintf((char *)buf, ".,.+%ld", cap->count0 - 1);
! 
!               STRCAT(buf, "! ");
!               if (cap->count0 == 0 && isman_s)
!                   STRCAT(buf, "man");
!               else
!                   STRCAT(buf, kp);
!               STRCAT(buf, " ");
!               if (cap->count0 != 0 && (isman || isman_s))
!               {
!                   sprintf((char *)buf + STRLEN(buf), "%ld", cap->count0);
!                   STRCAT(buf, " ");
!               }
!           }
            break;
  
        case ']':
--- 3808,3816 ----
            break;
  
        case 'K':
!           n = nv_K_getcmd(cap, kp, kp_help, kp_ex, &ptr, n, buf, buflen);
!           if (n == 0)
!               return;
            break;
  
        case ']':
***************
*** 3921,3929 ****
            }
      }
  
!     /*
!      * Now grab the chars in the identifier
!      */
      if (cmdchar == 'K' && !kp_help)
      {
        ptr = vim_strnsave(ptr, n);
--- 3838,3844 ----
            }
      }
  
!     // Now grab the chars in the identifier
      if (cmdchar == 'K' && !kp_help)
      {
        ptr = vim_strnsave(ptr, n);
***************
*** 3988,3996 ****
        *p = NUL;
      }
  
!     /*
!      * Execute the command.
!      */
      if (cmdchar == '*' || cmdchar == '#')
      {
        if (!g_cmd && (has_mbyte
--- 3903,3909 ----
        *p = NUL;
      }
  
!     // Execute the command.
      if (cmdchar == '*' || cmdchar == '#')
      {
        if (!g_cmd && (has_mbyte
***************
*** 4194,4203 ****
      cap->oap->inclusive = FALSE;
      past_line = (VIsual_active && *p_sel != 'o');
  
!     /*
!      * In virtual edit mode, there's no such thing as "past_line", as lines
!      * are (theoretically) infinitely long.
!      */
      if (virtual_active())
        past_line = 0;
  
--- 4107,4114 ----
      cap->oap->inclusive = FALSE;
      past_line = (VIsual_active && *p_sel != 'o');
  
!     // In virtual edit mode, there's no such thing as "past_line", as lines
!     // are (theoretically) infinitely long.
      if (virtual_active())
        past_line = 0;
  
***************
*** 4207,4217 ****
                || (past_line && *ml_get_cursor() == NUL)
                )
        {
!           /*
!            *    <Space> wraps to next line if 'whichwrap' has 's'.
!            *        'l' wraps to next line if 'whichwrap' has 'l'.
!            * CURS_RIGHT wraps to next line if 'whichwrap' has '>'.
!            */
            if (       ((cap->cmdchar == ' '
                            && vim_strchr(p_ww, 's') != NULL)
                        || (cap->cmdchar == 'l'
--- 4118,4126 ----
                || (past_line && *ml_get_cursor() == NUL)
                )
        {
!           //    <Space> wraps to next line if 'whichwrap' has 's'.
!           //        'l' wraps to next line if 'whichwrap' has 'l'.
!           // CURS_RIGHT wraps to next line if 'whichwrap' has '>'.
            if (       ((cap->cmdchar == ' '
                            && vim_strchr(p_ww, 's') != NULL)
                        || (cap->cmdchar == 'l'
***************
*** 4646,4665 ****
  }
  
  /*
   * "[" and "]" commands.
   * cap->arg is BACKWARD for "[" and FORWARD for "]".
   */
      static void
  nv_brackets(cmdarg_T *cap)
  {
-     pos_T     new_pos = {0, 0, 0};
      pos_T     prev_pos;
      pos_T     *pos = NULL;        // init for GCC
      pos_T     old_pos;            // cursor position before command
      int               flag;
      long      n;
-     int               findc;
-     int               c;
  
      cap->oap->motion_type = MCHAR;
      cap->oap->inclusive = FALSE;
--- 4555,4703 ----
  }
  
  /*
+  * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
+  * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
+  * "[/", "[*", "]/", "]*": go to Nth comment start/end.
+  * "[m" or "]m" search for prev/next start of (Java) method.
+  * "[M" or "]M" search for prev/next end of (Java) method.
+  */
+     static void
+ nv_bracket_block(cmdarg_T *cap, pos_T *old_pos)
+ {
+     pos_T     new_pos = {0, 0, 0};
+     pos_T     *pos = NULL;        // init for GCC
+     pos_T     prev_pos;
+     long      n;
+     int               findc;
+     int               c;
+ 
+     if (cap->nchar == '*')
+       cap->nchar = '/';
+     prev_pos.lnum = 0;
+     if (cap->nchar == 'm' || cap->nchar == 'M')
+     {
+       if (cap->cmdchar == '[')
+           findc = '{';
+       else
+           findc = '}';
+       n = 9999;
+     }
+     else
+     {
+       findc = cap->nchar;
+       n = cap->count1;
+     }
+     for ( ; n > 0; --n)
+     {
+       if ((pos = findmatchlimit(cap->oap, findc,
+                       (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) 
== NULL)
+       {
+           if (new_pos.lnum == 0)      // nothing found
+           {
+               if (cap->nchar != 'm' && cap->nchar != 'M')
+                   clearopbeep(cap->oap);
+           }
+           else
+               pos = &new_pos; // use last one found
+           break;
+       }
+       prev_pos = new_pos;
+       curwin->w_cursor = *pos;
+       new_pos = *pos;
+     }
+     curwin->w_cursor = *old_pos;
+ 
+     // Handle "[m", "]m", "[M" and "[M".  The findmatchlimit() only
+     // brought us to the match for "[m" and "]M" when inside a method.
+     // Try finding the '{' or '}' we want to be at.
+     // Also repeat for the given count.
+     if (cap->nchar == 'm' || cap->nchar == 'M')
+     {
+       // norm is TRUE for "]M" and "[m"
+       int         norm = ((findc == '{') == (cap->nchar == 'm'));
+ 
+       n = cap->count1;
+       // found a match: we were inside a method
+       if (prev_pos.lnum != 0)
+       {
+           pos = &prev_pos;
+           curwin->w_cursor = prev_pos;
+           if (norm)
+               --n;
+       }
+       else
+           pos = NULL;
+       while (n > 0)
+       {
+           for (;;)
+           {
+               if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0)
+               {
+                   // if not found anything, that's an error
+                   if (pos == NULL)
+                       clearopbeep(cap->oap);
+                   n = 0;
+                   break;
+               }
+               c = gchar_cursor();
+               if (c == '{' || c == '}')
+               {
+                   // Must have found end/start of class: use it.
+                   // Or found the place to be at.
+                   if ((c == findc && norm) || (n == 1 && !norm))
+                   {
+                       new_pos = curwin->w_cursor;
+                       pos = &new_pos;
+                       n = 0;
+                   }
+                   // if no match found at all, we started outside of the
+                   // class and we're inside now.  Just go on.
+                   else if (new_pos.lnum == 0)
+                   {
+                       new_pos = curwin->w_cursor;
+                       pos = &new_pos;
+                   }
+                   // found start/end of other method: go to match
+                   else if ((pos = findmatchlimit(cap->oap, findc,
+                                   (cap->cmdchar == '[') ? FM_BACKWARD : 
FM_FORWARD,
+                                   0)) == NULL)
+                       n = 0;
+                   else
+                       curwin->w_cursor = *pos;
+                   break;
+               }
+           }
+           --n;
+       }
+       curwin->w_cursor = *old_pos;
+       if (pos == NULL && new_pos.lnum != 0)
+           clearopbeep(cap->oap);
+     }
+     if (pos != NULL)
+     {
+       setpcmark();
+       curwin->w_cursor = *pos;
+       curwin->w_set_curswant = TRUE;
+ #ifdef FEAT_FOLDING
+       if ((fdo_flags & FDO_BLOCK) && KeyTyped
+               && cap->oap->op_type == OP_NOP)
+           foldOpenCursor();
+ #endif
+     }
+ }
+ 
+ /*
   * "[" and "]" commands.
   * cap->arg is BACKWARD for "[" and FORWARD for "]".
   */
      static void
  nv_brackets(cmdarg_T *cap)
  {
      pos_T     prev_pos;
      pos_T     *pos = NULL;        // init for GCC
      pos_T     old_pos;            // cursor position before command
      int               flag;
      long      n;
  
      cap->oap->motion_type = MCHAR;
      cap->oap->inclusive = FALSE;
***************
*** 4667,4690 ****
      curwin->w_cursor.coladd = 0;    // TODO: don't do this for an error.
  
  #ifdef FEAT_SEARCHPATH
!     /*
!      * "[f" or "]f" : Edit file under the cursor (same as "gf")
!      */
      if (cap->nchar == 'f')
        nv_gotofile(cap);
      else
  #endif
  
  #ifdef FEAT_FIND_ID
!     /*
!      * Find the occurrence(s) of the identifier or define under cursor
!      * in current and included files or jump to the first occurrence.
!      *
!      *                        search       list           jump
!      *                      fwd   bwd    fwd   bwd     fwd    bwd
!      * identifier     "]i"  "[i"   "]I"  "[I" "]^I"  "[^I"
!      * define       "]d"  "[d"   "]D"  "[D"   "]^D"  "[^D"
!      */
      if (vim_strchr((char_u *)
  # ifdef EBCDIC
                "iI\005dD\067",
--- 4705,4724 ----
      curwin->w_cursor.coladd = 0;    // TODO: don't do this for an error.
  
  #ifdef FEAT_SEARCHPATH
!     // "[f" or "]f" : Edit file under the cursor (same as "gf")
      if (cap->nchar == 'f')
        nv_gotofile(cap);
      else
  #endif
  
  #ifdef FEAT_FIND_ID
!     // Find the occurrence(s) of the identifier or define under cursor
!     // in current and included files or jump to the first occurrence.
!     //
!     //                        search       list           jump
!     //                      fwd   bwd    fwd   bwd     fwd    bwd
!     // identifier     "]i"  "[i"   "]I"  "[I" "]^I"  "[^I"
!     // define       "]d"  "[d"   "]D"  "[D"   "]^D"  "[^D"
      if (vim_strchr((char_u *)
  # ifdef EBCDIC
                "iI\005dD\067",
***************
*** 4714,4851 ****
      else
  #endif
  
!     /*
!      * "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
!      * "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
!      * "[/", "[*", "]/", "]*": go to Nth comment start/end.
!      * "[m" or "]m" search for prev/next start of (Java) method.
!      * "[M" or "]M" search for prev/next end of (Java) method.
!      */
      if (  (cap->cmdchar == '['
                && vim_strchr((char_u *)"{(*/#mM", cap->nchar) != NULL)
            || (cap->cmdchar == ']'
                && vim_strchr((char_u *)"})*/#mM", cap->nchar) != NULL))
!     {
!       if (cap->nchar == '*')
!           cap->nchar = '/';
!       prev_pos.lnum = 0;
!       if (cap->nchar == 'm' || cap->nchar == 'M')
!       {
!           if (cap->cmdchar == '[')
!               findc = '{';
!           else
!               findc = '}';
!           n = 9999;
!       }
!       else
!       {
!           findc = cap->nchar;
!           n = cap->count1;
!       }
!       for ( ; n > 0; --n)
!       {
!           if ((pos = findmatchlimit(cap->oap, findc,
!               (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL)
!           {
!               if (new_pos.lnum == 0)  // nothing found
!               {
!                   if (cap->nchar != 'm' && cap->nchar != 'M')
!                       clearopbeep(cap->oap);
!               }
!               else
!                   pos = &new_pos;     // use last one found
!               break;
!           }
!           prev_pos = new_pos;
!           curwin->w_cursor = *pos;
!           new_pos = *pos;
!       }
!       curwin->w_cursor = old_pos;
! 
!       /*
!        * Handle "[m", "]m", "[M" and "[M".  The findmatchlimit() only
!        * brought us to the match for "[m" and "]M" when inside a method.
!        * Try finding the '{' or '}' we want to be at.
!        * Also repeat for the given count.
!        */
!       if (cap->nchar == 'm' || cap->nchar == 'M')
!       {
!           // norm is TRUE for "]M" and "[m"
!           int     norm = ((findc == '{') == (cap->nchar == 'm'));
  
!           n = cap->count1;
!           // found a match: we were inside a method
!           if (prev_pos.lnum != 0)
!           {
!               pos = &prev_pos;
!               curwin->w_cursor = prev_pos;
!               if (norm)
!                   --n;
!           }
!           else
!               pos = NULL;
!           while (n > 0)
!           {
!               for (;;)
!               {
!                   if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0)
!                   {
!                       // if not found anything, that's an error
!                       if (pos == NULL)
!                           clearopbeep(cap->oap);
!                       n = 0;
!                       break;
!                   }
!                   c = gchar_cursor();
!                   if (c == '{' || c == '}')
!                   {
!                       // Must have found end/start of class: use it.
!                       // Or found the place to be at.
!                       if ((c == findc && norm) || (n == 1 && !norm))
!                       {
!                           new_pos = curwin->w_cursor;
!                           pos = &new_pos;
!                           n = 0;
!                       }
!                       // if no match found at all, we started outside of the
!                       // class and we're inside now.  Just go on.
!                       else if (new_pos.lnum == 0)
!                       {
!                           new_pos = curwin->w_cursor;
!                           pos = &new_pos;
!                       }
!                       // found start/end of other method: go to match
!                       else if ((pos = findmatchlimit(cap->oap, findc,
!                           (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD,
!                                                                 0)) == NULL)
!                           n = 0;
!                       else
!                           curwin->w_cursor = *pos;
!                       break;
!                   }
!               }
!               --n;
!           }
!           curwin->w_cursor = old_pos;
!           if (pos == NULL && new_pos.lnum != 0)
!               clearopbeep(cap->oap);
!       }
!       if (pos != NULL)
!       {
!           setpcmark();
!           curwin->w_cursor = *pos;
!           curwin->w_set_curswant = TRUE;
! #ifdef FEAT_FOLDING
!           if ((fdo_flags & FDO_BLOCK) && KeyTyped
!                                              && cap->oap->op_type == OP_NOP)
!               foldOpenCursor();
! #endif
!       }
!     }
! 
!     /*
!      * "[[", "[]", "]]" and "][": move to start or end of function
!      */
      else if (cap->nchar == '[' || cap->nchar == ']')
      {
        if (cap->nchar == cap->cmdchar)             // "]]" or "[["
--- 4748,4765 ----
      else
  #endif
  
!     // "[{", "[(", "]}" or "])": go to Nth unclosed '{', '(', '}' or ')'
!     // "[#", "]#": go to start/end of Nth innermost #if..#endif construct.
!     // "[/", "[*", "]/", "]*": go to Nth comment start/end.
!     // "[m" or "]m" search for prev/next start of (Java) method.
!     // "[M" or "]M" search for prev/next end of (Java) method.
      if (  (cap->cmdchar == '['
                && vim_strchr((char_u *)"{(*/#mM", cap->nchar) != NULL)
            || (cap->cmdchar == ']'
                && vim_strchr((char_u *)"})*/#mM", cap->nchar) != NULL))
!       nv_bracket_block(cap, &old_pos);
  
!     // "[[", "[]", "]]" and "][": move to start or end of function
      else if (cap->nchar == '[' || cap->nchar == ']')
      {
        if (cap->nchar == cap->cmdchar)             // "]]" or "[["
***************
*** 4854,4863 ****
            flag = '}';             // "][" or "[]"
  
        curwin->w_set_curswant = TRUE;
!       /*
!        * Imitate strange Vi behaviour: When using "]]" with an operator
!        * we also stop at '}'.
!        */
        if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, flag,
              (cap->oap->op_type != OP_NOP
                                      && cap->arg == FORWARD && flag == '{')))
--- 4768,4775 ----
            flag = '}';             // "][" or "[]"
  
        curwin->w_set_curswant = TRUE;
!       // Imitate strange Vi behaviour: When using "]]" with an operator
!       // we also stop at '}'.
        if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, flag,
              (cap->oap->op_type != OP_NOP
                                      && cap->arg == FORWARD && flag == '{')))
***************
*** 4873,4889 ****
        }
      }
  
!     /*
!      * "[p", "[P", "]P" and "]p": put with indent adjustment
!      */
      else if (cap->nchar == 'p' || cap->nchar == 'P')
      {
        nv_put_opt(cap, TRUE);
      }
  
!     /*
!      * "['", "[`", "]'" and "]`": jump to next mark
!      */
      else if (cap->nchar == '\'' || cap->nchar == '`')
      {
        pos = &curwin->w_cursor;
--- 4785,4797 ----
        }
      }
  
!     // "[p", "[P", "]P" and "]p": put with indent adjustment
      else if (cap->nchar == 'p' || cap->nchar == 'P')
      {
        nv_put_opt(cap, TRUE);
      }
  
!     // "['", "[`", "]'" and "]`": jump to next mark
      else if (cap->nchar == '\'' || cap->nchar == '`')
      {
        pos = &curwin->w_cursor;
***************
*** 4900,4909 ****
        nv_cursormark(cap, cap->nchar == '\'', pos);
      }
  
!     /*
!      * [ or ] followed by a middle mouse click: put selected text with
!      * indent adjustment.  Any other button just does as usual.
!      */
      else if (cap->nchar >= K_RIGHTRELEASE && cap->nchar <= K_LEFTMOUSE)
      {
        (void)do_mouse(cap->oap, cap->nchar,
--- 4808,4815 ----
        nv_cursormark(cap, cap->nchar == '\'', pos);
      }
  
!     // [ or ] followed by a middle mouse click: put selected text with
!     // indent adjustment.  Any other button just does as usual.
      else if (cap->nchar >= K_RIGHTRELEASE && cap->nchar <= K_LEFTMOUSE)
      {
        (void)do_mouse(cap->oap, cap->nchar,
***************
*** 4912,4920 ****
      }
  
  #ifdef FEAT_FOLDING
!     /*
!      * "[z" and "]z": move to start or end of open fold.
!      */
      else if (cap->nchar == 'z')
      {
        if (foldMoveTo(FALSE, cap->cmdchar == ']' ? FORWARD : BACKWARD,
--- 4818,4824 ----
      }
  
  #ifdef FEAT_FOLDING
!     // "[z" and "]z": move to start or end of open fold.
      else if (cap->nchar == 'z')
      {
        if (foldMoveTo(FALSE, cap->cmdchar == ']' ? FORWARD : BACKWARD,
***************
*** 4924,4932 ****
  #endif
  
  #ifdef FEAT_DIFF
!     /*
!      * "[c" and "]c": move to next or previous diff-change.
!      */
      else if (cap->nchar == 'c')
      {
        if (diff_move_to(cap->cmdchar == ']' ? FORWARD : BACKWARD,
--- 4828,4834 ----
  #endif
  
  #ifdef FEAT_DIFF
!     // "[c" and "]c": move to next or previous diff-change.
      else if (cap->nchar == 'c')
      {
        if (diff_move_to(cap->cmdchar == ']' ? FORWARD : BACKWARD,
***************
*** 4936,4944 ****
  #endif
  
  #ifdef FEAT_SPELL
!     /*
!      * "[s", "[S", "]s" and "]S": move to next spell error.
!      */
      else if (cap->nchar == 's' || cap->nchar == 'S')
      {
        setpcmark();
--- 4838,4844 ----
  #endif
  
  #ifdef FEAT_SPELL
!     // "[s", "[S", "]s" and "]S": move to next spell error.
      else if (cap->nchar == 's' || cap->nchar == 'S')
      {
        setpcmark();
***************
*** 5205,5216 ****
        return;
      }
  
!     /*
!      * Replacing with a TAB is done by edit() when it is complicated because
!      * 'expandtab' or 'smarttab' is set.  CTRL-V TAB inserts a literal TAB.
!      * Other characters are done below to avoid problems with things like
!      * CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
!      */
      if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && (curbuf->b_p_et || 
p_sta))
      {
        stuffnumReadbuff(cap->count1);
--- 5105,5114 ----
        return;
      }
  
!     // Replacing with a TAB is done by edit() when it is complicated because
!     // 'expandtab' or 'smarttab' is set.  CTRL-V TAB inserts a literal TAB.
!     // Other characters are done below to avoid problems with things like
!     // CTRL-V 048 (for edit() this would be R CTRL-V 0 ESC).
      if (had_ctrl_v != Ctrl_V && cap->nchar == '\t' && (curbuf->b_p_et || 
p_sta))
      {
        stuffnumReadbuff(cap->count1);
***************
*** 5226,5239 ****
  
      if (had_ctrl_v != Ctrl_V && (cap->nchar == '\r' || cap->nchar == '\n'))
      {
!       /*
!        * Replace character(s) by a single newline.
!        * Strange vi behaviour: Only one newline is inserted.
!        * Delete the characters here.
!        * Insert the newline with an insert command, takes care of
!        * autoindent.  The insert command depends on being on the last
!        * character of a line or not.
!        */
        (void)del_chars(cap->count1, FALSE);    // delete the characters
        stuffcharReadbuff('\r');
        stuffcharReadbuff(ESC);
--- 5124,5135 ----
  
      if (had_ctrl_v != Ctrl_V && (cap->nchar == '\r' || cap->nchar == '\n'))
      {
!       // Replace character(s) by a single newline.
!       // Strange vi behaviour: Only one newline is inserted.
!       // Delete the characters here.
!       // Insert the newline with an insert command, takes care of
!       // autoindent.  The insert command depends on being on the last
!       // character of a line or not.
        (void)del_chars(cap->count1, FALSE);    // delete the characters
        stuffcharReadbuff('\r');
        stuffcharReadbuff(ESC);
***************
*** 5283,5298 ****
        }
        else
        {
!           /*
!            * Replace the characters within one line.
!            */
            for (n = cap->count1; n > 0; --n)
            {
!               /*
!                * Get ptr again, because u_save and/or showmatch() will have
!                * released the line.  This may also happen in ins_copychar().
!                * At the same time we let know that the line will be changed.
!                */
                if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y)
                {
                  int c = ins_copychar(curwin->w_cursor.lnum
--- 5179,5190 ----
        }
        else
        {
!           // Replace the characters within one line.
            for (n = cap->count1; n > 0; --n)
            {
!               // Get ptr again, because u_save and/or showmatch() will have
!               // released the line.  This may also happen in ins_copychar().
!               // At the same time we let know that the line will be changed.
                if (cap->nchar == Ctrl_E || cap->nchar == Ctrl_Y)
                {
                  int c = ins_copychar(curwin->w_cursor.lnum
***************
*** 5849,5858 ****
            setmouse();
            if (p_smd && msg_silent == 0)
                redraw_cmdline = TRUE;      // show visual mode later
!           /*
!            * For V and ^V, we multiply the number of lines even if there
!            * was only one -- webb
!            */
            if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
            {
                curwin->w_cursor.lnum +=
--- 5741,5748 ----
            setmouse();
            if (p_smd && msg_silent == 0)
                redraw_cmdline = TRUE;      // show visual mode later
!           // For V and ^V, we multiply the number of lines even if there
!           // was only one -- webb
            if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1)
            {
                curwin->w_cursor.lnum +=
***************
*** 6677,6687 ****
  {
      if (!checkclearopq(cap->oap))
      {
!       /*
!        * If "restart_edit" is TRUE, the last but one command is repeated
!        * instead of the last command (inserting text). This is used for
!        * CTRL-O <.> in insert mode.
!        */
        if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == FAIL)
            clearopbeep(cap->oap);
      }
--- 6567,6575 ----
  {
      if (!checkclearopq(cap->oap))
      {
!       // If "restart_edit" is TRUE, the last but one command is repeated
!       // instead of the last command (inserting text). This is used for
!       // CTRL-O <.> in insert mode.
        if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == FAIL)
            clearopbeep(cap->oap);
      }
***************
*** 6907,6924 ****
      int               flag = FALSE;
      pos_T     startpos = curwin->w_cursor;
  
!     /*
!      * Set inclusive for the "E" and "e" command.
!      */
      if (cap->cmdchar == 'e' || cap->cmdchar == 'E')
        word_end = TRUE;
      else
        word_end = FALSE;
      cap->oap->inclusive = word_end;
  
!     /*
!      * "cw" and "cW" are a special case.
!      */
      if (!word_end && cap->oap->op_type == OP_CHANGE)
      {
        n = gchar_cursor();
--- 6795,6808 ----
      int               flag = FALSE;
      pos_T     startpos = curwin->w_cursor;
  
!     // Set inclusive for the "E" and "e" command.
      if (cap->cmdchar == 'e' || cap->cmdchar == 'E')
        word_end = TRUE;
      else
        word_end = FALSE;
      cap->oap->inclusive = word_end;
  
!     // "cw" and "cW" are a special case.
      if (!word_end && cap->oap->op_type == OP_CHANGE)
      {
        n = gchar_cursor();
***************
*** 6926,6937 ****
        {
            if (VIM_ISWHITE(n))
            {
!               /*
!                * Reproduce a funny Vi behaviour: "cw" on a blank only
!                * changes one character, not all blanks until the start of
!                * the next word.  Only do this when the 'w' flag is included
!                * in 'cpoptions'.
!                */
                if (cap->count1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL)
                {
                    cap->oap->inclusive = TRUE;
--- 6810,6819 ----
        {
            if (VIM_ISWHITE(n))
            {
!               // Reproduce a funny Vi behaviour: "cw" on a blank only
!               // changes one character, not all blanks until the start of
!               // the next word.  Only do this when the 'w' flag is included
!               // in 'cpoptions'.
                if (cap->count1 == 1 && vim_strchr(p_cpo, CPO_CW) != NULL)
                {
                    cap->oap->inclusive = TRUE;
***************
*** 6941,6957 ****
            }
            else
            {
!               /*
!                * This is a little strange. To match what the real Vi does,
!                * we effectively map 'cw' to 'ce', and 'cW' to 'cE', provided
!                * that we are not on a space or a TAB.  This seems impolite
!                * at first, but it's really more what we mean when we say
!                * 'cw'.
!                * Another strangeness: When standing on the end of a word
!                * "ce" will change until the end of the next word, but "cw"
!                * will change only one character! This is done by setting
!                * flag.
!                */
                cap->oap->inclusive = TRUE;
                word_end = TRUE;
                flag = TRUE;
--- 6823,6837 ----
            }
            else
            {
!               // This is a little strange. To match what the real Vi does,
!               // we effectively map 'cw' to 'ce', and 'cW' to 'cE', provided
!               // that we are not on a space or a TAB.  This seems impolite
!               // at first, but it's really more what we mean when we say
!               // 'cw'.
!               // Another strangeness: When standing on the end of a word
!               // "ce" will change until the end of the next word, but "cw"
!               // will change only one character! This is done by setting
!               // flag.
                cap->oap->inclusive = TRUE;
                word_end = TRUE;
                flag = TRUE;
*** ../vim-8.2.4220/src/version.c       2022-01-26 11:16:48.663593514 +0000
--- src/version.c       2022-01-26 12:07:16.074355910 +0000
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4221,
  /**/

-- 
If you only have a hammer, you tend to see every problem as a nail.
If you only have MS-Windows, you tend to solve every problem by rebooting.

 /// Bram Moolenaar -- [email protected] -- 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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220126121451.404B71C091E%40moolenaar.net.

Raspunde prin e-mail lui