Skip to content

Commit f951416

Browse files
committed
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)
1 parent 2b84949 commit f951416

11 files changed

Lines changed: 155 additions & 18 deletions

File tree

runtime/doc/change.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,10 @@ SHIFTING LINES LEFT OR RIGHT *shift-left-right*
476476
*<*
477477
<{motion} Shift {motion} lines one 'shiftwidth' leftwards.
478478

479+
If the 'vartabstop' feature is enabled, and the
480+
'shiftwidth' option is set to zero, the amount of
481+
indent is calculated at the first non-blank character
482+
in the line.
479483
*<<*
480484
<< Shift [count] lines one 'shiftwidth' leftwards.
481485

@@ -487,6 +491,10 @@ SHIFTING LINES LEFT OR RIGHT *shift-left-right*
487491
*>*
488492
>{motion} Shift {motion} lines one 'shiftwidth' rightwards.
489493

494+
If the 'vartabstop' feature is enabled, and the
495+
'shiftwidth' option is set to zero, the amount of
496+
indent is calculated at the first non-blank character
497+
in the line.
490498
*>>*
491499
>> Shift [count] lines one 'shiftwidth' rightwards.
492500

runtime/doc/eval.txt

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,7 +2308,6 @@ perleval({expr}) any evaluate |Perl| expression
23082308
pow({x}, {y}) Float {x} to the power of {y}
23092309
prevnonblank({lnum}) Number line nr of non-blank line <= {lnum}
23102310
printf({fmt}, {expr1}...) String format text
2311-
prompt_addtext({buf}, {expr}) none add text to a prompt buffer
23122311
prompt_setcallback({buf}, {expr}) none set prompt callback function
23132312
prompt_setinterrupt({buf}, {text}) none set prompt interrupt function
23142313
prompt_setprompt({buf}, {text}) none set prompt text
@@ -2386,7 +2385,7 @@ sha256({string}) String SHA256 checksum of {string}
23862385
shellescape({string} [, {special}])
23872386
String escape {string} for use as shell
23882387
command argument
2389-
shiftwidth([{list}]) Number effective value of 'shiftwidth'
2388+
shiftwidth([{col}]) Number effective value of 'shiftwidth'
23902389
simplify({filename}) String simplify filename as much as possible
23912390
sin({expr}) Float sine of {expr}
23922391
sinh({expr}) Float hyperbolic sine of {expr}
@@ -7639,19 +7638,17 @@ shellescape({string} [, {special}]) *shellescape()*
76397638
< See also |::S|.
76407639

76417640

7642-
shiftwidth([{list}]) *shiftwidth()*
7641+
shiftwidth([{col}]) *shiftwidth()*
76437642
Returns the effective value of 'shiftwidth'. This is the
76447643
'shiftwidth' value unless it is zero, in which case it is the
76457644
'tabstop' value. This function was introduced with patch
7646-
7.3.694 in 2012, everybody should have it by now.
7647-
7648-
When there is one argument {list} this is used as position
7649-
|List| for which to return the 'shiftwidth' value (actually
7650-
only the column number is relevant). This matters for the
7651-
'vartabstop' feature. For the {list} arguments see |cursor()|
7652-
function. If the 'vartabstop' setting is enabled and no
7653-
{list} argument is given, the current cursor position is
7654-
taken into account.
7645+
7.3.694 in 2012, everybody should have it by now (however it
7646+
did not allow for the optional {col} argument until 8.1.542).
7647+
7648+
When there is one argument {col} this is used as column number
7649+
for which to return the 'shiftwidth' value. This matters for the
7650+
'vartabstop' feature. If the 'vartabstop' setting is enabled and
7651+
no {col} argument is given, column 1 will be assumed.
76557652

76567653

76577654
simplify({filename}) *simplify()*

