diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index 98b0d6003a..c9b7a1ba3f 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -14,6 +14,7 @@ #include "nvim/indent_c.h" #include "nvim/macros_defs.h" #include "nvim/mark_defs.h" +#include "nvim/math.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/option.h" @@ -1689,7 +1690,7 @@ void parse_cino(buf_T *buf) p++; } char *digits_start = p; // remember where the digits start - int n = getdigits_int(&p, true, 0); + int64_t n = getdigits_int(&p, true, 0); divider = 0; if (*p == '.') { // ".5s" means a fraction. fraction = atoi(++p); @@ -1708,7 +1709,7 @@ void parse_cino(buf_T *buf) } else { n *= sw; if (divider) { - n += (sw * fraction + divider / 2) / divider; + n += ((int64_t)sw * fraction + divider / 2) / divider; } } p++; @@ -1717,119 +1718,121 @@ void parse_cino(buf_T *buf) n = -n; } + n = trim_to_int(n); + // When adding an entry here, also update the default 'cinoptions' in // doc/indent.txt, and add explanation for it! switch (*l) { case '>': - buf->b_ind_level = n; + buf->b_ind_level = (int)n; break; case 'e': - buf->b_ind_open_imag = n; + buf->b_ind_open_imag = (int)n; break; case 'n': - buf->b_ind_no_brace = n; + buf->b_ind_no_brace = (int)n; break; case 'f': - buf->b_ind_first_open = n; + buf->b_ind_first_open = (int)n; break; case '{': - buf->b_ind_open_extra = n; + buf->b_ind_open_extra = (int)n; break; case '}': - buf->b_ind_close_extra = n; + buf->b_ind_close_extra = (int)n; break; case '^': - buf->b_ind_open_left_imag = n; + buf->b_ind_open_left_imag = (int)n; break; case 'L': - buf->b_ind_jump_label = n; + buf->b_ind_jump_label = (int)n; break; case ':': - buf->b_ind_case = n; + buf->b_ind_case = (int)n; break; case '=': - buf->b_ind_case_code = n; + buf->b_ind_case_code = (int)n; break; case 'b': - buf->b_ind_case_break = n; + buf->b_ind_case_break = (int)n; break; case 'p': - buf->b_ind_param = n; + buf->b_ind_param = (int)n; break; case 't': - buf->b_ind_func_type = n; + buf->b_ind_func_type = (int)n; break; case '/': - buf->b_ind_comment = n; + buf->b_ind_comment = (int)n; break; case 'c': - buf->b_ind_in_comment = n; + buf->b_ind_in_comment = (int)n; break; case 'C': - buf->b_ind_in_comment2 = n; + buf->b_ind_in_comment2 = (int)n; break; case 'i': - buf->b_ind_cpp_baseclass = n; + buf->b_ind_cpp_baseclass = (int)n; break; case '+': - buf->b_ind_continuation = n; + buf->b_ind_continuation = (int)n; break; case '(': - buf->b_ind_unclosed = n; + buf->b_ind_unclosed = (int)n; break; case 'u': - buf->b_ind_unclosed2 = n; + buf->b_ind_unclosed2 = (int)n; break; case 'U': - buf->b_ind_unclosed_noignore = n; + buf->b_ind_unclosed_noignore = (int)n; break; case 'W': - buf->b_ind_unclosed_wrapped = n; + buf->b_ind_unclosed_wrapped = (int)n; break; case 'w': - buf->b_ind_unclosed_whiteok = n; + buf->b_ind_unclosed_whiteok = (int)n; break; case 'm': - buf->b_ind_matching_paren = n; + buf->b_ind_matching_paren = (int)n; break; case 'M': - buf->b_ind_paren_prev = n; + buf->b_ind_paren_prev = (int)n; break; case ')': - buf->b_ind_maxparen = n; + buf->b_ind_maxparen = (int)n; break; case '*': - buf->b_ind_maxcomment = n; + buf->b_ind_maxcomment = (int)n; break; case 'g': - buf->b_ind_scopedecl = n; + buf->b_ind_scopedecl = (int)n; break; case 'h': - buf->b_ind_scopedecl_code = n; + buf->b_ind_scopedecl_code = (int)n; break; case 'j': - buf->b_ind_java = n; + buf->b_ind_java = (int)n; break; case 'J': - buf->b_ind_js = n; + buf->b_ind_js = (int)n; break; case 'l': - buf->b_ind_keep_case_label = n; + buf->b_ind_keep_case_label = (int)n; break; case '#': - buf->b_ind_hash_comment = n; + buf->b_ind_hash_comment = (int)n; break; case 'N': - buf->b_ind_cpp_namespace = n; + buf->b_ind_cpp_namespace = (int)n; break; case 'k': - buf->b_ind_if_for_while = n; + buf->b_ind_if_for_while = (int)n; break; case 'E': - buf->b_ind_cpp_extern_c = n; + buf->b_ind_cpp_extern_c = (int)n; break; case 'P': - buf->b_ind_pragma = n; + buf->b_ind_pragma = (int)n; break; } if (*p == ',') { diff --git a/src/nvim/math.c b/src/nvim/math.c index 4ca212413b..0b5886d36c 100644 --- a/src/nvim/math.c +++ b/src/nvim/math.c @@ -106,3 +106,9 @@ int vim_append_digit_int(int *value, int digit) *value = x * 10 + digit; return OK; } + +/// Return something that fits into an int. +int trim_to_int(int64_t x) +{ + return x > INT_MAX ? INT_MAX : x < INT_MIN ? INT_MIN : (int)x; +} diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 63c78936ba..71a005bd24 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -48,6 +48,7 @@ #include "nvim/macros_defs.h" #include "nvim/mark.h" #include "nvim/mark_defs.h" +#include "nvim/math.h" #include "nvim/mbyte.h" #include "nvim/mbyte_defs.h" #include "nvim/memline.h" @@ -273,21 +274,53 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) changed_lines(curbuf, oap->start.lnum, 0, oap->end.lnum + 1, 0, true); } -/// Shift the current line one shiftwidth left (if left != 0) or right -/// leaves cursor on first blank in the line. -/// -/// @param call_changed_bytes call changed_bytes() -void shift_line(bool left, bool round, int amount, int call_changed_bytes) +/// 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. +static int get_vts(const int *vts_array, int index) { - int sw_val = get_sw_value_indent(curbuf, left); - if (sw_val == 0) { - sw_val = 1; // shouldn't happen, just in case + int ts; + + if (index < 1) { + ts = 0; + } else if (index <= vts_array[0]) { + ts = vts_array[index]; + } else { + ts = vts_array[vts_array[0]]; } - int count = get_indent(); // get current indent + + return ts; +} + +/// Return the sum of all the tabstops through the index-th. +static int get_vts_sum(const 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; +} + +/// @param left true if shift is to the left +/// @param count true if new indent is to be to a tabstop +/// @param amount number of shifts +static int64_t get_new_sw_indent(bool left, bool round, int64_t amount, int64_t sw_val) +{ + int64_t count = get_indent(); // get current indent if (round) { // round off indent - int i = count / sw_val; // number of 'shiftwidth' rounded down - int j = count % sw_val; // extra spaces + int64_t i = trim_to_int(count / sw_val); // number of 'shiftwidth' rounded down + int64_t j = trim_to_int(count % sw_val); // extra spaces if (j && left) { // first remove extra spaces amount--; } @@ -305,11 +338,94 @@ void shift_line(bool left, bool round, int amount, int call_changed_bytes) } } + return count; +} + +/// @param left true if shift is to the left +/// @param count true if new indent is to be to a tabstop +/// @param amount number of shifts +static int64_t get_new_vts_indent(bool left, bool round, int amount, int *vts_array) +{ + int64_t indent = get_indent(); + int vtsi = 0; + int vts_indent = 0; + int ts = 0; // Silence uninitialized variable warning. + + // 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--; + + // Extra indent spaces to the right of the tabstop + int64_t 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; +} + +/// 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. +/// +/// @param left true if shift is to the left +/// @param count true if new indent is to be to a tabstop +/// @param amount number of shifts +/// @param call_changed_bytes call changed_bytes() +void shift_line(bool left, bool round, int amount, int call_changed_bytes) +{ + int64_t count; + int64_t sw_val = curbuf->b_p_sw; + int64_t ts_val = curbuf->b_p_ts; + int *vts_array = curbuf->b_p_vts_array; + + 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 if ((vts_array == NULL) || (vts_array[0] == 0)) { + // 'shiftwidth' is zero and 'vartabstop' is empty; use 'tabstop' as the + // shift size. + count = get_new_sw_indent(left, round, amount, ts_val); + } 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); + } + // Set new indent if (State & VREPLACE_FLAG) { - change_indent(INDENT_SET, count, false, call_changed_bytes); + change_indent(INDENT_SET, trim_to_int(count), false, call_changed_bytes); } else { - set_indent(count, call_changed_bytes ? SIN_CHANGED : 0); + set_indent(trim_to_int(count), call_changed_bytes ? SIN_CHANGED : 0); } } diff --git a/test/old/testdir/test_indent.vim b/test/old/testdir/test_indent.vim index dcacc11663..0998b04443 100644 --- a/test/old/testdir/test_indent.vim +++ b/test/old/testdir/test_indent.vim @@ -276,4 +276,31 @@ func Test_formatting_keeps_first_line_indent() bwipe! endfunc +" Test for indenting with large amount, causes overflow +func Test_indent_overflow_count() + throw 'skipped: TODO: ' + new + setl sw=8 + call setline(1, "abc") + norm! V2147483647> + " indents by INT_MAX + call assert_equal(2147483647, indent(1)) + close! +endfunc + +func Test_indent_overflow_count2() + throw 'skipped: Nvim does not support 64-bit number options' + new + " this only works, when long is 64bits + try + setl sw=0x180000000 + catch /^Vim\%((\a\+)\)\=:E487:/ + throw 'Skipped: value negative on this platform' + endtry + call setline(1, "\tabc") + norm! << + call assert_equal(0, indent(1)) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/test/old/testdir/test_shift.vim b/test/old/testdir/test_shift.vim index ec357dac88..f31c5a11e6 100644 --- a/test/old/testdir/test_shift.vim +++ b/test/old/testdir/test_shift.vim @@ -108,10 +108,809 @@ func Test_ex_shift_errors() call assert_fails('>!', 'E477:') call assert_fails('', 'E493:') - call assert_fails('execute "2,1>"', 'E493:') - " call assert_fails('2,1<', 'E493:') - call assert_fails('execute "2,1<"', 'E493:') + call assert_fails('2,1>', 'E493:') + 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\" + call assert_equal(repeat(" ", 22) . "word", getline(1)) + call setline(1, repeat(" ", 23) . "word") + exe "norm! I\" + call assert_equal(repeat(" ", 22) . "word", getline(1)) + exe "norm! I\" + 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\" + call assert_equal(repeat(" ", 38) . "word", getline(1)) + call setline(1, repeat(" ", 39) . "word") + exe "norm! I\" + call assert_equal(repeat(" ", 38) . "word", getline(1)) + exe "norm! I\" + call assert_equal(repeat(" ", 31) . "word", getline(1)) + exe "norm! I\" + call assert_equal(repeat(" ", 24) . "word", getline(1)) + exe "norm! I\" + call assert_equal(repeat(" ", 13) . "word", getline(1)) + exe "norm! I\" + call assert_equal( "word", getline(1)) + exe "norm! I\" + 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 and . +" +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\" + call assert_equal(repeat(" ", 10) . "word", getline(1)) + exe "norm! A\" + call assert_equal(repeat(" ", 15) . "word", getline(1)) + exe "norm! I \" + call assert_equal(repeat(" ", 20) . "word", getline(1)) + + exe "norm! I \" + call assert_equal(repeat(" ", 20) . "word", getline(1)) + exe "norm! I " + exe "norm! 24|i\" + call assert_equal(repeat(" ", 20) . "word", getline(1)) + exe "norm! A\" + call assert_equal(repeat(" ", 15) . "word", getline(1)) + exe "norm! I " + exe "norm! A\\" + call assert_equal(repeat(" ", 10) . "word", getline(1)) + exe "norm! I\\\" + call assert_equal(repeat(" ", 0) . "word", getline(1)) + exe "norm! I\" + 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\" + call assert_equal(repeat(" ", 14) . "word", getline(1)) + exe "norm! A\" + call assert_equal(repeat(" ", 21) . "word", getline(1)) + exe "norm! I \" + call assert_equal(repeat(" ", 28) . "word", getline(1)) + + exe "norm! I \" + call assert_equal(repeat(" ", 28) . "word", getline(1)) + exe "norm! I " + exe "norm! 32|i\" + call assert_equal(repeat(" ", 28) . "word", getline(1)) + exe "norm! A\" + call assert_equal(repeat(" ", 21) . "word", getline(1)) + exe "norm! I " + exe "norm! A\\" + call assert_equal(repeat(" ", 14) . "word", getline(1)) + exe "norm! I\\\" + call assert_equal(repeat(" ", 0) . "word", getline(1)) + exe "norm! I\" + call assert_equal(repeat(" ", 0) . "word", getline(1)) + + set expandtab& shiftwidth& tabstop& + bw! +endfunc + +" Test shifting lines with and , 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\" + call assert_equal(repeat(" ", 19) . "word", getline(1)) + exe "norm! A\" + call assert_equal(repeat(" ", 36) . "word", getline(1)) + exe "norm! I \" + call assert_equal(repeat(" ", 47) . "word", getline(1)) + + exe "norm! I \" + call assert_equal(repeat(" ", 47) . "word", getline(1)) + exe "norm! I " + exe "norm! 51|i\" + call assert_equal(repeat(" ", 47) . "word", getline(1)) + exe "norm! A\" + call assert_equal(repeat(" ", 36) . "word", getline(1)) + exe "norm! I " + exe "norm! A\\" + call assert_equal(repeat(" ", 19) . "word", getline(1)) + exe "norm! I\\\" + call assert_equal(repeat(" ", 0) . "word", getline(1)) + exe "norm! I\" + call assert_equal(repeat(" ", 0) . "word", getline(1)) + + set expandtab& shiftwidth& vartabstop& + bw! endfunc " vim: shiftwidth=2 sts=2 expandtab