diff options
author | Gary Johnson <garyjohn@spocom.com> | 2021-07-26 22:19:10 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2021-07-26 22:19:10 +0200 |
commit | 53ba05b09075f14227f9be831a22ed16f7cc26b2 (patch) | |
tree | 75d5ddb38aa9702416d73b7a7b8f158f1d0c320a /src | |
parent | 29b857150c111a455f1a38a8f748243524f692e1 (diff) | |
download | vim-git-53ba05b09075f14227f9be831a22ed16f7cc26b2.tar.gz |
patch 8.2.3227: 'virtualedit' can only be set globallyv8.2.3227
Problem: 'virtualedit' can only be set globally.
Solution: Make 'virtualedit' global-local. (Gary Johnson, closes #8638)
Diffstat (limited to 'src')
-rw-r--r-- | src/buffer.c | 1 | ||||
-rw-r--r-- | src/change.c | 2 | ||||
-rw-r--r-- | src/drawscreen.c | 8 | ||||
-rw-r--r-- | src/edit.c | 6 | ||||
-rw-r--r-- | src/misc2.c | 21 | ||||
-rw-r--r-- | src/normal.c | 6 | ||||
-rw-r--r-- | src/ops.c | 16 | ||||
-rw-r--r-- | src/option.c | 21 | ||||
-rw-r--r-- | src/option.h | 3 | ||||
-rw-r--r-- | src/optiondefs.h | 3 | ||||
-rw-r--r-- | src/optionstr.c | 34 | ||||
-rw-r--r-- | src/proto/option.pro | 1 | ||||
-rw-r--r-- | src/register.c | 9 | ||||
-rw-r--r-- | src/structs.h | 2 | ||||
-rw-r--r-- | src/testdir/test_virtualedit.vim | 120 | ||||
-rw-r--r-- | src/version.c | 2 |
16 files changed, 215 insertions, 40 deletions
diff --git a/src/buffer.c b/src/buffer.c index 25efea1f3..59397e4a5 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -2384,6 +2384,7 @@ 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/change.c b/src/change.c index ee1bd6fca..f77b48c74 100644 --- a/src/change.c +++ b/src/change.c @@ -1257,7 +1257,7 @@ del_bytes( // 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) + && (get_ve_flags() & VE_ONEMORE) == 0) { --curwin->w_cursor.col; curwin->w_cursor.coladd = 0; diff --git a/src/drawscreen.c b/src/drawscreen.c index 49615bda6..36aad637b 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -2006,21 +2006,21 @@ win_update(win_T *wp) { colnr_T fromc, toc; #if defined(FEAT_LINEBREAK) - int save_ve_flags = ve_flags; + int save_ve_flags = curbuf->b_ve_flags; if (curwin->w_p_lbr) - ve_flags = VE_ALL; + curbuf->b_ve_flags = VE_ALL; #endif getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc); ++toc; #if defined(FEAT_LINEBREAK) - ve_flags = save_ve_flags; + 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 (ve_flags & VE_BLOCK) + if (get_ve_flags() & VE_BLOCK) { pos_T pos; int cursor_above = diff --git a/src/edit.c b/src/edit.c index 267c76d31..6bdeded00 100644 --- a/src/edit.c +++ b/src/edit.c @@ -861,7 +861,7 @@ doESCkey: ins_ctrl_o(); // don't move the cursor left when 'virtualedit' has "onemore". - if (ve_flags & VE_ONEMORE) + if (get_ve_flags() & VE_ONEMORE) { ins_at_eol = FALSE; nomove = TRUE; @@ -2673,7 +2673,7 @@ oneright(void) // 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) + if (ptr[l] == NUL && (get_ve_flags() & VE_ONEMORE) == 0) return FAIL; curwin->w_cursor.col += l; @@ -3656,7 +3656,7 @@ ins_esc( #endif ) { - if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL) + if (curwin->w_cursor.coladd > 0 || get_ve_flags() == VE_ALL) { oneleft(); if (restart_edit != NUL) diff --git a/src/misc2.c b/src/misc2.c index a8e34df7e..8e99b01a5 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -22,14 +22,16 @@ static int coladvance2(pos_T *pos, int addspaces, int finetune, colnr_T wcol); 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 (ve_flags == VE_ALL - || ((ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == Ctrl_V) - || ((ve_flags & VE_INSERT) && (State & INSERT))); + 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,7 +139,7 @@ coladvance2( one_more = (State & INSERT) || restart_edit != NUL || (VIsual_active && *p_sel != 'o') - || ((ve_flags & VE_ONEMORE) && wcol < MAXCOL); + || ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL); line = ml_get_buf(curbuf, pos->lnum, FALSE); if (wcol >= MAXCOL) @@ -549,9 +551,10 @@ check_cursor_col(void) 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; + 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,7 +567,7 @@ check_cursor_col_win(win_T *win) // - 'virtualedit' is set if ((State & INSERT) || restart_edit || (VIsual_active && *p_sel != 'o') - || (ve_flags & VE_ONEMORE) + || (cur_ve_flags & VE_ONEMORE) || virtual_active()) win->w_cursor.col = len; else @@ -583,7 +586,7 @@ check_cursor_col_win(win_T *win) // line. if (oldcol == MAXCOL) win->w_cursor.coladd = 0; - else if (ve_flags == VE_ALL) + else if (cur_ve_flags == VE_ALL) { if (oldcoladd > win->w_cursor.col) { diff --git a/src/normal.c b/src/normal.c index 56f89f518..74c76b2d2 100644 --- a/src/normal.c +++ b/src/normal.c @@ -5757,7 +5757,7 @@ n_start_visual_mode(int c) // 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) + if (c == Ctrl_V && (get_ve_flags() & VE_BLOCK) && gchar_cursor() == TAB) { validate_virtcol(); coladvance(curwin->w_virtcol); @@ -6780,7 +6780,7 @@ adjust_cursor(oparg_T *oap) // - '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) + && !virtual_active() && (get_ve_flags() & VE_ONEMORE) == 0) { --curwin->w_cursor.col; // prevent cursor from moving on the trail byte @@ -7014,7 +7014,7 @@ nv_esc(cmdarg_T *cap) set_cursor_for_append_to_line(void) { curwin->w_set_curswant = TRUE; - if (ve_flags == VE_ALL) + if (get_ve_flags() == VE_ALL) { int save_State = State; @@ -1474,18 +1474,22 @@ op_insert(oparg_T *oap, long count1) // 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 = ve_flags; + int old_ve_flags = curbuf->b_ve_flags; - ve_flags = VE_ALL; 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; - ve_flags = old_ve_flags; + 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,15 +1820,17 @@ op_change(oparg_T *oap) void adjust_cursor_eol(void) { + unsigned int cur_ve_flags = get_ve_flags(); + if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL - && (ve_flags & VE_ONEMORE) == 0 + && (cur_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) + if (cur_ve_flags == VE_ALL) { colnr_T scol, ecol; diff --git a/src/option.c b/src/option.c index 21d113e27..182ff341c 100644 --- a/src/option.c +++ b/src/option.c @@ -5181,6 +5181,10 @@ unset_global_local_option(char_u *name, void *from) 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,7 +5243,8 @@ get_varp_scope(struct vimoption *p, int opt_flags) #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_LCS: return (char_u *)&(curwin->w_p_lcs); + case PV_VE: return (char_u *)&(curbuf->b_p_ve); } return NULL; // "cannot happen" @@ -5507,6 +5512,8 @@ 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! @@ -6084,6 +6091,8 @@ 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, @@ -7026,6 +7035,16 @@ get_bkc_value(buf_T *buf) 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'. diff --git a/src/option.h b/src/option.h index 7be729a85..5732e8256 100644 --- a/src/option.h +++ b/src/option.h @@ -1052,6 +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 EXTERN long p_verbose; // 'verbose' #ifdef IN_OPTION_C char_u *p_vfile = (char_u *)""; // used before options are initialized @@ -1228,6 +1230,7 @@ enum , BV_VSTS , BV_VTS #endif + , BV_VE , BV_COUNT // must be the last one }; diff --git a/src/optiondefs.h b/src/optiondefs.h index 782e4ef44..ec89558f1 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -153,6 +153,7 @@ # 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,7 +2807,7 @@ static struct vimoption options[] = 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 *)&p_ve, PV_VE, {(char_u *)"", (char_u *)""} SCTX_INIT}, {"visualbell", "vb", P_BOOL|P_VI_DEF, diff --git a/src/optionstr.c b/src/optionstr.c index 4c1cacc5c..c22a441ff 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -56,7 +56,7 @@ static char *(p_tbis_values[]) = {"tiny", "small", "medium", "large", "huge", "g #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_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,6 +298,7 @@ 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); } /* @@ -2075,16 +2076,31 @@ ambw_end: #endif // 'virtualedit' - else if (varp == &p_ve) + else if (gvarp == &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) + 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 { - // Recompute cursor position in case the new 've' setting - // changes something. - validate_virtcol(); - coladvance(curwin->w_virtcol); + 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); + } } } diff --git a/src/proto/option.pro b/src/proto/option.pro index 25cfb6541..13b9c1b7e 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -73,6 +73,7 @@ int can_bs(int what); 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); diff --git a/src/register.c b/src/register.c index 0c714c69c..161587423 100644 --- a/src/register.c +++ b/src/register.c @@ -1556,6 +1556,7 @@ do_put( 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,7 +1743,7 @@ do_put( yanklen = (int)STRLEN(y_array[0]); - if (ve_flags == VE_ALL && y_type == MCHAR) + if (cur_ve_flags == VE_ALL && y_type == MCHAR) { if (gchar_cursor() == TAB) { @@ -1777,7 +1778,7 @@ do_put( if (dir == FORWARD && c != NUL) { - if (ve_flags == VE_ALL) + if (cur_ve_flags == VE_ALL) getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2); else getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); @@ -1786,7 +1787,7 @@ do_put( // 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) + if (c != TAB || cur_ve_flags != VE_ALL) ++curwin->w_cursor.col; ++col; } @@ -1794,7 +1795,7 @@ do_put( getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2); col += curwin->w_cursor.coladd; - if (ve_flags == VE_ALL + if (cur_ve_flags == VE_ALL && (curwin->w_cursor.coladd > 0 || endcol2 == curwin->w_cursor.col)) { diff --git a/src/structs.h b/src/structs.h index bf8102cd7..09f07030c 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2969,6 +2969,8 @@ 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 index 7f6e08c7c..f3cc26025 100644 --- a/src/testdir/test_virtualedit.vim +++ b/src/testdir/test_virtualedit.vim @@ -402,4 +402,124 @@ func Test_delete_past_eol() 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 diff --git a/src/version.c b/src/version.c index 0d60cc223..cdf5d4e4e 100644 --- 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 */ /**/ + 3227, +/**/ 3226, /**/ 3225, |