]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0456: Left shift is incorrect with vartabstop and shiftwidth=0 v9.1.0456
authorGary Johnson <garyjohn@spocom.com>
Sat, 1 Jun 2024 18:51:33 +0000 (20:51 +0200)
committerChristian Brabandt <cb@256bit.org>
Sat, 1 Jun 2024 18:51:33 +0000 (20:51 +0200)
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>
src/edit.c
src/evalfunc.c
src/indent.c
src/ops.c
src/proto/indent.pro
src/testdir/test_vartabs.vim
src/version.c

index 075b39bff0d943ec393b7c8a56d84a176bbeca89..e75a1cf118b38f0caa6c7b213cc40daa81738cee 100644 (file)
@@ -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)
index 6e1eb037e44da7df057334c82e29984076c55f63..3028cf975445072a038686f4373bf3537aa2842e 100644 (file)
@@ -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
     }
index 1dfde7dddafb838cc9212fb7ded2ec297831370d..777db244af80b36122cb252157fcea8f81b1620b 100644 (file)
@@ -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
index 8706a015d1608f64b816b293f8cc973be6c1c31e..fea021b93eaca0f057127d6852535ffff1b4db43 100644 (file)
--- 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)
index bafcefc67784ff22406f97f371dc482be65f1493..6e56a0e370df1fd2401ff314a349358637ba1945 100644 (file)
@@ -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);
index e15a072f72516dce2c672537d103442159284098..bae00dd057878fb64c513ffb717e4e2947e5450b 100644 (file)
@@ -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
index c0d6601772a00edb2b7ea04b9c8c369873a99d6a..6e02c3e58e4a57d0f6d56f09984dd766dbc1ae71 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    456,
 /**/
     455,
 /**/