vim-patch:8.0.1041: bogus characters when indenting during visual-block append

Problem:    Bogus characters appear when indenting kicks in while doing a
            visual-block append.
Solution:   Recompute when indenting is done. (Christian Brabandt)
e2e69e4813
This commit is contained in:
Jan Edmund Lazo 2018-08-23 04:43:44 -04:00
parent fe57a8a4e4
commit d677ae5f64
8 changed files with 62 additions and 21 deletions

View File

@ -302,8 +302,8 @@ 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.
See |v_b_I_example|.
retain visual columns. Works only for adding text to a line, not for
deletions. See |v_b_I_example|.
Visual-block Append *v_b_A*
With a blockwise selection, A{string}<ESC> will append {string} to the end of
@ -319,6 +319,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, not for deletions.
Visual-block change *v_b_c*
All selected text in the block will be replaced by the same text string. When

View File

@ -30,7 +30,7 @@
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/path.h"
#include "nvim/cursor.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "charset.c.generated.h"
@ -1465,6 +1465,18 @@ char_u *skipwhite(const char_u *q)
return (char_u *)p;
}
// getwhitecols: return the number of whitespace
// columns (bytes) at the start of a given line
intptr_t getwhitecols_curline(void)
{
return getwhitecols(get_cursor_line_ptr());
}
intptr_t getwhitecols(const char_u *p)
{
return skipwhite(p) - p;
}
/// Skip over digits
///
/// @param[in] q String to skip digits in.

View File

@ -4506,7 +4506,7 @@ static int ins_complete(int c, bool 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 */
@ -4625,7 +4625,7 @@ static int ins_complete(int c, bool 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;
@ -6963,8 +6963,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
if (match && try_match_word && !try_match) {
/* "0=word": Check if there are only blanks before the
* word. */
line = get_cursor_line_ptr();
if ((int)(skipwhite(line) - line) !=
if (getwhitecols(line) !=
(int)(curwin->w_cursor.col - (p - look)))
match = FALSE;
}

View File

@ -884,8 +884,7 @@ open_line (
&& curbuf->b_p_lisp
&& curbuf->b_p_ai) {
fixthisline(get_lisp_indent);
p = get_cursor_line_ptr();
ai_col = (colnr_T)(skipwhite(p) - p);
ai_col = (colnr_T)getwhitecols_curline();
}
/*
* May do indenting after opening a new line.
@ -898,8 +897,7 @@ open_line (
? KEY_OPEN_FORW
: KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum))) {
do_c_expr_indent();
p = get_cursor_line_ptr();
ai_col = (colnr_T)(skipwhite(p) - p);
ai_col = (colnr_T)getwhitecols_curline();
}
if (vreplace_mode != 0)
State = vreplace_mode;

View File

@ -2014,6 +2014,7 @@ void 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;
@ -2044,7 +2045,10 @@ void op_insert(oparg_T *oap, long count1)
}
// 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);
@ -2091,6 +2095,14 @@ void op_insert(oparg_T *oap, long count1)
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. */
@ -2216,7 +2228,7 @@ int op_change(oparg_T *oap)
}
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;
}
@ -2237,7 +2249,7 @@ int op_change(oparg_T *oap)
// the indent, exclude that indent change from the inserted text.
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 += (colnr_T)(new_indent - pre_indent);
@ -4122,8 +4134,7 @@ format_lines (
mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
(long)-next_leader_len);
} else if (second_indent > 0) { /* the "leader" for FO_Q_SECOND */
char_u *p = get_cursor_line_ptr();
int indent = (int)(skipwhite(p) - p);
int indent = (int)getwhitecols_curline();
if (indent > 0) {
(void)del_bytes(indent, FALSE, FALSE);

View File

@ -2462,7 +2462,7 @@ win_line (
if (has_spell) {
/* For checking first word with a capital skip white space. */
if (cap_col == 0)
cap_col = (int)(skipwhite(line) - line);
cap_col = (int)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

View File

@ -1399,10 +1399,10 @@ spell_move_to (
// For checking first word with a capital skip white space.
if (capcol == 0)
capcol = (int)(skipwhite(line) - line);
capcol = (int)getwhitecols(line);
else if (curline && wp == curwin) {
// For spellbadword(): check if first word needs a capital.
col = (int)(skipwhite(line) - line);
col = (int)getwhitecols(line);
if (check_need_cap(lnum, col))
capcol = col;
@ -2976,7 +2976,7 @@ static bool check_need_cap(linenr_T lnum, colnr_T col)
line = get_cursor_line_ptr();
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.
if (lnum == 1)

View File

@ -71,7 +71,7 @@ func Test_cino_extern_c()
bwipe!
endfunc
func! Test_cindent_rawstring()
func Test_cindent_rawstring()
new
setl cindent
call feedkeys("i" .
@ -81,5 +81,25 @@ func! Test_cindent_rawstring()
\ "statement;\<Esc>", "x")
call assert_equal("\tstatement;", getline(line('.')))
bw!
endfunction
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