On Do, 15 Nov 2018, Christian Brabandt wrote: > Ah, I have seen that error before and thought I fixed. That usually > happened when the buffer was not loaded. I'll have a closer look later. > I suppose that happen when running test86?
Here is an updated patch, that fixes the crash, and contains updated documentation and a test. Note, I changed the shiftwidth() function to accept an optional column number instead of a position List. However, I am not sure it makes sense. When developing the test, I found it actually confusing, that e.g. `>` depends on the actual cursor position. So using `norm! 0>>` will behave differently than `norm! $>>`. So it might be a better idea to simply document, that the shiftwidth() function will always return the `tabstop` setting instead of using whatever vartab setting is in effect for the current column (and also auto indenting will not respect the vartab feature, when the shiftwidth setting is zero). So here is an example, consider this example: :set sw=0 vartab=10,20,30,40 and the following line: x On hitting >>, the line will be shifted like this: x x x however, if you leave the cursor at the start of the line, the indent will rather look like this (e.g. using norm! 0>> x x x It might be confusing to the user to understand, why it was shifted one way and not the other. So I am not sure, if this change is actually justified. Best, Christian -- Zur Ehe gehört nicht bloß, daß man das Mädchen, sondern auch, daß man sich prüfe - ob nämlich 2 Vortreffliche dennoch sich einander nicht fügen. -- Jean Paul -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
From 18a9d5b8c8841dd7bfb491e36bbf69f98a199f4b Mon Sep 17 00:00:00 2001 From: Christian Brabandt <c...@256bit.org> Date: Wed, 14 Nov 2018 16:37:23 +0100 Subject: [PATCH] Return correct tabstop setting for 'sw'=0 and vartab When the vartab feature was merged into Vim with v8.1.0105, there was one feature forgotten. To return the actual tabstop value in effect when the shiftwidth setting is zero (|'shiftwidth'|) So fix this and make get_sw_value() return the actual vartabstop setting in effect, if it is enabled. This basically means, that get_sw_value() also needs to know the column number for which to return the correct vartab stop value. Therefore, return the value from the current cursor position. This also means, that the `shiftwidth()` function needs to be extended and returns the vartabstop value for a given position. So extend that function to use an optional position parameter and add some documentation. In addition, add a test to verify the feature. --- runtime/doc/change.txt | 8 +++++ runtime/doc/eval.txt | 12 +++++-- src/edit.c | 8 +++-- src/evalfunc.c | 16 ++++++++- src/normal.c | 1 + src/ops.c | 4 +-- src/option.c | 25 +++++++++++++- src/proto/edit.pro | 1 + src/proto/option.pro | 2 ++ src/testdir/test_vartabs.vim | 67 ++++++++++++++++++++++++++++++++++++ 10 files changed, 135 insertions(+), 9 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index d6b0242d2..22d616077 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 determined by the current cursor column. + *<<* << 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 determined by the current cursor column. + *>>* >> Shift [count] lines one 'shiftwidth' rightwards. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index bb80a665c..b32889f13 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2386,7 +2386,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' simplify({filename}) String simplify filename as much as possible sin({expr}) Float sine of {expr} sinh({expr}) Float hyperbolic sine of {expr} @@ -7639,11 +7639,17 @@ 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. This function was introduced with patch - 7.3.694 in 2012, everybody should have it by now. + 7.3.694 in 2012, everybody should have it by now (however it + did not allow for the optional {col} argument). + + 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..46302a4f7 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,20 @@ 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 d6559a2b1..f15866f44 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_pos(curbuf, &curwin->w_cursor); 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_pos(curbuf, &curwin->w_cursor); #ifdef FEAT_VARTABS int *p_vts = curbuf->b_p_vts_array; #endif diff --git a/src/option.c b/src/option.c index a4a9c9711..290df9fec 100644 --- a/src/option.c +++ b/src/option.c @@ -13085,7 +13085,30 @@ 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); +} + + 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; +} + + 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..38a9e4f42 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -72,6 +72,8 @@ 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_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..8499f3a5b 100644 --- a/src/testdir/test_vartabs.vim +++ b/src/testdir/test_vartabs.vim @@ -297,6 +297,73 @@ 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") + + let expect = ['x '] + let lines = ScreenLines(1, winwidth(0)) + call s:compare_lines(expect, lines) + " Test 1: + " shiftwidth depends on where the cursor is, therefore put it at the end of + " the line + norm! $>> + let expect = [' x '] + let lines = ScreenLines(1, winwidth(0)) + call s:compare_lines(expect, lines) + call assert_equal(10, shiftwidth()) + call assert_equal(10, shiftwidth(1)) + call assert_equal(20, shiftwidth(virtcol('.'))) + norm! $>> + let expect = [' x ', '~ '] + let lines = ScreenLines([1,2], winwidth(0)) + call s:compare_lines(expect, lines) + call assert_equal(20, shiftwidth(virtcol('.')-2)) + call assert_equal(30, shiftwidth(virtcol('.'))) + norm! $>> + let expect = [' ', ' x ', '~ '] + let lines = ScreenLines([1,3], winwidth(0)) + call s:compare_lines(expect, lines) + call assert_equal(30, shiftwidth(virtcol('.')-2)) + call assert_equal(40, shiftwidth(virtcol('.'))) + norm! $>> + let expect = [' ', ' ', ' x '] + let lines = ScreenLines([1, 3], winwidth(0)) + call assert_equal(40, shiftwidth(virtcol('.'))) + call s:compare_lines(expect, lines) + + " Test 2: Leave the cursor at the beginning of the line + call setline(1, "x") + norm! 0>> + let expect = [' x '] + let lines = ScreenLines(1, winwidth(0)) + call s:compare_lines(expect, lines) + norm! 0>> + let expect = [' x ', '~ '] + let lines = ScreenLines([1,2], winwidth(0)) + call s:compare_lines(expect, lines) + norm! 0>> + let expect = [' x ', '~ ', '~ '] + let lines = ScreenLines([1,3], winwidth(0)) + call s:compare_lines(expect, lines) + norm! 0>> + let expect = [' ', 'x '] + let lines = ScreenLines([1, 2], winwidth(0)) + call s:compare_lines(expect, lines) + + " cleanup + bw! + bw! +endfunc + func Test_vartabs_failures() call assert_fails('set vts=8,') call assert_fails('set vsts=8,') -- 2.18.0