1
0
forked from aniani/vim

patch 8.2.3227: 'virtualedit' can only be set globally

Problem:    'virtualedit' can only be set globally.
Solution:   Make 'virtualedit' global-local. (Gary Johnson, closes #8638)
This commit is contained in:
Gary Johnson
2021-07-26 22:19:10 +02:00
committed by Bram Moolenaar
parent 29b857150c
commit 53ba05b090
17 changed files with 220 additions and 41 deletions

View File

@@ -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);
}
/*

View File

@@ -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;

View File

@@ -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 =

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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'.

View File

@@ -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
};

View File

@@ -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,

View File

@@ -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)
{
// Recompute cursor position in case the new 've' setting
// changes something.
validate_virtcol();
coladvance(curwin->w_virtcol);
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);
}
}
}

View File

@@ -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);

View File

@@ -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))
{

View File

@@ -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

View File

@@ -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

View File

@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3227,
/**/
3226,
/**/