Hi Bram! On Do, 09 Mär 2017, Bram Moolenaar wrote:
> This can use skipwhite(). There are several other places where this > computation is done, e.g. in misc1.c, open_line(): > > p = ml_get_curline(); > ai_col = (colnr_T)(skipwhite(p) - p); > > Similar one a bit further down. > > Would be good to put this function close to skipwhite() to make it > easeri to find. Attached patch does that. > > > + /* if indent kicked in, the firstline might have changed > > + * but only do that, if the indent actually increased */ > > + ind_post = get_whitespace_line_start(curwin->w_cursor.lnum); > > + if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre) > > + { > > + bd.textcol += ind_post - ind_pre; > > + bd.start_vcol += ind_post - ind_pre; > > + } > > Why only for when the indent increases? To be on the safe side. Currently blockwise editing only allows for actually adding text. This expectation isn't documented yet, so I documented it. Best, Christian -- Ohne Spekulation gibt es keine neue Beobachtung. -- Charles Darwin -- -- 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 acb35eb468a2b34fe86d730685f90adf84d2d2a4 Mon Sep 17 00:00:00 2001 From: Christian Brabandt <c...@256bit.org> Date: Sun, 26 Feb 2017 21:48:21 +0100 Subject: [PATCH] Fix block-insert when indenting kicks in This fixes #1269 / https://groups.google.com/d/msg/vim_dev/uMsaEfGexoI/j8NlqiHeCgAJ --- runtime/doc/visual.txt | 3 ++- src/charset.c | 23 +++++++++++++++++++++++ src/edit.c | 7 +++---- src/misc1.c | 6 ++---- src/ops.c | 19 +++++++++++++++---- src/proto/charset.pro | 3 +++ src/proto/misc1.pro | 1 + src/screen.c | 2 +- src/spell.c | 6 +++--- src/testdir/test_cindent.vim | 19 +++++++++++++++++++ 10 files changed, 72 insertions(+), 17 deletions(-) diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt index 0a91b9f48..039aac958 100644 --- a/runtime/doc/visual.txt +++ b/runtime/doc/visual.txt @@ -314,7 +314,7 @@ Visual-block Insert *v_b_I* With a blockwise selection, I{string}<ESC> will insert {string} at the start of block on every line of the block, provided that the line extends into the block. Thus lines that are short will remain unmodified. TABs are split to -retain visual columns. +retain visual columns. Works only for adding text to a line, no deletions. See |v_b_I_example|. Visual-block Append *v_b_A* @@ -331,6 +331,7 @@ See |v_b_A_example|. Note: "I" and "A" behave differently for lines that don't extend into the selected block. This was done intentionally, so that you can do it the way you want. +Works only for adding text to a line, no deletions. Visual-block change *v_b_c* All selected text in the block will be replaced by the same text string. When diff --git a/src/charset.c b/src/charset.c index 29c587b52..867961dff 100644 --- a/src/charset.c +++ b/src/charset.c @@ -1536,6 +1536,29 @@ skipwhite(char_u *q) } /* + * getwhitecols: return the number of whitespace + * columns (bytes) at the start of a given line + */ + int +getwhitecols_line(linenr_T lnum) +{ + + return getwhitecols(ml_get(lnum)); +} + + int +getwhitecols_curline() +{ + return getwhitecols(ml_get_curline()); +} + + int +getwhitecols(char_u *p) +{ + return skipwhite(p) - p; +} + +/* * skip over digits */ char_u * diff --git a/src/edit.c b/src/edit.c index 35fa23b7d..1dedcd425 100644 --- a/src/edit.c +++ b/src/edit.c @@ -5151,7 +5151,7 @@ ins_complete(int c, int enable_pum) * first non_blank in the line, if it is not a wordchar * include it to get a better pattern, but then we don't * want the "\\<" prefix, check it bellow */ - compl_col = (colnr_T)(skipwhite(line) - line); + compl_col = (colnr_T)getwhitecols(line); compl_startpos.col = compl_col; compl_startpos.lnum = curwin->w_cursor.lnum; compl_cont_status &= ~CONT_SOL; /* clear SOL if present */ @@ -5317,7 +5317,7 @@ ins_complete(int c, int enable_pum) } else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) { - compl_col = (colnr_T)(skipwhite(line) - line); + compl_col = (colnr_T)getwhitecols(line); compl_length = (int)curs_col - (int)compl_col; if (compl_length < 0) /* cursor in indent: empty pattern */ compl_length = 0; @@ -8175,8 +8175,7 @@ in_cinkeys( { /* "0=word": Check if there are only blanks before the * word. */ - line = ml_get_curline(); - if ((int)(skipwhite(line) - line) != + if (getwhitecols(line) != (int)(curwin->w_cursor.col - (p - look))) match = FALSE; } diff --git a/src/misc1.c b/src/misc1.c index 3379e757d..158c77b26 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -1586,8 +1586,7 @@ open_line( && curbuf->b_p_ai) { fixthisline(get_lisp_indent); - p = ml_get_curline(); - ai_col = (colnr_T)(skipwhite(p) - p); + ai_col = (colnr_T)getwhitecols_curline(); } #endif #ifdef FEAT_CINDENT @@ -1605,8 +1604,7 @@ open_line( : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum))) { do_c_expr_indent(); - p = ml_get_curline(); - ai_col = (colnr_T)(skipwhite(p) - p); + ai_col = (colnr_T)getwhitecols_curline(); } #endif #if defined(FEAT_VREPLACE) && (defined(FEAT_LISP) || defined(FEAT_CINDENT)) diff --git a/src/ops.c b/src/ops.c index d3e97f07f..770baa181 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2502,6 +2502,7 @@ op_insert(oparg_T *oap, long count1) { long ins_len, pre_textlen = 0; char_u *firstline, *ins_text; + colnr_T ind_pre, ind_post; struct block_def bd; int i; pos_T t1; @@ -2536,7 +2537,10 @@ op_insert(oparg_T *oap, long count1) #endif /* Get the info about the block before entering the text */ block_prep(oap, &bd, oap->start.lnum, TRUE); + /* Get indent information */ + ind_pre = (colnr_T)getwhitecols_curline(); firstline = ml_get(oap->start.lnum) + bd.textcol; + if (oap->op_type == OP_APPEND) firstline += bd.textlen; pre_textlen = (long)STRLEN(firstline); @@ -2588,6 +2592,14 @@ op_insert(oparg_T *oap, long count1) && LT_POS(curbuf->b_op_start_orig, t1)) oap->start = curbuf->b_op_start_orig; + /* if indent kicked in, the firstline might have changed + * but only do that, if the indent actually increased */ + ind_post = (colnr_T)getwhitecols_curline(); + if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre) + { + bd.textcol += ind_post - ind_pre; + bd.start_vcol += ind_post - ind_pre; + } /* If user has moved off this line, we don't know what to do, so do * nothing. * Also don't repeat the insert when Insert mode ended with CTRL-C. */ @@ -2749,7 +2761,7 @@ op_change(oparg_T *oap) # endif firstline = ml_get(oap->start.lnum); pre_textlen = (long)STRLEN(firstline); - pre_indent = (long)(skipwhite(firstline) - firstline); + pre_indent = (long)getwhitecols(firstline); bd.textcol = curwin->w_cursor.col; } #endif @@ -2774,7 +2786,7 @@ op_change(oparg_T *oap) firstline = ml_get(oap->start.lnum); if (bd.textcol > (colnr_T)pre_indent) { - long new_indent = (long)(skipwhite(firstline) - firstline); + long new_indent = (long)getwhitecols(firstline); pre_textlen += new_indent - pre_indent; bd.textcol += new_indent - pre_indent; @@ -5050,8 +5062,7 @@ format_lines( #endif if (second_indent > 0) /* the "leader" for FO_Q_SECOND */ { - char_u *p = ml_get_curline(); - int indent = (int)(skipwhite(p) - p); + int indent = getwhitecols_curline(); if (indent > 0) { diff --git a/src/proto/charset.pro b/src/proto/charset.pro index 52b741a74..6a6e6a98d 100644 --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -35,6 +35,9 @@ colnr_T getvcol_nolist(pos_T *posp); void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end); void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right); char_u *skipwhite(char_u *q); +int getwhitecols_line(linenr_T lnum); +int getwhitecols_curline(void); +int getwhitecols(char_u *p); char_u *skipdigits(char_u *q); char_u *skipbin(char_u *q); char_u *skiphex(char_u *q); diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro index cac644969..4e299e5f9 100644 --- a/src/proto/misc1.pro +++ b/src/proto/misc1.pro @@ -1,4 +1,5 @@ /* misc1.c */ +int get_whitespace_line_start(linenr_T lnum); int get_indent(void); int get_indent_lnum(linenr_T lnum); int get_indent_buf(buf_T *buf, linenr_T lnum); diff --git a/src/screen.c b/src/screen.c index 206b50fc0..137e46bfa 100644 --- a/src/screen.c +++ b/src/screen.c @@ -3329,7 +3329,7 @@ win_line( { /* For checking first word with a capital skip white space. */ if (cap_col == 0) - cap_col = (int)(skipwhite(line) - line); + cap_col = getwhitecols(line); /* To be able to spell-check over line boundaries copy the end of the * current line into nextline[]. Above the start of the next line was diff --git a/src/spell.c b/src/spell.c index 1700bba0e..9cfbdda02 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1625,11 +1625,11 @@ spell_move_to( /* For checking first word with a capital skip white space. */ if (capcol == 0) - capcol = (int)(skipwhite(line) - line); + capcol = getwhitecols(line); else if (curline && wp == curwin) { /* For spellbadword(): check if first word needs a capital. */ - col = (int)(skipwhite(line) - line); + col = getwhitecols(line); if (check_need_cap(lnum, col)) capcol = col; @@ -3593,7 +3593,7 @@ check_need_cap(linenr_T lnum, colnr_T col) line = ml_get_curline(); endcol = 0; - if ((int)(skipwhite(line) - line) >= (int)col) + if (getwhitecols(line) >= (int)col) { /* At start of line, check if previous line is empty or sentence * ends there. */ diff --git a/src/testdir/test_cindent.vim b/src/testdir/test_cindent.vim index 444c4c410..5f9d9fd5b 100644 --- a/src/testdir/test_cindent.vim +++ b/src/testdir/test_cindent.vim @@ -73,4 +73,23 @@ func Test_cino_extern_c() bwipe! endfunc +func! Test_cindent_expr() + new + func! MyIndentFunction() + return v:lnum == 1 ? shiftwidth() : 0 + endfunc + setl expandtab sw=8 indentkeys+=; indentexpr=MyIndentFunction() + call setline(1, ['var_a = something()', 'b = something()']) + call cursor(1, 1) + call feedkeys("^\<c-v>j$A;\<esc>", 'tnix') + call assert_equal([' var_a = something();', 'b = something();'], getline(1, '$')) + + %d + call setline(1, [' var_a = something()', ' b = something()']) + call cursor(1, 1) + call feedkeys("^\<c-v>j$A;\<esc>", 'tnix') + call assert_equal([' var_a = something();', ' b = something()'], getline(1, '$')) + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab -- 2.11.0