patch 8.2.3280: 'virtualedit' local to buffer is not the best solution

Problem:    'virtualedit' local to buffer is not the best solution.
Solution:   Make it window-local. (Gary Johnson, closes #8685)
diff --git a/src/buffer.c b/src/buffer.c
index 628c82f..bc3378a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2388,7 +2388,6 @@
 #endif
     clear_string_option(&buf->b_p_bkc);
     clear_string_option(&buf->b_p_menc);
-    clear_string_option(&buf->b_p_ve);
 }
 
 /*
diff --git a/src/drawscreen.c b/src/drawscreen.c
index 36aad63..82e5375 100644
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -2006,15 +2006,15 @@
 	    {
 		colnr_T	    fromc, toc;
 #if defined(FEAT_LINEBREAK)
-		int	    save_ve_flags = curbuf->b_ve_flags;
+		int	    save_ve_flags = curwin->w_ve_flags;
 
 		if (curwin->w_p_lbr)
-		    curbuf->b_ve_flags = VE_ALL;
+		    curwin->w_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;
+		curwin->w_ve_flags = save_ve_flags;
 #endif
 		// Highlight to the end of the line, unless 'virtualedit' has
 		// "block".
diff --git a/src/ops.c b/src/ops.c
index 75619c5..614ada5 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -1475,21 +1475,21 @@
 	// 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.
+	// state for the current window.  To override that state, we need to
+	// set the window-local value of ve_flags rather than the global value.
 	if (curwin->w_cursor.coladd > 0)
 	{
-	    int		old_ve_flags = curbuf->b_ve_flags;
+	    int		old_ve_flags = curwin->w_ve_flags;
 
 	    if (u_save_cursor() == FAIL)
 		return;
 
-	    curbuf->b_ve_flags = VE_ALL;
+	    curwin->w_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;
+	    curwin->w_ve_flags = old_ve_flags;
 	}
 	// Get the info about the block before entering the text
 	block_prep(oap, &bd, oap->start.lnum, TRUE);
diff --git a/src/option.c b/src/option.c
index decba50..4e0e5a6 100644
--- a/src/option.c
+++ b/src/option.c
@@ -5182,8 +5182,8 @@
 	    redraw_later(NOT_VALID);
 	    break;
 	case PV_VE:
-	    clear_string_option(&buf->b_p_ve);
-	    buf->b_ve_flags = 0;
+	    clear_string_option(&((win_T *)from)->w_p_ve);
+	    ((win_T *)from)->w_ve_flags = 0;
 	    break;
     }
 }
@@ -5244,7 +5244,7 @@
 	    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);
+	    case PV_VE:	  return (char_u *)&(curwin->w_p_ve);
 
 	}
 	return NULL; // "cannot happen"
@@ -5345,6 +5345,8 @@
 	case PV_LIST:	return (char_u *)&(curwin->w_p_list);
 	case PV_LCS:	return *curwin->w_p_lcs != NUL
 				    ? (char_u *)&(curwin->w_p_lcs) : p->var;
+	case PV_VE:	return *curwin->w_p_ve != NUL
+				    ? (char_u *)&(curwin->w_p_ve) : p->var;
 #ifdef FEAT_SPELL
 	case PV_SPELL:	return (char_u *)&(curwin->w_p_spell);
 #endif
@@ -5512,8 +5514,6 @@
 	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!
@@ -5593,6 +5593,8 @@
     to->wo_lcs = vim_strsave(from->wo_lcs);
     to->wo_nu = from->wo_nu;
     to->wo_rnu = from->wo_rnu;
+    to->wo_ve = vim_strsave(from->wo_ve);
+    to->wo_ve_flags = from->wo_ve_flags;
 #ifdef FEAT_LINEBREAK
     to->wo_nuw = from->wo_nuw;
 #endif
@@ -5726,6 +5728,7 @@
 #endif
     check_string_option(&wop->wo_wcr);
     check_string_option(&wop->wo_lcs);
+    check_string_option(&wop->wo_ve);
 }
 
 /*
@@ -5772,6 +5775,7 @@
     clear_string_option(&wop->wo_tws);
 #endif
     clear_string_option(&wop->wo_lcs);
+    clear_string_option(&wop->wo_ve);
 }
 
 #ifdef FEAT_EVAL
@@ -6091,8 +6095,6 @@
 	    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,
@@ -7041,8 +7043,8 @@
     unsigned int
 get_ve_flags(void)
 {
-    return (curbuf->b_ve_flags ? curbuf->b_ve_flags : ve_flags)
-	   & ~(VE_NONE | VE_NONEU);
+    return (curwin->w_ve_flags ? curwin->w_ve_flags : ve_flags)
+	    & ~(VE_NONE | VE_NONEU);
 }
 
 #if defined(FEAT_LINEBREAK) || defined(PROTO)
diff --git a/src/option.h b/src/option.h
index 5732e82..48a3ec3 100644
--- a/src/option.h
+++ b/src/option.h
@@ -1052,8 +1052,8 @@
 #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
+#define VE_NONE		16	// "none"
+#define VE_NONEU	32      // "NONE"
 EXTERN long	p_verbose;	// 'verbose'
 #ifdef IN_OPTION_C
 char_u	*p_vfile = (char_u *)""; // used before options are initialized
diff --git a/src/optionstr.c b/src/optionstr.c
index c22a441..a394d8d 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -298,7 +298,6 @@
     check_string_option(&buf->b_p_vsts);
     check_string_option(&buf->b_p_vts);
 #endif
-    check_string_option(&buf->b_p_ve);
 }
 
 /*
@@ -2083,8 +2082,8 @@
 
 	if (opt_flags & OPT_LOCAL)
 	{
-	    ve = curbuf->b_p_ve;
-	    flags = &curbuf->b_ve_flags;
+	    ve = curwin->w_p_ve;
+	    flags = &curwin->w_ve_flags;
 	}
 
 	if ((opt_flags & OPT_LOCAL) && *ve == NUL)
diff --git a/src/structs.h b/src/structs.h
index 09f0703..0418be9 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -231,6 +231,10 @@
 #define w_p_nu w_onebuf_opt.wo_nu	// 'number'
     int		wo_rnu;
 #define w_p_rnu w_onebuf_opt.wo_rnu	// 'relativenumber'
+    char_u	*wo_ve;
+#define w_p_ve w_onebuf_opt.wo_ve	// 'virtualedit'
+    unsigned	wo_ve_flags;
+#define	w_ve_flags w_onebuf_opt.wo_ve_flags	// flags for 'virtualedit'
 #ifdef FEAT_LINEBREAK
     long	wo_nuw;
 # define w_p_nuw w_onebuf_opt.wo_nuw	// 'numberwidth'
@@ -2969,8 +2973,6 @@
 #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
diff --git a/src/testdir/test_virtualedit.vim b/src/testdir/test_virtualedit.vim
index f3cc260..b31f3a2 100644
--- a/src/testdir/test_virtualedit.vim
+++ b/src/testdir/test_virtualedit.vim
@@ -407,7 +407,7 @@
 let s:result_ve_on  = 'a      x'
 let s:result_ve_off = 'x'
 
-" Utility function for Test_global_local()
+" Utility function for Test_global_local_virtualedit()
 func s:TryVirtualeditReplace()
   call setline(1, 'a')
   normal gg7l
@@ -415,7 +415,7 @@
 endfunc
 
 " Test for :set and :setlocal
-func Test_global_local()
+func Test_global_local_virtualedit()
   new
 
   " Verify that 'virtualedit' is initialized to empty, can be set globally to
@@ -435,8 +435,8 @@
   call s:TryVirtualeditReplace()
   call assert_equal(s:result_ve_off, getline(1))
 
-  " Verify that :set affects multiple buffers
-  new
+  " Verify that :set affects multiple windows.
+  split
   set ve=all
   call s:TryVirtualeditReplace()
   call assert_equal(s:result_ve_on, getline(1))
@@ -449,17 +449,15 @@
   call assert_equal(s:result_ve_off, getline(1))
   bwipe!
 
-  " Verify that :setlocal affects only the current buffer
-  setlocal ve=all
+  " Verify that :setlocal affects only the current window.
   new
-  call s:TryVirtualeditReplace()
-  call assert_equal(s:result_ve_off, getline(1))
+  split
   setlocal ve=all
-  wincmd p
-  setlocal ve=
-  wincmd p
   call s:TryVirtualeditReplace()
   call assert_equal(s:result_ve_on, getline(1))
+  wincmd p
+  call s:TryVirtualeditReplace()
+  call assert_equal(s:result_ve_off, getline(1))
   bwipe!
   call s:TryVirtualeditReplace()
   call assert_equal(s:result_ve_off, getline(1))
@@ -518,6 +516,23 @@
 
   bwipe!
 
+  " Verify that the 'virtualedit' state is copied to new windows.
+  new
+  call s:TryVirtualeditReplace()
+  call assert_equal(s:result_ve_off, getline(1))
+  split
+  setlocal ve=all
+  call s:TryVirtualeditReplace()
+  call assert_equal(s:result_ve_on, getline(1))
+  split
+  call s:TryVirtualeditReplace()
+  call assert_equal(s:result_ve_on, getline(1))
+  setlocal ve=
+  split
+  call s:TryVirtualeditReplace()
+  call assert_equal(s:result_ve_off, getline(1))
+  bwipe!
+
   setlocal virtualedit&
   set virtualedit&
 endfunc
diff --git a/src/version.c b/src/version.c
index 69df671..32403f4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3280,
+/**/
     3279,
 /**/
     3278,