src/edit.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,6 @@ static int ins_ctrl_ey(int tc);
262262
#ifdef FEAT_SMARTINDENT
263263
static void ins_try_si(int c);
264264
#endif
265-
static colnr_T get_nolist_virtcol(void);
266265
#if defined(FEAT_EVAL)
267266
static char_u *do_insert_char_pre(int c);
268267
#endif
@@ -10681,9 +10680,14 @@ ins_try_si(int c)
1068110680
* Get the value that w_virtcol would have when 'list' is off.
1068210681
* Unless 'cpo' contains the 'L' flag.
1068310682
*/
10684-
static colnr_T
10683+
colnr_T
1068510684
get_nolist_virtcol(void)
1068610685
{
10686+
// check validity of cursor in current buffer
10687+
if (curwin->w_buffer == NULL
10688+
|| curwin->w_buffer->b_ml.ml_mfp == NULL
10689+
|| curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count)
10690+
return 0;
1068710691
if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
1068810692
return getvcol_nolist(&curwin->w_cursor);
1068910693
validate_virtcol();

src/evalfunc.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ static struct fst
835835
{"sha256", 1, 1, f_sha256},
836836
#endif
837837
{"shellescape", 1, 2, f_shellescape},
838-
{"shiftwidth", 0, 0, f_shiftwidth},
838+
{"shiftwidth", 0, 1, f_shiftwidth},
839839
{"simplify", 1, 1, f_simplify},
840840
#ifdef FEAT_FLOAT
841841
{"sin", 1, 1, f_sin},
@@ -11241,6 +11241,21 @@ f_shellescape(typval_T *argvars, typval_T *rettv)
1124111241
static void
1124211242
f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
1124311243
{
11244+
rettv->vval.v_number = 0;
11245+
11246+
if (argvars[0].v_type != VAR_UNKNOWN)
11247+
{
11248+
long col;
11249+
11250+
col = (long)get_tv_number_chk(argvars, NULL);
11251+
if (col < 0)
11252+
return; // type error; errmsg already given
11253+
#ifdef FEAT_VARTABS
11254+
rettv->vval.v_number = get_sw_value_col(curbuf, col);
11255+
return;
11256+
#endif
11257+
}
11258+
1124411259
rettv->vval.v_number = get_sw_value(curbuf);
1124511260
}
1124611261

src/normal.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8143,6 +8143,7 @@ nv_g_cmd(cmdarg_T *cap)
81438143
do
81448144
i = gchar_cursor();
81458145
while (VIM_ISWHITE(i) && oneright() == OK);
8146+
curwin->w_valid &= ~VALID_WCOL;
81468147
}
81478148
curwin->w_set_curswant = TRUE;
81488149
break;

