summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/edit.c11
-rw-r--r--src/evalfunc.c4
-rw-r--r--src/indent.c47
-rw-r--r--src/ops.c16
-rw-r--r--src/proto/indent.pro6
-rw-r--r--src/testdir/test_vartabs.vim59
-rw-r--r--src/version.c2
7 files changed, 113 insertions, 32 deletions
diff --git a/src/edit.c b/src/edit.c
index 075b39bff0..e75a1cf118 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -519,9 +519,10 @@ edit(
if (
#ifdef FEAT_VARTABS
- curwin->w_wcol < mincol - tabstop_at(
- get_nolist_virtcol(), curbuf->b_p_ts,
- curbuf->b_p_vts_array)
+ curwin->w_wcol < mincol - tabstop_at(get_nolist_virtcol(),
+ curbuf->b_p_ts,
+ curbuf->b_p_vts_array,
+ FALSE)
#else
(int)curwin->w_wcol < mincol - curbuf->b_p_ts
#endif
@@ -1310,7 +1311,7 @@ docomplete:
c = ins_ctrl_ey(c);
break;
- default:
+ default:
#ifdef UNIX
if (c == intr_char) // special interrupt char
goto do_intr;
@@ -1842,7 +1843,7 @@ backspace_until_column(int col)
* Only matters when there are composing characters.
* Return TRUE when something was deleted.
*/
- static int
+ static int
del_char_after_col(int limit_col UNUSED)
{
if (enc_utf8 && limit_col >= 0)
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 6e1eb037e4..3028cf9754 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -5464,7 +5464,7 @@ f_getpos(typval_T *argvars, typval_T *rettv)
/*
* Convert from block_def to string
*/
- static char_u *
+ static char_u *
block_def2str(struct block_def *bd)
{
char_u *p, *ret;
@@ -10948,7 +10948,7 @@ f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
if (col < 0)
return; // type error; errmsg already given
#ifdef FEAT_VARTABS
- rettv->vval.v_number = get_sw_value_col(curbuf, col);
+ rettv->vval.v_number = get_sw_value_col(curbuf, col, FALSE);
return;
#endif
}
diff --git a/src/indent.c b/src/indent.c
index 1dfde7ddda..777db244af 100644
--- a/src/indent.c
+++ b/src/indent.c
@@ -123,14 +123,22 @@ tabstop_padding(colnr_T col, int ts_arg, int *vts)
/*
* Find the size of the tab that covers a particular column.
+ *
+ * If this is being called as part of a shift operation, col is not the cursor
+ * column but is the column number to the left of the first non-whitespace
+ * character in the line. If the shift is to the left (left = TRUE), then
+ * return the size of the tab interval to the left of the column.
*/
int
-tabstop_at(colnr_T col, int ts, int *vts)
+tabstop_at(colnr_T col, int ts, int *vts, int left)
{
- int tabcount;
- colnr_T tabcol = 0;
- int t;
- int tab_size = 0;
+ int tabcount; // Number of tab stops in the list of variable
+ // tab stops.
+ colnr_T tabcol = 0; // Column of the tab stop under consideration.
+ int t; // Tabstop index in the list of variable tab
+ // stops.
+ int tab_size = 0; // Size of the tab stop interval to the right
+ // or left of the col.
if (vts == 0 || vts[0] == 0)
return ts;
@@ -141,11 +149,22 @@ tabstop_at(colnr_T col, int ts, int *vts)
tabcol += vts[t];
if (tabcol > col)
{
- tab_size = vts[t];
+ // If shifting left (left != 0), and if the column to the left of
+ // the first first non-blank character (col) in the line is
+ // already to the left of the first tabstop, set the shift amount
+ // (tab_size) to just enough to shift the line to the left margin.
+ // The value doesn't seem to matter as long as it is at least that
+ // distance.
+ if (left && (t == 1))
+ tab_size = col;
+ else
+ tab_size = vts[t - (left ? 1 : 0)];
break;
}
}
- if (t > tabcount)
+ if (t > tabcount) // If the value of the index t is beyond the
+ // end of the list, use the tab stop value at
+ // the end of the list.
tab_size = vts[tabcount];
return tab_size;
@@ -327,20 +346,20 @@ tabstop_first(int *ts)
long
get_sw_value(buf_T *buf)
{
- return get_sw_value_col(buf, 0);
+ return get_sw_value_col(buf, 0, FALSE);
}
/*
* Idem, using "pos".
*/
static long
-get_sw_value_pos(buf_T *buf, pos_T *pos)
+get_sw_value_pos(buf_T *buf, pos_T *pos, int left)
{
pos_T save_cursor = curwin->w_cursor;
long sw_value;
curwin->w_cursor = *pos;
- sw_value = get_sw_value_col(buf, get_nolist_virtcol());
+ sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left);
curwin->w_cursor = save_cursor;
return sw_value;
}
@@ -349,23 +368,23 @@ get_sw_value_pos(buf_T *buf, pos_T *pos)
* Idem, using the first non-black in the current line.
*/
long
-get_sw_value_indent(buf_T *buf)
+get_sw_value_indent(buf_T *buf, int left)
{
pos_T pos = curwin->w_cursor;
pos.col = getwhitecols_curline();
- return get_sw_value_pos(buf, &pos);
+ return get_sw_value_pos(buf, &pos, left);
}
/*
* Idem, using virtual column "col".
*/
long
-get_sw_value_col(buf_T *buf, colnr_T col UNUSED)
+get_sw_value_col(buf_T *buf, colnr_T col UNUSED, int left UNUSED)
{
return buf->b_p_sw ? buf->b_p_sw :
#ifdef FEAT_VARTABS
- tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
+ tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left);
#else
buf->b_p_ts;
#endif
diff --git a/src/ops.c b/src/ops.c
index 8706a015d1..fea021b93e 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -231,7 +231,7 @@ shift_line(
{
vimlong_T count;
int i, j;
- int sw_val = trim_to_int(get_sw_value_indent(curbuf));
+ int sw_val = trim_to_int(get_sw_value_indent(curbuf, left));
count = get_indent(); // get current indent
@@ -283,7 +283,7 @@ shift_block(oparg_T *oap, int amount)
char_u *newp, *oldp;
size_t newlen, oldlen;
int oldcol = curwin->w_cursor.col;
- int sw_val = (int)get_sw_value_indent(curbuf);
+ int sw_val = (int)get_sw_value_indent(curbuf, left);
int ts_val = (int)curbuf->b_p_ts;
struct block_def bd;
int incr;
@@ -1258,8 +1258,8 @@ op_replace(oparg_T *oap, int c)
replace_character(c);
else
PBYTE(curwin->w_cursor, c);
- if (inc(&curwin->w_cursor) == -1)
- break;
+ if (inc(&curwin->w_cursor) == -1)
+ break;
}
}
@@ -2523,11 +2523,11 @@ op_addsub(
int change_cnt = 0;
linenr_T amount = Prenum1;
- // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the
- // buffer is not completely updated yet. Postpone updating folds until before
- // the call to changed_lines().
+ // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the
+ // buffer is not completely updated yet. Postpone updating folds until before
+ // the call to changed_lines().
#ifdef FEAT_FOLDING
- disable_fold_update++;
+ disable_fold_update++;
#endif
if (!VIsual_active)
diff --git a/src/proto/indent.pro b/src/proto/indent.pro
index bafcefc677..6e56a0e370 100644
--- a/src/proto/indent.pro
+++ b/src/proto/indent.pro
@@ -1,15 +1,15 @@
/* indent.c */
int tabstop_set(char_u *var, int **array);
int tabstop_padding(colnr_T col, int ts_arg, int *vts);
-int tabstop_at(colnr_T col, int ts, int *vts);
+int tabstop_at(colnr_T col, int ts, int *vts, int left);
colnr_T tabstop_start(colnr_T col, int ts, int *vts);
void tabstop_fromto(colnr_T start_col, colnr_T end_col, int ts_arg, int *vts, int *ntabs, int *nspcs);
int *tabstop_copy(int *oldts);
int tabstop_count(int *ts);
int tabstop_first(int *ts);
long get_sw_value(buf_T *buf);
-long get_sw_value_indent(buf_T *buf);
-long get_sw_value_col(buf_T *buf, colnr_T col);
+long get_sw_value_indent(buf_T *buf, int left);
+long get_sw_value_col(buf_T *buf, colnr_T col, int left);
long get_sts_value(void);
int get_indent(void);
int get_indent_lnum(linenr_T lnum);
diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim
index e15a072f72..bae00dd057 100644
--- a/src/testdir/test_vartabs.vim
+++ b/src/testdir/test_vartabs.vim
@@ -454,5 +454,64 @@ func Test_vartabstop_latin1()
set nocompatible linebreak& list& revins& smarttab& vartabstop&
endfunc
+" Verify that right-shifting and left-shifting adjust lines to the proper
+" tabstops.
+func Test_vartabstop_shift_right_left()
+ new
+ set expandtab
+ set shiftwidth=0
+ set vartabstop=17,11,7
+ exe "norm! aword"
+ let expect = "word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to first tabstop.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to second tabstop.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to third tabstop.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift to fourth tabstop, repeating the third shift width.
+ norm! >>
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the third tabstop.
+ norm! <<
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the second tabstop.
+ norm! <<
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the first tabstop.
+ norm! <<
+ let expect = " word"
+ call assert_equal(expect, getline(1))
+
+ " Shift back to the left margin.
+ norm! <<
+ let expect = "word"
+ call assert_equal(expect, getline(1))
+
+ " Shift again back to the left margin.
+ norm! <<
+ let expect = "word"
+ call assert_equal(expect, getline(1))
+
+ bwipeout!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index c0d6601772..6e02c3e58e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 456,
+/**/
455,
/**/
454,