Patch 8.2.3227
Problem:    'virtualedit' can only be set globally.
Solution:   Make 'virtualedit' global-local. (Gary Johnson, closes #8638)
Files:      runtime/doc/options.txt, src/buffer.c, src/change.c,
            src/drawscreen.c, src/edit.c, src/misc2.c, src/normal.c,
            src/ops.c, src/option.c, src/option.h, src/optiondefs.h,
            src/optionstr.c, src/proto/option.pro, src/register.c,
            src/structs.h, src/testdir/test_virtualedit.vim


*** ../vim-8.2.3226/runtime/doc/options.txt     2021-07-22 11:46:55.502419535 
+0200
--- runtime/doc/options.txt     2021-07-26 22:15:33.304602845 +0200
***************
*** 8634,8645 ****
  
                                            *'virtualedit'* *'ve'*
  'virtualedit' 've'    string  (default "")
!                       global
        A comma separated list of these words:
            block       Allow virtual editing in Visual block mode.
            insert      Allow virtual editing in Insert mode.
            all         Allow virtual editing in all modes.
            onemore     Allow the cursor to move just past the end of the line
  
        Virtual editing means that the cursor can be positioned where there is
        no actual character.  This can be halfway into a tab or beyond the end
--- 8643,8658 ----
  
                                            *'virtualedit'* *'ve'*
  'virtualedit' 've'    string  (default "")
!                       global or local to buffer |global-local|
        A comma separated list of these words:
            block       Allow virtual editing in Visual block mode.
            insert      Allow virtual editing in Insert mode.
            all         Allow virtual editing in all modes.
            onemore     Allow the cursor to move just past the end of the line
+           none        When used as the local value, do not allow virtual
+                       editing even when the global value is set.  When used
+                       as the global value, "none" is the same as "".
+           NONE        Alternative spelling of "none".
  
        Virtual editing means that the cursor can be positioned where there is
        no actual character.  This can be halfway into a tab or beyond the end
*** ../vim-8.2.3226/src/buffer.c        2021-07-20 21:07:32.960058864 +0200
--- src/buffer.c        2021-07-26 22:15:33.304602845 +0200
***************
*** 2384,2389 ****
--- 2384,2390 ----
  #endif
      clear_string_option(&buf->b_p_bkc);
      clear_string_option(&buf->b_p_menc);
+     clear_string_option(&buf->b_p_ve);
  }
  
  /*
*** ../vim-8.2.3226/src/change.c        2021-07-24 21:33:22.387681963 +0200
--- src/change.c        2021-07-26 22:15:33.304602845 +0200
***************
*** 1257,1263 ****
        // fixpos is TRUE, we don't want to end up positioned at the NUL,
        // unless "restart_edit" is set or 'virtualedit' contains "onemore".
        if (col > 0 && fixpos && restart_edit == 0
!                                             && (ve_flags & VE_ONEMORE) == 0)
        {
            --curwin->w_cursor.col;
            curwin->w_cursor.coladd = 0;
--- 1257,1263 ----
        // fixpos is TRUE, we don't want to end up positioned at the NUL,
        // unless "restart_edit" is set or 'virtualedit' contains "onemore".
        if (col > 0 && fixpos && restart_edit == 0
!                                             && (get_ve_flags() & VE_ONEMORE) 
== 0)
        {
            --curwin->w_cursor.col;
            curwin->w_cursor.coladd = 0;
*** ../vim-8.2.3226/src/drawscreen.c    2021-07-22 21:32:38.429405726 +0200
--- src/drawscreen.c    2021-07-26 22:15:33.304602845 +0200
***************
*** 2006,2026 ****
            {
                colnr_T     fromc, toc;
  #if defined(FEAT_LINEBREAK)
!               int         save_ve_flags = ve_flags;
  
                if (curwin->w_p_lbr)
!                   ve_flags = VE_ALL;
  #endif
                getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
                ++toc;
  #if defined(FEAT_LINEBREAK)
!               ve_flags = save_ve_flags;
  #endif
                // Highlight to the end of the line, unless 'virtualedit' has
                // "block".
                if (curwin->w_curswant == MAXCOL)
                {
!                   if (ve_flags & VE_BLOCK)
                    {
                        pos_T       pos;
                        int         cursor_above =
--- 2006,2026 ----
            {
                colnr_T     fromc, toc;
  #if defined(FEAT_LINEBREAK)
!               int         save_ve_flags = curbuf->b_ve_flags;
  
                if (curwin->w_p_lbr)
!                   curbuf->b_ve_flags = VE_ALL;
  #endif
                getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
                ++toc;
  #if defined(FEAT_LINEBREAK)
!               curbuf->b_ve_flags = save_ve_flags;
  #endif
                // Highlight to the end of the line, unless 'virtualedit' has
                // "block".
                if (curwin->w_curswant == MAXCOL)
                {
!                   if (get_ve_flags() & VE_BLOCK)
                    {
                        pos_T       pos;
                        int         cursor_above =
*** ../vim-8.2.3226/src/edit.c  2021-07-26 21:54:00.051491580 +0200
--- src/edit.c  2021-07-26 22:15:33.304602845 +0200
***************
*** 861,867 ****
            ins_ctrl_o();
  
            // don't move the cursor left when 'virtualedit' has "onemore".
!           if (ve_flags & VE_ONEMORE)
            {
                ins_at_eol = FALSE;
                nomove = TRUE;
--- 861,867 ----
            ins_ctrl_o();
  
            // don't move the cursor left when 'virtualedit' has "onemore".
!           if (get_ve_flags() & VE_ONEMORE)
            {
                ins_at_eol = FALSE;
                nomove = TRUE;
***************
*** 2673,2679 ****
  
      // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
      // contains "onemore".
!     if (ptr[l] == NUL && (ve_flags & VE_ONEMORE) == 0)
        return FAIL;
      curwin->w_cursor.col += l;
  
--- 2673,2679 ----
  
      // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
      // contains "onemore".
!     if (ptr[l] == NUL && (get_ve_flags() & VE_ONEMORE) == 0)
        return FAIL;
      curwin->w_cursor.col += l;
  
***************
*** 3656,3662 ****
  #endif
                                      )
      {
!       if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
        {
            oneleft();
            if (restart_edit != NUL)
--- 3656,3662 ----
  #endif
                                      )
      {
!       if (curwin->w_cursor.coladd > 0 || get_ve_flags() == VE_ALL)
        {
            oneleft();
            if (restart_edit != NUL)
*** ../vim-8.2.3226/src/misc2.c 2021-07-10 21:28:55.327050110 +0200
--- src/misc2.c 2021-07-26 22:15:33.304602845 +0200
***************
*** 22,35 ****
      int
  virtual_active(void)
  {
      // While an operator is being executed we return "virtual_op", because
      // VIsual_active has already been reset, thus we can't check for "block"
      // being used.
      if (virtual_op != MAYBE)
        return virtual_op;
!     return (ve_flags == VE_ALL
!           || ((ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == Ctrl_V)
!           || ((ve_flags & VE_INSERT) && (State & INSERT)));
  }
  
  /*
--- 22,37 ----
      int
  virtual_active(void)
  {
+     unsigned int cur_ve_flags = get_ve_flags();
+ 
      // While an operator is being executed we return "virtual_op", because
      // VIsual_active has already been reset, thus we can't check for "block"
      // being used.
      if (virtual_op != MAYBE)
        return virtual_op;
!     return (cur_ve_flags == VE_ALL
!           || ((cur_ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == 
Ctrl_V)
!           || ((cur_ve_flags & VE_INSERT) && (State & INSERT)));
  }
  
  /*
***************
*** 137,143 ****
      one_more = (State & INSERT)
                    || restart_edit != NUL
                    || (VIsual_active && *p_sel != 'o')
!                   || ((ve_flags & VE_ONEMORE) && wcol < MAXCOL);
      line = ml_get_buf(curbuf, pos->lnum, FALSE);
  
      if (wcol >= MAXCOL)
--- 139,145 ----
      one_more = (State & INSERT)
                    || restart_edit != NUL
                    || (VIsual_active && *p_sel != 'o')
!                   || ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL);
      line = ml_get_buf(curbuf, pos->lnum, FALSE);
  
      if (wcol >= MAXCOL)
***************
*** 549,557 ****
      void
  check_cursor_col_win(win_T *win)
  {
!     colnr_T len;
!     colnr_T oldcol = win->w_cursor.col;
!     colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd;
  
      len = (colnr_T)STRLEN(ml_get_buf(win->w_buffer, win->w_cursor.lnum, 
FALSE));
      if (len == 0)
--- 551,560 ----
      void
  check_cursor_col_win(win_T *win)
  {
!     colnr_T      len;
!     colnr_T      oldcol = win->w_cursor.col;
!     colnr_T      oldcoladd = win->w_cursor.col + win->w_cursor.coladd;
!     unsigned int cur_ve_flags = get_ve_flags();
  
      len = (colnr_T)STRLEN(ml_get_buf(win->w_buffer, win->w_cursor.lnum, 
FALSE));
      if (len == 0)
***************
*** 564,570 ****
        // - 'virtualedit' is set
        if ((State & INSERT) || restart_edit
                || (VIsual_active && *p_sel != 'o')
!               || (ve_flags & VE_ONEMORE)
                || virtual_active())
            win->w_cursor.col = len;
        else
--- 567,573 ----
        // - 'virtualedit' is set
        if ((State & INSERT) || restart_edit
                || (VIsual_active && *p_sel != 'o')
!               || (cur_ve_flags & VE_ONEMORE)
                || virtual_active())
            win->w_cursor.col = len;
        else
***************
*** 583,589 ****
      // line.
      if (oldcol == MAXCOL)
        win->w_cursor.coladd = 0;
!     else if (ve_flags == VE_ALL)
      {
        if (oldcoladd > win->w_cursor.col)
        {
--- 586,592 ----
      // line.
      if (oldcol == MAXCOL)
        win->w_cursor.coladd = 0;
!     else if (cur_ve_flags == VE_ALL)
      {
        if (oldcoladd > win->w_cursor.col)
        {
*** ../vim-8.2.3226/src/normal.c        2021-06-29 20:22:27.651393066 +0200
--- src/normal.c        2021-07-26 22:15:33.308602836 +0200
***************
*** 5757,5763 ****
  
      // Corner case: the 0 position in a tab may change when going into
      // virtualedit.  Recalculate curwin->w_cursor to avoid bad highlighting.
!     if (c == Ctrl_V && (ve_flags & VE_BLOCK) && gchar_cursor() == TAB)
      {
        validate_virtcol();
        coladvance(curwin->w_virtcol);
--- 5757,5763 ----
  
      // Corner case: the 0 position in a tab may change when going into
      // virtualedit.  Recalculate curwin->w_cursor to avoid bad highlighting.
!     if (c == Ctrl_V && (get_ve_flags() & VE_BLOCK) && gchar_cursor() == TAB)
      {
        validate_virtcol();
        coladvance(curwin->w_virtcol);
***************
*** 6780,6786 ****
      // - 'virtualedit' is not "all" and not "onemore".
      if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL
                && (!VIsual_active || *p_sel == 'o')
!               && !virtual_active() && (ve_flags & VE_ONEMORE) == 0)
      {
        --curwin->w_cursor.col;
        // prevent cursor from moving on the trail byte
--- 6780,6786 ----
      // - 'virtualedit' is not "all" and not "onemore".
      if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL
                && (!VIsual_active || *p_sel == 'o')
!               && !virtual_active() && (get_ve_flags() & VE_ONEMORE) == 0)
      {
        --curwin->w_cursor.col;
        // prevent cursor from moving on the trail byte
***************
*** 7014,7020 ****
  set_cursor_for_append_to_line(void)
  {
      curwin->w_set_curswant = TRUE;
!     if (ve_flags == VE_ALL)
      {
        int save_State = State;
  
--- 7014,7020 ----
  set_cursor_for_append_to_line(void)
  {
      curwin->w_set_curswant = TRUE;
!     if (get_ve_flags() == VE_ALL)
      {
        int save_State = State;
  
*** ../vim-8.2.3226/src/ops.c   2021-06-29 18:54:32.284672333 +0200
--- src/ops.c   2021-07-26 22:15:33.308602836 +0200
***************
*** 1474,1491 ****
        // doing block_prep().  When only "block" is used, virtual edit is
        // already disabled, but still need it when calling
        // coladvance_force().
        if (curwin->w_cursor.coladd > 0)
        {
!           int         old_ve_flags = ve_flags;
  
-           ve_flags = VE_ALL;
            if (u_save_cursor() == FAIL)
                return;
            coladvance_force(oap->op_type == OP_APPEND
                                           ? oap->end_vcol + 1 : getviscol());
            if (oap->op_type == OP_APPEND)
                --curwin->w_cursor.col;
!           ve_flags = old_ve_flags;
        }
        // Get the info about the block before entering the text
        block_prep(oap, &bd, oap->start.lnum, TRUE);
--- 1474,1495 ----
        // doing block_prep().  When only "block" is used, virtual edit is
        // already disabled, but still need it when calling
        // coladvance_force().
+       // coladvance_force() uses get_ve_flags() to get the 'virtualedit'
+       // state for the current buffer.  To override that state, we need to
+       // set the buffer-local value of ve_flags rather than the global value.
        if (curwin->w_cursor.coladd > 0)
        {
!           int         old_ve_flags = curbuf->b_ve_flags;
  
            if (u_save_cursor() == FAIL)
                return;
+ 
+           curbuf->b_ve_flags = VE_ALL;
            coladvance_force(oap->op_type == OP_APPEND
                                           ? oap->end_vcol + 1 : getviscol());
            if (oap->op_type == OP_APPEND)
                --curwin->w_cursor.col;
!           curbuf->b_ve_flags = old_ve_flags;
        }
        // Get the info about the block before entering the text
        block_prep(oap, &bd, oap->start.lnum, TRUE);
***************
*** 1816,1830 ****
      void
  adjust_cursor_eol(void)
  {
      if (curwin->w_cursor.col > 0
            && gchar_cursor() == NUL
!           && (ve_flags & VE_ONEMORE) == 0
            && !(restart_edit || (State & INSERT)))
      {
        // Put the cursor on the last character in the line.
        dec_cursor();
  
!       if (ve_flags == VE_ALL)
        {
            colnr_T         scol, ecol;
  
--- 1820,1836 ----
      void
  adjust_cursor_eol(void)
  {
+     unsigned int cur_ve_flags = get_ve_flags();
+ 
      if (curwin->w_cursor.col > 0
            && gchar_cursor() == NUL
!           && (cur_ve_flags & VE_ONEMORE) == 0
            && !(restart_edit || (State & INSERT)))
      {
        // Put the cursor on the last character in the line.
        dec_cursor();
  
!       if (cur_ve_flags == VE_ALL)
        {
            colnr_T         scol, ecol;
  
*** ../vim-8.2.3226/src/option.c        2021-07-21 22:20:30.066401728 +0200
--- src/option.c        2021-07-26 22:15:33.308602836 +0200
***************
*** 5181,5186 ****
--- 5181,5190 ----
            set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs);
            redraw_later(NOT_VALID);
            break;
+       case PV_VE:
+           clear_string_option(&buf->b_p_ve);
+           buf->b_ve_flags = 0;
+           break;
      }
  }
  #endif
***************
*** 5239,5245 ****
  #endif
            case PV_BKC:  return (char_u *)&(curbuf->b_p_bkc);
            case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
!           case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
  
        }
        return NULL; // "cannot happen"
--- 5243,5250 ----
  #endif
            case PV_BKC:  return (char_u *)&(curbuf->b_p_bkc);
            case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
!           case PV_LCS:  return (char_u *)&(curwin->w_p_lcs);
!           case PV_VE:   return (char_u *)&(curbuf->b_p_ve);
  
        }
        return NULL; // "cannot happen"
***************
*** 5507,5512 ****
--- 5512,5519 ----
        case PV_VSTS:   return (char_u *)&(curbuf->b_p_vsts);
        case PV_VTS:    return (char_u *)&(curbuf->b_p_vts);
  #endif
+       case PV_VE:     return *curbuf->b_p_ve != NUL
+                                   ? (char_u *)&(curbuf->b_p_ve) : p->var;
        default:        iemsg(_("E356: get_varp ERROR"));
      }
      // always return a valid pointer to avoid a crash!
***************
*** 6084,6089 ****
--- 6091,6098 ----
            buf->b_p_lw = empty_option;
  #endif
            buf->b_p_menc = empty_option;
+           buf->b_p_ve = empty_option;
+           buf->b_ve_flags = 0;
  
            /*
             * Don't copy the options set by ex_help(), use the saved values,
***************
*** 7026,7031 ****
--- 7035,7050 ----
      return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
  }
  
+ /*
+  * Get the local or global value of the 'virtualedit' flags.
+  */
+     unsigned int
+ get_ve_flags(void)
+ {
+     return (curbuf->b_ve_flags ? curbuf->b_ve_flags : ve_flags)
+          & ~(VE_NONE | VE_NONEU);
+ }
+ 
  #if defined(FEAT_LINEBREAK) || defined(PROTO)
  /*
   * Get the local or global value of 'showbreak'.
*** ../vim-8.2.3226/src/option.h        2021-05-30 18:04:14.714468918 +0200
--- src/option.h        2021-07-26 22:15:33.308602836 +0200
***************
*** 1052,1057 ****
--- 1052,1059 ----
  #define VE_INSERT     6       // includes "all"
  #define VE_ALL                4
  #define VE_ONEMORE    8
+ #define VE_NONE               16
+ #define VE_NONEU      32      // Upper-case NONE
  EXTERN long   p_verbose;      // 'verbose'
  #ifdef IN_OPTION_C
  char_u        *p_vfile = (char_u *)""; // used before options are initialized
***************
*** 1228,1233 ****
--- 1230,1236 ----
      , BV_VSTS
      , BV_VTS
  #endif
+     , BV_VE
      , BV_COUNT            // must be the last one
  };
  
*** ../vim-8.2.3226/src/optiondefs.h    2021-06-02 13:28:11.435120452 +0200
--- src/optiondefs.h    2021-07-26 22:15:33.308602836 +0200
***************
*** 153,158 ****
--- 153,159 ----
  # define PV_VSTS              OPT_BUF(BV_VSTS)
  # define PV_VTS               OPT_BUF(BV_VTS)
  #endif
+ #define PV_VE         OPT_BOTH(OPT_BUF(BV_VE))
  
  // Definition of the PV_ values for window-local options.
  // The WV_ values are defined in option.h.
***************
*** 2806,2812 ****
                            SCTX_INIT},
      {"virtualedit", "ve",   P_STRING|P_ONECOMMA|P_NODUP|P_VI_DEF
                                                            |P_VIM|P_CURSWANT,
!                           (char_u *)&p_ve, PV_NONE,
                            {(char_u *)"", (char_u *)""}
                            SCTX_INIT},
      {"visualbell",  "vb",   P_BOOL|P_VI_DEF,
--- 2807,2813 ----
                            SCTX_INIT},
      {"virtualedit", "ve",   P_STRING|P_ONECOMMA|P_NODUP|P_VI_DEF
                                                            |P_VIM|P_CURSWANT,
!                           (char_u *)&p_ve, PV_VE,
                            {(char_u *)"", (char_u *)""}
                            SCTX_INIT},
      {"visualbell",  "vb",   P_BOOL|P_VI_DEF,
*** ../vim-8.2.3226/src/optionstr.c     2021-06-27 22:03:28.645707721 +0200
--- src/optionstr.c     2021-07-26 22:15:33.308602836 +0200
***************
*** 56,62 ****
  #if defined(UNIX) || defined(VMS)
  static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", 
"jsbterm", "pterm", "urxvt", "sgr", NULL};
  #endif
! static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", NULL};
  static char *(p_wop_values[]) = {"tagfile", NULL};
  #ifdef FEAT_WAK
  static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
--- 56,62 ----
  #if defined(UNIX) || defined(VMS)
  static char *(p_ttym_values[]) = {"xterm", "xterm2", "dec", "netterm", 
"jsbterm", "pterm", "urxvt", "sgr", NULL};
  #endif
! static char *(p_ve_values[]) = {"block", "insert", "all", "onemore", "none", 
"NONE", NULL};
  static char *(p_wop_values[]) = {"tagfile", NULL};
  #ifdef FEAT_WAK
  static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
***************
*** 298,303 ****
--- 298,304 ----
      check_string_option(&buf->b_p_vsts);
      check_string_option(&buf->b_p_vts);
  #endif
+     check_string_option(&buf->b_p_ve);
  }
  
  /*
***************
*** 2075,2090 ****
  #endif
  
      // 'virtualedit'
!     else if (varp == &p_ve)
      {
!       if (opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE) != OK)
!           errmsg = e_invarg;
!       else if (STRCMP(p_ve, oldval) != 0)
        {
!           // Recompute cursor position in case the new 've' setting
!           // changes something.
!           validate_virtcol();
!           coladvance(curwin->w_virtcol);
        }
      }
  
--- 2076,2106 ----
  #endif
  
      // 'virtualedit'
!     else if (gvarp == &p_ve)
      {
!       char_u          *ve = p_ve;
!       unsigned int    *flags = &ve_flags;
! 
!       if (opt_flags & OPT_LOCAL)
!       {
!           ve = curbuf->b_p_ve;
!           flags = &curbuf->b_ve_flags;
!       }
! 
!       if ((opt_flags & OPT_LOCAL) && *ve == NUL)
!           // make the local value empty: use the global value
!           *flags = 0;
!       else
        {
!           if (opt_strings_flags(ve, p_ve_values, flags, TRUE) != OK)
!               errmsg = e_invarg;
!           else if (STRCMP(p_ve, oldval) != 0)
!           {
!               // Recompute cursor position in case the new 've' setting
!               // changes something.
!               validate_virtcol();
!               coladvance(curwin->w_virtcol);
!           }
        }
      }
  
*** ../vim-8.2.3226/src/proto/option.pro        2021-06-13 20:27:32.889357660 
+0200
--- src/proto/option.pro        2021-07-26 22:15:33.308602836 +0200
***************
*** 73,78 ****
--- 73,79 ----
  long get_scrolloff_value(void);
  long get_sidescrolloff_value(void);
  unsigned int get_bkc_value(buf_T *buf);
+ unsigned int get_ve_flags(void);
  char_u *get_showbreak_value(win_T *win);
  dict_T *get_winbuf_options(int bufopt);
  int fill_culopt_flags(char_u *val, win_T *wp);
*** ../vim-8.2.3226/src/register.c      2021-07-20 21:07:32.968058851 +0200
--- src/register.c      2021-07-26 22:15:33.308602836 +0200
***************
*** 1556,1561 ****
--- 1556,1562 ----
      long      cnt;
      pos_T     orig_start = curbuf->b_op_start;
      pos_T     orig_end = curbuf->b_op_end;
+     unsigned int cur_ve_flags = get_ve_flags();
  
  #ifdef FEAT_CLIPBOARD
      // Adjust register name for "unnamed" in 'clipboard'.
***************
*** 1742,1748 ****
  
      yanklen = (int)STRLEN(y_array[0]);
  
!     if (ve_flags == VE_ALL && y_type == MCHAR)
      {
        if (gchar_cursor() == TAB)
        {
--- 1743,1749 ----
  
      yanklen = (int)STRLEN(y_array[0]);
  
!     if (cur_ve_flags == VE_ALL && y_type == MCHAR)
      {
        if (gchar_cursor() == TAB)
        {
***************
*** 1777,1783 ****
  
        if (dir == FORWARD && c != NUL)
        {
!           if (ve_flags == VE_ALL)
                getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
            else
                getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
--- 1778,1784 ----
  
        if (dir == FORWARD && c != NUL)
        {
!           if (cur_ve_flags == VE_ALL)
                getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
            else
                getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
***************
*** 1786,1792 ****
                // move to start of next multi-byte character
                curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
            else
!           if (c != TAB || ve_flags != VE_ALL)
                ++curwin->w_cursor.col;
            ++col;
        }
--- 1787,1793 ----
                // move to start of next multi-byte character
                curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
            else
!           if (c != TAB || cur_ve_flags != VE_ALL)
                ++curwin->w_cursor.col;
            ++col;
        }
***************
*** 1794,1800 ****
            getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
  
        col += curwin->w_cursor.coladd;
!       if (ve_flags == VE_ALL
                && (curwin->w_cursor.coladd > 0
                    || endcol2 == curwin->w_cursor.col))
        {
--- 1795,1801 ----
            getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
  
        col += curwin->w_cursor.coladd;
!       if (cur_ve_flags == VE_ALL
                && (curwin->w_cursor.coladd > 0
                    || endcol2 == curwin->w_cursor.col))
        {
*** ../vim-8.2.3226/src/structs.h       2021-07-25 14:13:50.040566339 +0200
--- src/structs.h       2021-07-26 22:15:33.308602836 +0200
***************
*** 2969,2974 ****
--- 2969,2976 ----
  #ifdef FEAT_TERMINAL
      long      b_p_twsl;       // 'termwinscroll'
  #endif
+     char_u    *b_p_ve;        // 'virtualedit' local value
+     unsigned  b_ve_flags;     // flags for 'virtualedit'
  
      /*
       * end of buffer options
*** ../vim-8.2.3226/src/testdir/test_virtualedit.vim    2021-05-29 
16:30:08.674611431 +0200
--- src/testdir/test_virtualedit.vim    2021-07-26 22:15:33.308602836 +0200
***************
*** 402,405 ****
--- 402,525 ----
    bw!
  endfunc
  
+ " After calling s:TryVirtualeditReplace(), line 1 will contain one of these
+ " two strings, depending on whether virtual editing is on or off.
+ let s:result_ve_on  = 'a      x'
+ let s:result_ve_off = 'x'
+ 
+ " Utility function for Test_global_local()
+ func s:TryVirtualeditReplace()
+   call setline(1, 'a')
+   normal gg7l
+   normal rx
+ endfunc
+ 
+ " Test for :set and :setlocal
+ func Test_global_local()
+   new
+ 
+   " Verify that 'virtualedit' is initialized to empty, can be set globally to
+   " all and to empty, and can be set locally to all and to empty.
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+   set ve=all
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   set ve=
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+   setlocal ve=all
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   setlocal ve=
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+ 
+   " Verify that :set affects multiple buffers
+   new
+   set ve=all
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   wincmd p
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   set ve=
+   wincmd p
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+   bwipe!
+ 
+   " Verify that :setlocal affects only the current buffer
+   setlocal ve=all
+   new
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+   setlocal ve=all
+   wincmd p
+   setlocal ve=
+   wincmd p
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   bwipe!
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+ 
+   " Verify that the buffer 'virtualedit' state follows the global value only
+   " when empty and that "none" works as expected.
+   "
+   "          'virtualedit' State
+   " +--------+--------------------------+
+   " | Local  |          Global          |
+   " |        |                          |
+   " +--------+--------+--------+--------+
+   " |        | ""     | "all"  | "none" |
+   " +--------+--------+--------+--------+
+   " | ""     |  off   |  on    |  off   |
+   " | "all"  |  on    |  on    |  on    |
+   " | "none" |  off   |  off   |  off   |
+   " +--------+--------+--------+--------+
+   new
+ 
+   setglobal ve=
+   setlocal ve=
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+   setlocal ve=all
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   setlocal ve=none
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+ 
+   setglobal ve=all
+   setlocal ve=
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   setlocal ve=all
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   setlocal ve=none
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+   setlocal ve=NONE
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+ 
+   setglobal ve=none
+   setlocal ve=
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+   setlocal ve=all
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_on, getline(1))
+   setlocal ve=none
+   call s:TryVirtualeditReplace()
+   call assert_equal(s:result_ve_off, getline(1))
+ 
+   bwipe!
+ 
+   setlocal virtualedit&
+   set virtualedit&
+ endfunc
+ 
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.3226/src/version.c       2021-07-26 21:54:00.055491571 +0200
--- src/version.c       2021-07-26 22:17:27.816343578 +0200
***************
*** 757,758 ****
--- 757,760 ----
  {   /* Add new patch number below this line */
+ /**/
+     3227,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
244. You use more than 20 passwords.

 /// 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/202107262019.16QKJjib1417655%40masaka.moolenaar.net.

Raspunde prin e-mail lui