]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0917: various vartabstop and shiftround bugs when shifting lines v9.1.0917
authorGary Johnson <garyjohn@spocom.com>
Mon, 9 Dec 2024 20:03:48 +0000 (21:03 +0100)
committerChristian Brabandt <cb@256bit.org>
Mon, 9 Dec 2024 20:28:08 +0000 (21:28 +0100)
Problem:  various vartabstop and shiftround bugs when shifting lines
Solution: Fix the bugs, add new tests for shifting lines in various ways
          (Gary Johnson)

fixes: #14891
closes: #16193

Signed-off-by: Gary Johnson <garyjohn@spocom.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/ops.c
src/testdir/test_shift.vim
src/version.c

index eb8f64c1fbcbf0c2d2943d09d9a4c7778ed77d9e..a75efab59e861e0f19ac8d16fd81530620faa143 100644 (file)
--- a/src/ops.c
+++ b/src/ops.c
@@ -218,25 +218,57 @@ op_shift(oparg_T *oap, int curs_top, int amount)
     }
 }
 
+#ifdef FEAT_VARTABS
 /*
- * Shift the current line one shiftwidth left (if left != 0) or right
- * leaves cursor on first blank in the line.
+ * Return the tabstop width at the index of the variable tabstop array.  If an
+ * index greater than the length of the array is given, the last tabstop width
+ * in the array is returned.
  */
-    void
-shift_line(
-    int        left,
-    int        round,
-    int        amount,
-    int call_changed_bytes)    // call changed_bytes()
+    static int
+get_vts(int *vts_array, int index)
 {
-    vimlong_T  count;
-    int                i, j;
-    int                sw_val = trim_to_int(get_sw_value_indent(curbuf, left));
+    int        ts;
+
+    if (index < 1)
+       ts = 0;
+    else if (index <= vts_array[0])
+       ts = vts_array[index];
+    else
+       ts = vts_array[vts_array[0]];
+
+    return ts;
+}
 
-    if (sw_val == 0)
-       sw_val = 1;             // shouldn't happen, just in case
+/*
+ * Return the sum of all the tabstops through the index-th.
+ */
+    static int
+get_vts_sum(int *vts_array, int index)
+{
+    int        sum = 0;
+    int        i;
+
+    // Perform the summation for indeces within the actual array.
+    for (i = 1; i <= index && i <= vts_array[0]; i++)
+       sum += vts_array[i];
+
+    // Add topstops whose indeces exceed the actual array.
+    if (i <= index)
+       sum += vts_array[vts_array[0]] * (index - vts_array[0]);
+
+    return sum;
+}
+#endif
 
