summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-11-22 03:08:29 +0100
committerBram Moolenaar <Bram@vim.org>2018-11-22 03:08:29 +0100
commitf951416a8396a54bbbe21de1a8b16716428549f2 (patch)
tree2903bb024e534d4a4c5004beef72f4dc38583b29
parent2b84949ad8f247e5d142e2fb1371b3e37567977a (diff)
downloadvim-git-f951416a8396a54bbbe21de1a8b16716428549f2.tar.gz
patch 8.1.0542: shiftwidth() does not take 'vartabstop' into accountv8.1.0542
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)
-rw-r--r--runtime/doc/change.txt8
-rw-r--r--runtime/doc/eval.txt21
-rw-r--r--src/edit.c8
-rw-r--r--src/evalfunc.c17
-rw-r--r--src/normal.c1
-rw-r--r--src/ops.c4
-rw-r--r--src/option.c43
-rw-r--r--src/proto/edit.pro1
-rw-r--r--src/proto/option.pro3
-rw-r--r--src/testdir/test_vartabs.vim65
-rw-r--r--src/version.c2
11 files changed, 155 insertions, 18 deletions
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index d6b0242d2..dc3a23c59 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -476,6 +476,10 @@ SHIFTING LINES LEFT OR RIGHT *shift-left-right*
*<*
<{motion} Shift {motion} lines one 'shiftwidth' leftwards.
+ If the 'vartabstop' feature is enabled, and 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.
@@ -487,6 +491,10 @@ SHIFTING LINES LEFT OR RIGHT *shift-left-right*
*>*
>{motion} Shift {motion} lines one 'shiftwidth' rightwards.
+ If the 'vartabstop' feature is enabled, and 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.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 07c88d114..5e6545cbd 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -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
@@ -2386,7 +2385,7 @@ sha256({string}) String SHA256 checksum of {string}
shellescape({string} [, {special}])
String escape {string} for use as shell
command argument
-shiftwidth([{list}]) Number effective value of 'shiftwidth'
+shiftwidth([{col}]) Number effective value of 'shiftwidth'
simplify({filename}) String simplify filename as much as possible
sin({expr}) Float sine of {expr}
sinh({expr}) Float hyperbolic sine of {expr}
@@ -7639,19 +7638,17 @@ shellescape({string} [, {special}]) *shellescape()*
< See also |::S|.
-shiftwidth([{list}]) *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. This function was introduced with patch
- 7.3.694 in 2012, everybody should have it by now.
-
- When there is one argument {list} this is used as position
- |List| for which to return the 'shiftwidth' value (actually
- only the column number is relevant). This matters for the
- 'vartabstop' feature. For the {list} arguments see |cursor()|
- function. If the 'vartabstop' setting is enabled and no
- {list} argument is given, the current cursor position is
- taken into account.
+ 7.3.694 in 2012, everybody should have it by now (however it
+ did not allow for the optional {col} argument until 8.1.542).
+
+ When there is one argument {col} this is used as column number
+ for which to return the 'shiftwidth' value. This matters for the
+ 'vartabstop' feature. If the 'vartabstop' setting is enabled and
+ no {col} argument is given, column 1 will be assumed.
simplify({filename}) *simplify()*
diff --git a/src/edit.c b/src/edit.c
index 239881ee5..6b5bc0f63 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -262,7 +262,6 @@ static int ins_ctrl_ey(int tc);
#ifdef FEAT_SMARTINDENT
static void ins_try_si(int c);
#endif
-static colnr_T get_nolist_virtcol(void);
#if defined(FEAT_EVAL)
static char_u *do_insert_char_pre(int c);
#endif
@@ -10681,9 +10680,14 @@ 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
+ colnr_T
get_nolist_virtcol(void)
{
+ // 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();
diff --git a/src/evalfunc.c b/src/evalfunc.c
index f55739ed5..d3bacad77 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -835,7 +835,7 @@ static struct fst
{"sha256", 1, 1, f_sha256},
#endif
{"shellescape", 1, 2, f_shellescape},
- {"shiftwidth", 0, 0, f_shiftwidth},
+ {"shiftwidth", 0, 1, f_shiftwidth},
{"simplify", 1, 1, f_simplify},
#ifdef FEAT_FLOAT
{"sin", 1, 1, f_sin},
@@ -11241,6 +11241,21 @@ f_shellescape(typval_T *argvars, typval_T *rettv)
static void
f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
{
+ rettv->vval.v_number = 0;
+
+ if (argvars[0].v_type != VAR_UNKNOWN)
+ {
+ long col;
+
+ col = (long)get_tv_number_chk(argvars, NULL);
+ if (col < 0)
+ return; // type error; errmsg already given
+#ifdef FEAT_VARTABS
+ rettv->vval.v_number = get_sw_value_col(curbuf, col);
+ return;
+#endif
+ }
+
rettv->vval.v_number = get_sw_value(curbuf);
}
diff --git a/src/normal.c b/src/normal.c
index a0683b207..5310824ee 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -8143,6 +8143,7 @@ nv_g_cmd(cmdarg_T *cap)
do
i = gchar_cursor();
while (VIM_ISWHITE(i) && oneright() == OK);
+ curwin->w_valid &= ~VALID_WCOL;
}
curwin->w_set_curswant = TRUE;
break;
diff --git a/src/ops.c b/src/ops.c
index 7564fac7d..004d5093c 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -334,7 +334,7 @@ shift_line(
{
int count;
int i, j;
- int p_sw = (int)get_sw_value(curbuf);
+ int p_sw = (int)get_sw_value_indent(curbuf);
count = get_indent(); /* get current indent */
@@ -386,7 +386,7 @@ shift_block(oparg_T *oap, int amount)
int total;
char_u *newp, *oldp;
int oldcol = curwin->w_cursor.col;
- int p_sw = (int)get_sw_value(curbuf);
+ int p_sw = (int)get_sw_value_indent(curbuf);
#ifdef FEAT_VARTABS
int *p_vts = curbuf->b_p_vts_array;
#endif
diff --git a/src/option.c b/src/option.c
index 50d405a95..fdb99addd 100644
--- a/src/option.c
+++ b/src/option.c
@@ -13113,7 +13113,48 @@ tabstop_first(int *ts)
long
get_sw_value(buf_T *buf)
{
- return buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts;
+ return get_sw_value_col(buf, 0);
+}
+
+/*
+ * 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 = 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 UNUSED)
+{
+ return buf->b_p_sw ? buf->b_p_sw :
+ #ifdef FEAT_VARTABS
+ tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
+ #else
+ buf->b_p_ts;
+ #endif
}
/*
diff --git a/src/proto/edit.pro b/src/proto/edit.pro
index 9ba71645b..768af3a48 100644
--- a/src/proto/edit.pro
+++ b/src/proto/edit.pro
@@ -46,4 +46,5 @@ int bracketed_paste(paste_mode_T mode, int drop, garray_T *gap);
void ins_scroll(void);
void ins_horscroll(void);
int ins_copychar(linenr_T lnum);
+colnr_T get_nolist_virtcol(void);
/* vim: set ft=c : */
diff --git a/src/proto/option.pro b/src/proto/option.pro
index 228036587..b198c7516 100644
--- a/src/proto/option.pro
+++ b/src/proto/option.pro
@@ -72,6 +72,9 @@ int *tabstop_copy(int *oldts);
int tabstop_count(int *ts);
int tabstop_first(int *ts);
long get_sw_value(buf_T *buf);
+long get_sw_value_indent(buf_T *buf);
+long get_sw_value_pos(buf_T *buf, pos_T *pos);
+long get_sw_value_col(buf_T *buf, colnr_T col);
long get_sts_value(void);
void find_mps_values(int *initc, int *findc, int *backwards, int switchit);
unsigned int get_bkc_value(buf_T *buf);
diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim
index c8470952d..81e81b7fb 100644
--- a/src/testdir/test_vartabs.vim
+++ b/src/testdir/test_vartabs.vim
@@ -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,')
diff --git a/src/version.c b/src/version.c
index 37f4b1f47..82b8abe5d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -793,6 +793,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 542,
+/**/
541,
/**/
540,