src/ops.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ shift_line(
334334
{
335335
int count;
336336
int i, j;
337-
int p_sw = (int)get_sw_value(curbuf);
337+
int p_sw = (int)get_sw_value_indent(curbuf);
338338

339339
count = get_indent(); /* get current indent */
340340

@@ -386,7 +386,7 @@ shift_block(oparg_T *oap, int amount)
386386
int total;
387387
char_u *newp, *oldp;
388388
int oldcol = curwin->w_cursor.col;
389-
int p_sw = (int)get_sw_value(curbuf);
389+
int p_sw = (int)get_sw_value_indent(curbuf);
390390
#ifdef FEAT_VARTABS
391391
int *p_vts = curbuf->b_p_vts_array;
392392
#endif

src/option.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13113,7 +13113,48 @@ tabstop_first(int *ts)
1311313113
long
1311413114
get_sw_value(buf_T *buf)
1311513115
{
13116-
return buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts;
13116+
return get_sw_value_col(buf, 0);
13117+
}
13118+
13119+
/*
13120+
* Idem, using the first non-black in the current line.
13121+
*/
13122+
long
13123+
get_sw_value_indent(buf_T *buf)
13124+
{
13125+
pos_T pos = curwin->w_cursor;
13126+
13127+
pos.col = getwhitecols_curline();
13128+
return get_sw_value_pos(buf, &pos);
13129+
}
13130+
13131+
/*
13132+
* Idem, using "pos".
13133+
*/
13134+
long
13135+
get_sw_value_pos(buf_T *buf, pos_T *pos)
13136+
{
13137+
pos_T save_cursor = curwin->w_cursor;
13138+
long sw_value;
13139+
13140+
curwin->w_cursor = *pos;
13141+
sw_value = get_sw_value_col(buf, get_nolist_virtcol());
13142+
curwin->w_cursor = save_cursor;
13143+
return sw_value;
13144+
}
13145+
13146+
/*
13147+
* Idem, using virtual column "col".
13148+
*/
13149+
long
13150+
get_sw_value_col(buf_T *buf, colnr_T col UNUSED)
13151+
{
13152+
return buf->b_p_sw ? buf->b_p_sw :
13153+
#ifdef FEAT_VARTABS
13154+
tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
13155+
#else
13156+
buf->b_p_ts;
13157+
#endif
1311713158
}
1311813159

1311913160
/*

src/proto/edit.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ int bracketed_paste(paste_mode_T mode, int drop, garray_T *gap);
4646
void ins_scroll(void);
4747
void ins_horscroll(void);
4848
int ins_copychar(linenr_T lnum);
49+
colnr_T get_nolist_virtcol(void);
4950
/* vim: set ft=c : */

src/proto/option.pro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ int *tabstop_copy(int *oldts);
7272
int tabstop_count(int *ts);
7373
int tabstop_first(int *ts);
7474
long get_sw_value(buf_T *buf);
75+
long get_sw_value_indent(buf_T *buf);
76+
long get_sw_value_pos(buf_T *buf, pos_T *pos);
77+
long get_sw_value_col(buf_T *buf, colnr_T col);
7578
long get_sts_value(void);
7679
void find_mps_values(int *initc, int *findc, int *backwards, int switchit);
7780
unsigned int get_bkc_value(buf_T *buf);

src/testdir/test_vartabs.vim

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,71 @@ func Test_vartabs_linebreak()
297297
set nolist listchars&vim
298298
endfunc
299299

300+
func Test_vartabs_shiftwidth()
301+
"return
302+
if winwidth(0) < 40
303+
return
304+
endif
305+
new
306+
40vnew
307+
%d
308+
" setl varsofttabstop=10,20,30,40
309+
setl shiftwidth=0 vartabstop=10,20,30,40
310+
call setline(1, "x")
311+
312+
" Check without any change.
313+
let expect = ['x ']
314+
let lines = ScreenLines(1, winwidth(0))
315+
call s:compare_lines(expect, lines)
316+
" Test 1:
317+
" shiftwidth depends on the indent, first check with cursor at the end of the
318+
" line (which is the same as the start of the line, since there is only one
319+
" character).
320+
norm! $>>
321+
let expect1 = [' x ']
322+
let lines = ScreenLines(1, winwidth(0))
323+
call s:compare_lines(expect1, lines)
324+
call assert_equal(10, shiftwidth())
325+
call assert_equal(10, shiftwidth(1))
326+
call assert_equal(20, shiftwidth(virtcol('.')))
327+
norm! $>>
328+
let expect2 = [' x ', '~ ']
329+
let lines = ScreenLines([1, 2], winwidth(0))
330+
call s:compare_lines(expect2, lines)
331+
call assert_equal(20, shiftwidth(virtcol('.')-2))
332+
call assert_equal(30, shiftwidth(virtcol('.')))
333+
norm! $>>
334+
let expect3 = [' ', ' x ', '~ ']
335+
let lines = ScreenLines([1, 3], winwidth(0))
336+
call s:compare_lines(expect3, lines)
337+
call assert_equal(30, shiftwidth(virtcol('.')-2))
338+
call assert_equal(40, shiftwidth(virtcol('.')))
339+
norm! $>>
340+
let expect4 = [' ', ' ', ' x ']
341+
let lines = ScreenLines([1, 3], winwidth(0))
342+
call assert_equal(40, shiftwidth(virtcol('.')))
343+
call s:compare_lines(expect4, lines)
344+
345+
" Test 2: Put the cursor at the first column, result should be the same
346+
call setline(1, "x")
347+
norm! 0>>
348+
let lines = ScreenLines(1, winwidth(0))
349+
call s:compare_lines(expect1, lines)
350+
norm! 0>>
351+
let lines = ScreenLines([1, 2], winwidth(0))
352+
call s:compare_lines(expect2, lines)
353+
norm! 0>>
354+
let lines = ScreenLines([1, 3], winwidth(0))
355+
call s:compare_lines(expect3, lines)
356+
norm! 0>>
357+
let lines = ScreenLines([1, 3], winwidth(0))
358+
call s:compare_lines(expect4, lines)
359+
360+
" cleanup
361+
bw!
362+
bw!
363+
endfunc
364+
300365
func Test_vartabs_failures()
301366
call assert_fails('set vts=8,')
302367
call assert_fails('set vsts=8,')

0 commit comments

Comments
 (0)