vim-patch:8.1.0542: shiftwidth() does not take 'vartabstop' into account

Problem:    shiftwidth() does not take 'vartabstop' into account.
Solution:   Use the cursor position or a position explicitly passed.
            Also make >> and << work better with 'vartabstop'. (Christian
            Brabandt)
f951416a83
This commit is contained in:
VVKot
2021-02-13 20:02:48 +00:00
parent facb1d897e
commit 7fc58ec99a
9 changed files with 129 additions and 12 deletions

View File

@@ -9156,10 +9156,16 @@ static void ins_try_si(int c)
* Get the value that w_virtcol would have when 'list' is off.
* Unless 'cpo' contains the 'L' flag.
*/
static colnr_T get_nolist_virtcol(void)
colnr_T get_nolist_virtcol(void)
{
if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
// check validity of cursor in current buffer
if (curwin->w_buffer == NULL || curwin->w_buffer->b_ml.ml_mfp == NULL
|| curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count) {
return 0;
}
if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) {
return getvcol_nolist(&curwin->w_cursor);
}
validate_virtcol();
return curwin->w_virtcol;
}

View File

@@ -309,7 +309,7 @@ return {
setwinvar={args=3},
sha256={args=1},
shellescape={args={1, 2}},
shiftwidth={},
shiftwidth={args={0, 1}},
sign_define={args={1, 2}},
sign_getdefined={args={0, 1}},
sign_getplaced={args={0, 2}},

View File

@@ -8849,6 +8849,18 @@ static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = 0;
if (argvars[0].v_type != VAR_UNKNOWN) {
long col;
col = (long)tv_get_number_chk(argvars, NULL);
if (col < 0) {
return; // type error; errmsg already given
}
rettv->vval.v_number = get_sw_value_col(curbuf, col);
return;
}
rettv->vval.v_number = get_sw_value(curbuf);
}

View File

@@ -6777,9 +6777,10 @@ static void nv_g_cmd(cmdarg_T *cap)
}
coladvance((colnr_T)i);
if (flag) {
do
do {
i = gchar_cursor();
while (ascii_iswhite(i) && oneright());
} while (ascii_iswhite(i) && oneright());
curwin->w_valid &= ~VALID_WCOL;
}
curwin->w_set_curswant = true;
break;

View File

@@ -288,7 +288,7 @@ void shift_line(
{
int count;
int i, j;
int p_sw = get_sw_value(curbuf);
int p_sw = (int)get_sw_value_indent(curbuf);
count = get_indent(); // get current indent
@@ -332,9 +332,9 @@ static void shift_block(oparg_T *oap, int amount)
const int oldstate = State;
char_u *newp;
const int oldcol = curwin->w_cursor.col;
const int p_sw = get_sw_value(curbuf);
const long p_ts = curbuf->b_p_ts;
int p_sw = (int)get_sw_value_indent(curbuf);
long *p_vts = curbuf->b_p_vts_array;
const long p_ts = curbuf->b_p_ts;
struct block_def bd;
int incr;
int i = 0, j = 0;

View File

@@ -7342,11 +7342,39 @@ int tabstop_first(long *ts)
/// 'tabstop' value when 'shiftwidth' is zero.
int get_sw_value(buf_T *buf)
{
long result = buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts;
long result = get_sw_value_col(buf, 0);
assert(result >= 0 && result <= INT_MAX);
return (int)result;
}
// Idem, using the first non-black in the current line.
long get_sw_value_indent(buf_T *buf)
{
pos_T pos = curwin->w_cursor;
pos.col = (colnr_T)getwhitecols_curline();
return get_sw_value_pos(buf, &pos);
}
// Idem, using "pos".
long get_sw_value_pos(buf_T *buf, pos_T *pos)
{
pos_T save_cursor = curwin->w_cursor;
long sw_value;
curwin->w_cursor = *pos;
sw_value = get_sw_value_col(buf, get_nolist_virtcol());
curwin->w_cursor = save_cursor;
return sw_value;
}
// Idem, using virtual column "col".
long get_sw_value_col(buf_T *buf, colnr_T col)
{
return buf->b_p_sw ? buf->b_p_sw
: tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
}
/// Return the effective softtabstop value for the current buffer,
/// using the shiftwidth value when 'softtabstop' is negative.
int get_sts_value(void)

View File

@@ -297,6 +297,71 @@ func Test_vartabs_linebreak()
set nolist listchars&vim
endfunc
func Test_vartabs_shiftwidth()
"return
if winwidth(0) < 40
return
endif
new
40vnew
%d
" setl varsofttabstop=10,20,30,40
setl shiftwidth=0 vartabstop=10,20,30,40
call setline(1, "x")
" Check without any change.
let expect = ['x ']
let lines = ScreenLines(1, winwidth(0))
call s:compare_lines(expect, lines)
" Test 1:
" shiftwidth depends on the indent, first check with cursor at the end of the
" line (which is the same as the start of the line, since there is only one
" character).
norm! $>>
let expect1 = [' x ']
let lines = ScreenLines(1, winwidth(0))
call s:compare_lines(expect1, lines)
call assert_equal(10, shiftwidth())
call assert_equal(10, shiftwidth(1))
call assert_equal(20, shiftwidth(virtcol('.')))
norm! $>>
let expect2 = [' x ', '~ ']
let lines = ScreenLines([1, 2], winwidth(0))
call s:compare_lines(expect2, lines)
call assert_equal(20, shiftwidth(virtcol('.')-2))
call assert_equal(30, shiftwidth(virtcol('.')))
norm! $>>
let expect3 = [' ', ' x ', '~ ']
let lines = ScreenLines([1, 3], winwidth(0))
call s:compare_lines(expect3, lines)
call assert_equal(30, shiftwidth(virtcol('.')-2))
call assert_equal(40, shiftwidth(virtcol('.')))
norm! $>>
let expect4 = [' ', ' ', ' x ']
let lines = ScreenLines([1, 3], winwidth(0))
call assert_equal(40, shiftwidth(virtcol('.')))
call s:compare_lines(expect4, lines)
" Test 2: Put the cursor at the first column, result should be the same
call setline(1, "x")
norm! 0>>
let lines = ScreenLines(1, winwidth(0))
call s:compare_lines(expect1, lines)
norm! 0>>
let lines = ScreenLines([1, 2], winwidth(0))
call s:compare_lines(expect2, lines)
norm! 0>>
let lines = ScreenLines([1, 3], winwidth(0))
call s:compare_lines(expect3, lines)
norm! 0>>
let lines = ScreenLines([1, 3], winwidth(0))
call s:compare_lines(expect4, lines)
" cleanup
bw!
bw!
endfunc
func Test_vartabs_failures()
call assert_fails('set vts=8,')
call assert_fails('set vsts=8,')