changeset 25487:c26ff3203b43 v8.2.3280

patch 8.2.3280: 'virtualedit' local to buffer is not the best solution Commit: https://github.com/vim/vim/commit/51ad850f5fbafa7aa3f60affa74ec9c9f992c6cc Author: Gary Johnson <garyjohn@spocom.com> Date: Tue Aug 3 18:33:08 2021 +0200 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 https://github.com/vim/vim/issues/8685)
author Bram Moolenaar <Bram@vim.org>
date Tue, 03 Aug 2021 18:45:04 +0200
parents 9ca6ec7da094
children fbe646778e21
files runtime/doc/options.txt src/buffer.c src/drawscreen.c src/ops.c src/option.c src/option.h src/optionstr.c src/structs.h src/testdir/test_virtualedit.vim src/version.c
diffstat 10 files changed, 57 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -8643,7 +8643,7 @@ A jump table for the options with a shor
 
 					    *'virtualedit'* *'ve'*
 'virtualedit' 've'	string	(default "")
-			global or local to buffer |global-local|
+			global or local to window |global-local|
 	A comma separated list of these words:
 	    block	Allow virtual editing in Visual block mode.
 	    insert	Allow virtual editing in Insert mode.
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2388,7 +2388,6 @@ free_buf_options(
 #endif
     clear_string_option(&buf->b_p_bkc);
     clear_string_option(&buf->b_p_menc);
-    clear_string_option(&buf->b_p_ve);
 }
 
 /*
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -2006,15 +2006,15 @@ win_update(win_T *wp)
 	    {
 		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".
--- a/src/ops.c
+++ b/src/ops.c
@@ -1475,21 +1475,21 @@ op_insert(oparg_T *oap, long count1)
 	// 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);
--- a/src/option.c
+++ b/src/option.c
@@ -5182,8 +5182,8 @@ unset_global_local_option(char_u *name, 
 	    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 @@ get_varp_scope(struct vimoption *p, int 
 	    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 @@ get_varp(struct vimoption *p)
 	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 @@ get_varp(struct vimoption *p)
 	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 @@ copy_winopt(winopt_T *from, winopt_T *to
     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 @@ check_winopt(winopt_T *wop UNUSED)
 #endif
     check_string_option(&wop->wo_wcr);
     check_string_option(&wop->wo_lcs);
+    check_string_option(&wop->wo_ve);
 }
 
 /*
@@ -5772,6 +5775,7 @@ clear_winopt(winopt_T *wop UNUSED)
     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_copy_options(buf_T *buf, int flags)
 	    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 @@ get_bkc_value(buf_T *buf)
     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)
--- a/src/option.h
+++ b/src/option.h
@@ -1052,8 +1052,8 @@ EXTERN unsigned ve_flags;
 #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
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -298,7 +298,6 @@ check_buf_options(buf_T *buf)
     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 @@ ambw_end:
 
 	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)
--- a/src/structs.h
+++ b/src/structs.h
@@ -231,6 +231,10 @@ typedef struct
 #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 @@ struct file_buffer
 #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
--- a/src/testdir/test_virtualedit.vim
+++ b/src/testdir/test_virtualedit.vim
@@ -407,7 +407,7 @@ endfunc
 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 @@ func s:TryVirtualeditReplace()
 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 @@ func Test_global_local()
   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 @@ func Test_global_local()
   call assert_equal(s:result_ve_off, getline(1))
   bwipe!
 
-  " Verify that :setlocal affects only the current buffer
+  " Verify that :setlocal affects only the current window.
+  new
+  split
   setlocal ve=all
-  new
+  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))
-  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))
@@ -518,6 +516,23 @@ func Test_global_local()
 
   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
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3280,
+/**/
     3279,
 /**/
     3278,