summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c1
-rw-r--r--src/change.c2
-rw-r--r--src/drawscreen.c8
-rw-r--r--src/edit.c6
-rw-r--r--src/misc2.c21
-rw-r--r--src/normal.c6
-rw-r--r--src/ops.c16
-rw-r--r--src/option.c21
-rw-r--r--src/option.h3
-rw-r--r--src/optiondefs.h3
-rw-r--r--src/optionstr.c34
-rw-r--r--src/proto/option.pro1
-rw-r--r--src/register.c9
-rw-r--r--src/structs.h2
-rw-r--r--src/testdir/test_virtualedit.vim120
-rw-r--r--src/version.c2
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;
diff --git a/src/ops.c b/src/ops.c
index 59d5bff50..75619c570 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -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,