-    count = get_indent();      // get current indent
+    static vimlong_T
+get_new_sw_indent(
+    int                left,           // TRUE if shift is to the left
+    int                round,          // TRUE if new indent is to be to a tabstop
+    vimlong_T  amount,         // Number of shifts
+    vimlong_T  sw_val)
+{
+    vimlong_T  count = get_indent();
+    vimlong_T  i, j;
 
     if (round)                 // round off indent
     {
@@ -252,19 +284,123 @@ shift_line(
        }
        else
            i += amount;
-       count = (vimlong_T)i * (vimlong_T)sw_val;
+       count = i * sw_val;
     }
-    else               // original vi indent
+    else                       // original vi indent
     {
        if (left)
        {
-           count -= (vimlong_T)sw_val * (vimlong_T)amount;
+           count -= sw_val * amount;
            if (count < 0)
                count = 0;
        }
        else
-           count += (vimlong_T)sw_val * (vimlong_T)amount;
+           count += sw_val * amount;
+    }
+
+    return count;
+}
+
+#ifdef FEAT_VARTABS
+    static vimlong_T
+get_new_vts_indent(
+    int        left,                   // TRUE if shift is to the left
+    int        round,                  // TRUE if new indent is to be to a tabstop
+    int        amount,                 // Number of shifts
+    int        *vts_array)
+{
+    vimlong_T  indent = get_indent();
+    int                vtsi = 0;
+    int                vts_indent = 0;
+    int                ts = 0;         // Silence uninitialized variable warning.
+    int                offset;         // Extra indent spaces to the right of the
+                               // tabstop
+
+    // Find the tabstop at or to the left of the current indent.
+    while (vts_indent <= indent)
+    {
+       vtsi++;
+       ts = get_vts(vts_array, vtsi);
+       vts_indent += ts;
     }
+    vts_indent -= ts;
+    vtsi--;
+
+    offset = indent - vts_indent;
+
+    if (round)
+    {
+       if (left)
+       {
+           if (offset == 0)
+               indent = get_vts_sum(vts_array, vtsi - amount);
+           else
+               indent = get_vts_sum(vts_array, vtsi - (amount - 1));
+       }
+       else
+           indent = get_vts_sum(vts_array, vtsi + amount);
+    }
+    else
+    {
+       if (left)
+       {
+           if (amount > vtsi)
+               indent = 0;
+           else
+               indent = get_vts_sum(vts_array, vtsi - amount) + offset;
+       }
+       else
+           indent = get_vts_sum(vts_array, vtsi + amount) + offset;
+    }
+
+    return indent;
+}
+#endif
+
+/*
+ * Shift the current line 'amount' shiftwidth(s) left (if 'left' is TRUE) or
+ * right.
+ *
+ * The rules for choosing a shiftwidth are:  If 'shiftwidth' is non-zero, use
+ * 'shiftwidth'; else if 'vartabstop' is not empty, use 'vartabstop'; else use
+ * 'tabstop'.  The Vim documentation says nothing about 'softtabstop' or
+ * 'varsofttabstop' affecting the shiftwidth, and neither affects the
+ * shiftwidth in current versions of Vim, so they are not considered here.
+ */
+    void
+shift_line(
+    int        left,                   // TRUE if shift is to the left
+    int        round,                  // TRUE if new indent is to be to a tabstop
+    int        amount,                 // Number of shifts
+    int        call_changed_bytes)     // call changed_bytes()
+{
+    vimlong_T  count;
+    long       sw_val = curbuf->b_p_sw;
+    long       ts_val = curbuf->b_p_ts;
+#ifdef FEAT_VARTABS
+    int                *vts_array = curbuf->b_p_vts_array;
+#endif
+
+    if (sw_val != 0)
+       // 'shiftwidth' is not zero; use it as the shift size.
+       count = get_new_sw_indent(left, round, amount, sw_val);
+    else
+#ifdef FEAT_VARTABS
+       if ((vts_array == NULL) || (vts_array[0] == 0))
+#endif
+    {
+       // 'shiftwidth is zero and 'vartabstop' is empty; use 'tabstop' as the
+       // shift size.
+       count = get_new_sw_indent(left, round, amount, ts_val);
+    }
+#ifdef FEAT_VARTABS
+    else
+    {
+       // 'shiftwidth is zero and 'vartabstop' is defined; use 'vartabstop'
+       // to determine the new indent.
+       count = get_new_vts_indent(left, round, amount, vts_array);
+    }
+#endif
 
     // Set new indent
     if (State & VREPLACE_FLAG)
index 370082fa59a08230010a2cb6ff99d047050c2a5c..f31c5a11e6b618b971ca6bf77ee39e3fdfcf4ba3 100644 (file)
@@ -112,4 +112,805 @@ func Test_ex_shift_errors()
   call assert_fails('2,1<', 'E493:')
 endfunc
 
+" Test inserting a backspace at the start of a line.
+"
+" This is to verify the proper behavior of tabstop_start() as called from
+" ins_bs().
+"
+func Test_shift_ins_bs()
+  set backspace=indent,start
+  set softtabstop=11
+
+  call setline(1, repeat(" ", 33) . "word")
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 22) . "word", getline(1))
+  call setline(1, repeat(" ", 23) . "word")
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 22) . "word", getline(1))
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 11) . "word", getline(1))
+
+  set backspace& softtabstop&
+  bw!
+endfunc
+
+" Test inserting a backspace at the start of a line, with 'varsofttabstop'.
+"
+func Test_shift_ins_bs_vartabs()
+  CheckFeature vartabs
+  set backspace=indent,start
+  set varsofttabstop=13,11,7
+
+  call setline(1, repeat(" ", 44) . "word")
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 38) . "word", getline(1))
+  call setline(1, repeat(" ", 39) . "word")
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 38) . "word", getline(1))
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 31) . "word", getline(1))
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 24) . "word", getline(1))
+  exe "norm! I\<BS>"
+  call assert_equal(repeat(" ", 13) . "word", getline(1))
+  exe "norm! I\<BS>"
+  call assert_equal(                  "word", getline(1))
+  exe "norm! I\<BS>"
+  call assert_equal(                  "word", getline(1))
+
+  set backspace& varsofttabstop&
+  bw!
+endfunc
+
+" Test the >> and << normal-mode commands.
+"
+func Test_shift_norm()
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=5
+  set tabstop=7
+
+  call setline(1, "  word")
+
+  " Shift by 'shiftwidth' right and left.
+
+  norm! >>
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  12) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  17) . "word", getline(1))
+
+  norm! <<
+  call assert_equal(repeat(" ",  12) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  " Shift by 'tabstop' right and left.
+
+  set shiftwidth=0
+  call setline(1, "  word")
+
+  norm! >>
+  call assert_equal(repeat(" ",  9) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  16) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  23) . "word", getline(1))
+
+  norm! <<
+  call assert_equal(repeat(" ",  16) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  9) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftwidth& tabstop&
+  bw!
+endfunc
+
+" Test the >> and << normal-mode commands, with 'vartabstop'.
+"
+func Test_shift_norm_vartabs()
+  CheckFeature vartabs
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=0
+  set vartabstop=19,17,11
+
+  " Shift by 'vartabstop' right and left.
+
+  call setline(1, "  word")
+
+  norm! >>
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  38) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  49) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  60) . "word", getline(1))
+
+  norm! <<
+  call assert_equal(repeat(" ",  49) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  38) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftwidth& vartabstop&
+  bw!
+endfunc
+
+" Test the >> and << normal-mode commands with 'shiftround'.
+"
+func Test_shift_norm_round()
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftround
+  set shiftwidth=5
+  set tabstop=7
+
+  call setline(1, "word")
+
+  " Shift by 'shiftwidth' right and left.
+
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  5) . "word", getline(1))
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  10) . "word", getline(1))
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  15) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  20) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  25) . "word", getline(1))
+
+  norm! <<
+  call assert_equal(repeat(" ",  20) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  15) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  10) . "word", getline(1))
+  exe "norm! I  "
+  norm! <<
+  call assert_equal(repeat(" ",  10) . "word", getline(1))
+
+  call setline(1, repeat(" ", 7) . "word")
+  norm! <<
+  call assert_equal(repeat(" ",  5) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  call setline(1, repeat(" ", 2) . "word")
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  " Shift by 'tabstop' right and left.
+
+  set shiftwidth=0
+  call setline(1, "word")
+
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  14) . "word", getline(1))
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  28) . "word", getline(1))
+  norm! >>
+  call assert_equal(repeat(" ",  35) . "word", getline(1))
+
+  norm! <<
+  call assert_equal(repeat(" ",  28) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  14) . "word", getline(1))
+  exe "norm! I  "
+  norm! <<
+  call assert_equal(repeat(" ",  14) . "word", getline(1))
+
+  call setline(1, repeat(" ", 9) . "word")
+  norm! <<
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  call setline(1, repeat(" ", 2) . "word")
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftround& shiftwidth& tabstop&
+  bw!
+endfunc
+
+" Test the >> and << normal-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_norm_round_vartabs()
+  CheckFeature vartabs
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftround
+  set shiftwidth=0
+  set vartabstop=19,17,11
+
+  " Shift by 'vartabstop' right and left.
+
+  call setline(1, "word")
+
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  19) . "word", getline(1))
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  36) . "word", getline(1))
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  47) . "word", getline(1))
+  exe "norm! I  "
+  norm! >>
+  call assert_equal(repeat(" ",  58) . "word", getline(1))
+
+  exe "norm! I  "
+  norm! <<
+  call assert_equal(repeat(" ",  58) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  47) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  36) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  19) . "word", getline(1))
+  exe "norm! I  "
+  norm! <<
+  call assert_equal(repeat(" ",  19) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  exe "norm! I  "
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftround& shiftwidth& vartabstop&
+  bw!
+endfunc
+
+" Test the V> and V< visual-mode commands.
+"
+" See ":help v_<" and ":help v_>".  See also the last paragraph of "3. Simple
+" changes", ":help simple-change", immediately above "4. Complex changes",
+" ":help complex-change".
+"
+func Test_shift_vis()
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=5
+  set tabstop=7
+
+  call setline(1, "  word")
+
+  " Shift by 'shiftwidth' right and left.
+
+  norm! V>
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  norm! V2>
+  call assert_equal(repeat(" ",  17) . "word", getline(1))
+  norm! V3>
+  call assert_equal(repeat(" ",  32) . "word", getline(1))
+
+  norm! V<
+  call assert_equal(repeat(" ",  27) . "word", getline(1))
+  norm! V2<
+  call assert_equal(repeat(" ",  17) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  norm! V<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  " Shift by 'tabstop' right and left.
+
+  set shiftwidth=0
+  call setline(1, "  word")
+
+  norm! V>
+  call assert_equal(repeat(" ",  9) . "word", getline(1))
+  norm! V2>
+  call assert_equal(repeat(" ",  23) . "word", getline(1))
+  norm! V3>
+  call assert_equal(repeat(" ",  44) . "word", getline(1))
+
+  norm! V<
+  call assert_equal(repeat(" ",  37) . "word", getline(1))
+  norm! V2<
+  call assert_equal(repeat(" ",  23) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  norm! V<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftwidth& tabstop&
+  bw!
+endfunc
+
+" Test the V> and V< visual-mode commands, with 'vartabstop'.
+"
+" See ":help v_<" and ":help v_>".  See also the last paragraph of "3. Simple
+" changes", ":help simple-change", immediately above "4. Complex changes",
+" ":help complex-change".
+"
+func Test_shift_vis_vartabs()
+  CheckFeature vartabs
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=0
+  set vartabstop=19,17,11
+
+  " Shift by 'vartabstop' right and left.
+
+  call setline(1, "  word")
+
+  norm! V>
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  norm! V2>
+  call assert_equal(repeat(" ",  49) . "word", getline(1))
+  norm! V3>
+  call assert_equal(repeat(" ",  82) . "word", getline(1))
+
+  norm! V<
+  call assert_equal(repeat(" ",  71) . "word", getline(1))
+  norm! V2<
+  call assert_equal(repeat(" ",  49) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  norm! V<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftwidth& vartabstop&
+  bw!
+endfunc
+
+" Test the V> and V< visual-mode commands with 'shiftround'.
+"
+func Test_shift_vis_round()
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftround
+  set shiftwidth=5
+  set tabstop=7
+
+  call setline(1, "word")
+
+  " Shift by 'shiftwidth' right and left.
+
+  exe "norm! I  "
+  norm! V>
+  call assert_equal(repeat(" ",  5) . "word", getline(1))
+  exe "norm! I  "
+  norm! V2>
+  call assert_equal(repeat(" ",  15) . "word", getline(1))
+  exe "norm! I  "
+  norm! V3>
+  call assert_equal(repeat(" ",  30) . "word", getline(1))
+
+  exe "norm! I  "
+  norm! V2<
+  call assert_equal(repeat(" ",  25) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  10) . "word", getline(1))
+  norm! V<
+  call assert_equal(repeat(" ",  5) . "word", getline(1))
+  norm! V<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  " Shift by 'tabstop' right and left.
+
+  set shiftwidth=0
+  call setline(1, "word")
+
+  exe "norm! I  "
+  norm! V>
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  exe "norm! I  "
+  norm! V2>
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  exe "norm! I  "
+  norm! V3>
+  call assert_equal(repeat(" ",  42) . "word", getline(1))
+
+  exe "norm! I  "
+  norm! V<
+  call assert_equal(repeat(" ",  42) . "word", getline(1))
+  norm! V<
+  call assert_equal(repeat(" ",  35) . "word", getline(1))
+  norm! V2<
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! V<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  norm! V3<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  call setline(1, "  word")
+  norm! V<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+
+  set expandtab& shiftround& shiftwidth& tabstop&
+  bw!
+endfunc
+
+" Test the V> and V< visual-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_vis_round_vartabs()
+  CheckFeature vartabs
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftround
+  set shiftwidth=0
+  set vartabstop=19,17,11
+
+  " Shift by 'vartabstop' right and left.
+
+  call setline(1, "word")
+
+  exe "norm! I  "
+  norm! V>
+  call assert_equal(repeat(" ",  19) . "word", getline(1))
+  exe "norm! I  "
+  norm! V3>
+  call assert_equal(repeat(" ",  58) . "word", getline(1))
+
+  exe "norm! I  "
+  norm! V2<
+  call assert_equal(repeat(" ",  47) . "word", getline(1))
+  exe "norm! I  "
+  norm! V3<
+  call assert_equal(repeat(" ",  19) . "word", getline(1))
+  exe "norm! I  "
+  norm! V3<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  exe "norm! I  "
+  norm! V<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftround& shiftwidth& vartabstop&
+  bw!
+endfunc
+
+" Test the :> and :< ex-mode commands.
+"
+func Test_shift_ex()
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=5
+  set tabstop=7
+
+  call setline(1, "  word")
+
+  " Shift by 'shiftwidth' right and left.
+
+  >
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  >>
+  call assert_equal(repeat(" ",  17) . "word", getline(1))
+  >>>
+  call assert_equal(repeat(" ",  32) . "word", getline(1))
+
+  <<<<
+  call assert_equal(repeat(" ",  12) . "word", getline(1))
+  <
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  <
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  <
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  " Shift by 'tabstop' right and left.
+
+  set shiftwidth=0
+  call setline(1, "  word")
+
+  >
+  call assert_equal(repeat(" ",  9) . "word", getline(1))
+  >>
+  call assert_equal(repeat(" ",  23) . "word", getline(1))
+  >>>
+  call assert_equal(repeat(" ",  44) . "word", getline(1))
+
+  <<<<
+  call assert_equal(repeat(" ",  16) . "word", getline(1))
+  <<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  <
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftwidth& tabstop&
+  bw!
+endfunc
+
+" Test the :> and :< ex-mode commands, with vartabstop.
+"
+func Test_shift_ex_vartabs()
+  CheckFeature vartabs
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=0
+  set vartabstop=19,17,11
+
+  " Shift by 'vartabstop' right and left.
+
+  call setline(1, "  word")
+
+  >
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  >>
+  call assert_equal(repeat(" ",  49) . "word", getline(1))
+  >>>
+  call assert_equal(repeat(" ",  82) . "word", getline(1))
+
+  <<<<
+  call assert_equal(repeat(" ",  38) . "word", getline(1))
+  <<
+  call assert_equal(repeat(" ",  2) . "word", getline(1))
+  <
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftwidth& vartabstop&
+  bw!
+endfunc
+
+" Test the :> and :< ex-mode commands with 'shiftround'.
+"
+func Test_shift_ex_round()
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftround
+  set shiftwidth=5
+  set tabstop=7
+
+  call setline(1, "word")
+
+  " Shift by 'shiftwidth' right and left.
+
+  exe "norm! I  "
+  >
+  call assert_equal(repeat(" ",  5) . "word", getline(1))
+  exe "norm! I  "
+  >>
+  call assert_equal(repeat(" ",  15) . "word", getline(1))
+  exe "norm! I  "
+  >>>
+  call assert_equal(repeat(" ",  30) . "word", getline(1))
+
+  exe "norm! I  "
+  <<<<
+  call assert_equal(repeat(" ",  15) . "word", getline(1))
+  exe "norm! I  "
+  <<
+  call assert_equal(repeat(" ",  10) . "word", getline(1))
+  <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  >>
+  <<<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  " Shift by 'tabstop' right and left.
+
+  set shiftwidth=0
+  call setline(1, "word")
+
+  exe "norm! I  "
+  >
+  call assert_equal(repeat(" ",  7) . "word", getline(1))
+  exe "norm! I  "
+  >>
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  exe "norm! I  "
+  >>>
+  call assert_equal(repeat(" ",  42) . "word", getline(1))
+
+  exe "norm! I  "
+  <<<<
+  call assert_equal(repeat(" ",  21) . "word", getline(1))
+  exe "norm! I  "
+  <<
+  call assert_equal(repeat(" ",  14) . "word", getline(1))
+  exe "norm! I  "
+  <<<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  >>
+  <<<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftround& shiftwidth& tabstop&
+  bw!
+endfunc
+
+" Test the :> and :< ex-mode commands with 'shiftround' and 'vartabstop'.
+"
+func Test_shift_ex_round_vartabs()
+  CheckFeature vartabs
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftround
+  set shiftwidth=0
+  set vartabstop=19,17,11
+
+  " Shift by 'vartabstop' right and left.
+
+  call setline(1, "word")
+
+  exe "norm! I  "
+  >
+  call assert_equal(repeat(" ",  19) . "word", getline(1))
+  exe "norm! I  "
+  >>
+  call assert_equal(repeat(" ",  47) . "word", getline(1))
+  >>>
+  call assert_equal(repeat(" ",  80) . "word", getline(1))
+
+  <<<<
+  call assert_equal(repeat(" ",  36) . "word", getline(1))
+  exe "norm! I  "
+  <<
+  call assert_equal(repeat(" ",  19) . "word", getline(1))
+  exe "norm! I  "
+  <<
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+  <
+  call assert_equal(repeat(" ",  0) . "word", getline(1))
+
+  set expandtab& shiftround& shiftwidth& vartabstop&
+  bw!
+endfunc
+
+" Test shifting lines with <C-T> and <C-D>.
+"
+func Test_shift_ins()
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=5
+  set tabstop=7
+
+  " Shift by 'shiftwidth' right and left.
+
+  call setline(1, repeat(" ", 7) . "word")
+  exe "norm! 9|i\<C-T>"
+  call assert_equal(repeat(" ", 10) . "word", getline(1))
+  exe "norm! A\<C-T>"
+  call assert_equal(repeat(" ", 15) . "word", getline(1))
+  exe "norm! I  \<C-T>"
+  call assert_equal(repeat(" ", 20) . "word", getline(1))
+
+  exe "norm! I  \<C-D>"
+  call assert_equal(repeat(" ", 20) . "word", getline(1))
+  exe "norm! I  "
+  exe "norm! 24|i\<C-D>"
+  call assert_equal(repeat(" ", 20) . "word", getline(1))
+  exe "norm! A\<C-D>"
+  call assert_equal(repeat(" ", 15) . "word", getline(1))
+  exe "norm! I  "
+  exe "norm! A\<C-D>\<C-D>"
+  call assert_equal(repeat(" ", 10) . "word", getline(1))
+  exe "norm! I\<C-D>\<C-D>\<C-D>"
+  call assert_equal(repeat(" ", 0) . "word", getline(1))
+  exe "norm! I\<C-D>"
+  call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+  " Shift by 'tabstop' right and left.
+
+  set shiftwidth=0
+  call setline(1, "word")
+
+  call setline(1, repeat(" ", 9) . "word")
+  exe "norm! 11|i\<C-T>"
+  call assert_equal(repeat(" ", 14) . "word", getline(1))
+  exe "norm! A\<C-T>"
+  call assert_equal(repeat(" ", 21) . "word", getline(1))
+  exe "norm! I  \<C-T>"
+  call assert_equal(repeat(" ", 28) . "word", getline(1))
+
+  exe "norm! I  \<C-D>"
+  call assert_equal(repeat(" ", 28) . "word", getline(1))
+  exe "norm! I  "
+  exe "norm! 32|i\<C-D>"
+  call assert_equal(repeat(" ", 28) . "word", getline(1))
+  exe "norm! A\<C-D>"
+  call assert_equal(repeat(" ", 21) . "word", getline(1))
+  exe "norm! I  "
+  exe "norm! A\<C-D>\<C-D>"
+  call assert_equal(repeat(" ", 14) . "word", getline(1))
+  exe "norm! I\<C-D>\<C-D>\<C-D>"
+  call assert_equal(repeat(" ", 0) . "word", getline(1))
+  exe "norm! I\<C-D>"
+  call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+  set expandtab& shiftwidth& tabstop&
+  bw!
+endfunc
+
+" Test shifting lines with <C-T> and <C-D>, with 'vartabstop'.
+"
+func Test_shift_ins_vartabs()
+  CheckFeature vartabs
+  set expandtab                 " Don't want to worry about tabs vs. spaces in
+                                " results.
+
+  set shiftwidth=0
+  set vartabstop=19,17,11
+
+  " Shift by 'vartabstop' right and left.
+
+  call setline(1, "word")
+
+  call setline(1, repeat(" ", 9) . "word")
+  exe "norm! 11|i\<C-T>"
+  call assert_equal(repeat(" ", 19) . "word", getline(1))
+  exe "norm! A\<C-T>"
+  call assert_equal(repeat(" ", 36) . "word", getline(1))
+  exe "norm! I  \<C-T>"
+  call assert_equal(repeat(" ", 47) . "word", getline(1))
+
+  exe "norm! I  \<C-D>"
+  call assert_equal(repeat(" ", 47) . "word", getline(1))
+  exe "norm! I  "
+  exe "norm! 51|i\<C-D>"
+  call assert_equal(repeat(" ", 47) . "word", getline(1))
+  exe "norm! A\<C-D>"
+  call assert_equal(repeat(" ", 36) . "word", getline(1))
+  exe "norm! I  "
+  exe "norm! A\<C-D>\<C-D>"
+  call assert_equal(repeat(" ", 19) . "word", getline(1))
+  exe "norm! I\<C-D>\<C-D>\<C-D>"
+  call assert_equal(repeat(" ", 0) . "word", getline(1))
+  exe "norm! I\<C-D>"
+  call assert_equal(repeat(" ", 0) . "word", getline(1))
+
+  set expandtab& shiftwidth& vartabstop&
+  bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
index 5933af3b897d48a2c75ebd6c1a8674f97b963eea..96b3803fa89d947d1fa8904d0fea758aacc22dcc 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    917,
 /**/
     916,
 /**/