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

@@ -445,6 +445,9 @@ SHIFTING LINES LEFT OR RIGHT *shift-left-right*
*<*
<{motion} Shift {motion} lines one 'shiftwidth' leftwards.
If the 'shiftwidth' option is set to zero, the amount
of indent is calculated at the first non-blank
character in the line.
*<<*
<< Shift [count] lines one 'shiftwidth' leftwards.
@@ -455,6 +458,9 @@ SHIFTING LINES LEFT OR RIGHT *shift-left-right*
*>*
>{motion} Shift {motion} lines one 'shiftwidth' rightwards.
If the 'shiftwidth' option is set to zero, the amount
of indent is calculated at the first non-blank
character in the line.
*>>*
>> Shift [count] lines one 'shiftwidth' rightwards.

View File

@@ -2308,7 +2308,6 @@ perleval({expr}) any evaluate |perl| expression
pow({x}, {y}) Float {x} to the power of {y}
prevnonblank({lnum}) Number line nr of non-blank line <= {lnum}
printf({fmt}, {expr1}...) String format text
prompt_addtext({buf}, {expr}) none add text to a prompt buffer
prompt_setcallback({buf}, {expr}) none set prompt callback function
prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
prompt_setprompt({buf}, {text}) none set prompt text
@@ -2393,7 +2392,7 @@ sha256({string}) String SHA256 checksum of {string}
shellescape({string} [, {special}])
String escape {string} for use as shell
command argument
shiftwidth() Number effective value of 'shiftwidth'
shiftwidth([{col}]) Number effective value of 'shiftwidth'
sign_define({name} [, {dict}]) Number define or update a sign
sign_getdefined([{name}]) List get a list of defined signs
sign_getplaced([{expr} [, {dict}]])
@@ -7899,7 +7898,7 @@ shellescape({string} [, {special}]) *shellescape()*
< See also |::S|.
shiftwidth() *shiftwidth()*
shiftwidth([{col}]) *shiftwidth()*
Returns the effective value of 'shiftwidth'. This is the
'shiftwidth' value unless it is zero, in which case it is the
'tabstop' value. To be backwards compatible in indent

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,')