# HG changeset patch # User Bram Moolenaar # Date 1628009104 -7200 # Node ID c26ff3203b43ee83030e5ef8b075e1a662b90584 # Parent 9ca6ec7da094ce0f8b88d708d774a3d44aab1663 patch 8.2.3280: 'virtualedit' local to buffer is not the best solution Commit: https://github.com/vim/vim/commit/51ad850f5fbafa7aa3f60affa74ec9c9f992c6cc Author: Gary Johnson 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) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- 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. diff --git a/src/buffer.c b/src/buffer.c --- 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); } /* diff --git a/src/drawscreen.c b/src/drawscreen.c --- 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". diff --git a/src/ops.c b/src/ops.c --- 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); diff --git a/src/option.c b/src/option.c --- 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) diff --git a/src/option.h b/src/option.h --- 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 diff --git a/src/optionstr.c b/src/optionstr.c --- 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) diff --git a/src/structs.h b/src/structs.h --- 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 diff --git a/src/testdir/test_virtualedit.vim b/src/testdir/test_virtualedit.vim --- 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 diff --git a/src/version.c b/src/version.c --- 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,