summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGary Johnson <garyjohn@spocom.com>2024-06-01 20:51:33 +0200
committerChristian Brabandt <cb@256bit.org>2024-06-01 20:51:33 +0200
commit88d4f255b7b7a19bb4f6489e0ad0956e47d51fed (patch)
tree6d81fd5e8675a167ca253375b26b13f8f2e0f86c
parente299591498a20c5c587364e4df57f947dfc02897 (diff)
patch 9.1.0456: Left shift is incorrect with vartabstop and shiftwidth=0v9.1.0456
Problem: Left shift is incorrect with vartabstop and shiftwidth=0 Solution: make tabstop_at() function aware of shift direction (Gary Johnson) The problem was that with 'vartabstop' set and 'shiftwidth' equal 0, left shifts using << were shifting the line to the wrong column. The tabstop to the right of the first character in the line was being used as the shift amount instead of the tabstop to the left of that first character. The reason was that the tabstop_at() function always returned the value of the tabstop to the right of the given column and was not accounting for the direction of the shift. The solution was to make tabstop_at() aware of the direction of the shift and to choose the tabtop accordingly. A test was added to check this behavior and make sure it doesn't regress. While at it, also fix a few indentation/alignment issues. fixes: #14864 closes: #14887 Signed-off-by: Gary Johnson <garyjohn@spocom.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-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,