# HG changeset patch # User vimboss # Date 1236785306 0 # Node ID df7ceb64b0c65cc5ea525f7df25ecdbba80b0208 # Parent d66394147eea6cd5b304fd2b78e5dde46fbb1b02 updated for version 7.2-137 diff --git a/src/ops.c b/src/ops.c --- a/src/ops.c +++ b/src/ops.c @@ -72,11 +72,11 @@ static struct yankreg *y_previous = NULL */ struct block_def { - int startspaces; /* 'extra' cols of first char */ - int endspaces; /* 'extra' cols of first char */ + int startspaces; /* 'extra' cols before first char */ + int endspaces; /* 'extra' cols after last char */ int textlen; /* chars in block */ - char_u *textstart; /* pointer to 1st char in block */ - colnr_T textcol; /* cols of chars (at least part.) in block */ + char_u *textstart; /* pointer to 1st char (partially) in block */ + colnr_T textcol; /* index of chars (partially) in block */ colnr_T start_vcol; /* start col of 1st char wholly inside block */ colnr_T end_vcol; /* start col of 1st char wholly after block */ #ifdef FEAT_VISUALEXTRA @@ -382,15 +382,14 @@ shift_block(oap, amount) { int left = (oap->op_type == OP_LSHIFT); int oldstate = State; - int total, split; - char_u *newp, *oldp, *midp, *ptr; + int total; + char_u *newp, *oldp; int oldcol = curwin->w_cursor.col; int p_sw = (int)curbuf->b_p_sw; int p_ts = (int)curbuf->b_p_ts; struct block_def bd; - int internal = 0; int incr; - colnr_T vcol, col = 0, ws_vcol; + colnr_T ws_vcol; int i = 0, j = 0; int len; @@ -456,67 +455,89 @@ shift_block(oap, amount) } else /* left */ { - vcol = oap->start_vcol; - /* walk vcol past ws to be removed */ - for (midp = oldp + bd.textcol; - vcol < (oap->start_vcol + total) && vim_iswhite(*midp); ) + colnr_T destination_col; /* column to which text in block will + be shifted */ + char_u *verbatim_copy_end; /* end of the part of the line which is + copied verbatim */ + colnr_T verbatim_copy_width;/* the (displayed) width of this part + of line */ + unsigned fill; /* nr of spaces that replace a TAB */ + unsigned new_line_len; /* the length of the line after the + block shift */ + size_t block_space_width; + size_t shift_amount; + char_u *non_white = bd.textstart; + colnr_T non_white_col; + + /* + * Firstly, let's find the first non-whitespace character that is + * displayed after the block's start column and the character's column + * number. Also, let's calculate the width of all the whitespace + * characters that are displayed in the block and precede the searched + * non-whitespace character. + */ + + /* If "bd.startspaces" is set, "bd.textstart" points to the character, + * the part of which is displayed at the block's beginning. Let's start + * searching from the next character. */ + if (bd.startspaces) + mb_ptr_adv(non_white); + + /* The character's column is in "bd.start_vcol". */ + non_white_col = bd.start_vcol; + + while (vim_iswhite(*non_white)) { - incr = lbr_chartabsize_adv(&midp, (colnr_T)vcol); - vcol += incr; - } - /* internal is the block-internal ws replacing a split TAB */ - if (vcol > (oap->start_vcol + total)) - { - /* we have to split the TAB *(midp-1) */ - internal = vcol - (oap->start_vcol + total); + incr = lbr_chartabsize_adv(&non_white, non_white_col); + non_white_col += incr; } - /* if 'expandtab' is not set, use TABs */ - - split = bd.startspaces + internal; - if (split > 0) + + block_space_width = non_white_col - oap->start_vcol; + /* We will shift by "total" or "block_space_width", whichever is less. + */ + shift_amount = (block_space_width < total? block_space_width: total); + + /* The column to which we will shift the text. */ + destination_col = non_white_col - shift_amount; + + /* Now let's find out how much of the beginning of the line we can + * reuse without modification. */ + verbatim_copy_end = bd.textstart; + verbatim_copy_width = bd.start_vcol; + + /* If "bd.startspaces" is set, "bd.textstart" points to the character + * preceding the block. We have to subtract its width to obtain its + * column number. */ + if (bd.startspaces) + verbatim_copy_width -= bd.start_char_vcols; + while (verbatim_copy_width < destination_col) { - if (!curbuf->b_p_et) - { - for (ptr = oldp, col = 0; ptr < oldp+bd.textcol; ) - col += lbr_chartabsize_adv(&ptr, (colnr_T)col); - - /* col+1 now equals the start col of the first char of the - * block (may be < oap.start_vcol if we're splitting a TAB) */ - i = ((col % p_ts) + split) / p_ts; /* number of tabs */ - } - if (i) - j = ((col % p_ts) + split) % p_ts; /* number of spp */ - else - j = split; + incr = lbr_chartabsize(verbatim_copy_end, verbatim_copy_width); + if (verbatim_copy_width + incr > destination_col) + break; + verbatim_copy_width += incr; + mb_ptr_adv(verbatim_copy_end); } - newp = alloc_check(bd.textcol + i + j + (unsigned)STRLEN(midp) + 1); + /* If "destination_col" is different from the width of the initial + * part of the line that will be copied, it means we encountered a tab + * character, which we will have to partly replace with spaces. */ + fill = destination_col - verbatim_copy_width; + + /* The replacement line will consist of: + * - the beginning of the original line up to "verbatim_copy_end", + * - "fill" number of spaces, + * - the rest of the line, pointed to by non_white. */ + new_line_len = (unsigned)(verbatim_copy_end - oldp) + + fill + + (unsigned)STRLEN(non_white) + 1; + + newp = alloc_check(new_line_len); if (newp == NULL) return; - vim_memset(newp, NUL, (size_t)(bd.textcol + i + j + STRLEN(midp) + 1)); - - /* copy first part we want to keep */ - mch_memmove(newp, oldp, (size_t)bd.textcol); - /* Now copy any TABS and spp to ensure correct alignment! */ - while (vim_iswhite(*midp)) - { - if (*midp == TAB) - i++; - else /*space */ - j++; - midp++; - } - /* We might have an extra TAB worth of spp now! */ - if (j / p_ts && !curbuf->b_p_et) - { - i++; - j -= p_ts; - } - copy_chars(newp + bd.textcol, (size_t)i, TAB); - copy_spaces(newp + bd.textcol + i, (size_t)j); - - /* the end */ - STRMOVE(newp + STRLEN(newp), midp); + mch_memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp)); + copy_spaces(newp + (verbatim_copy_end - oldp), (size_t)fill); + STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white); } /* replace the line */ ml_replace(curwin->w_cursor.lnum, newp, FALSE); @@ -4851,7 +4872,8 @@ paragraph_start(lnum) * - textlen includes the first/last char to be (partly) deleted * - start/endspaces is the number of columns that are taken by the * first/last deleted char minus the number of columns that have to be - * deleted. for yank and tilde: + * deleted. + * for yank and tilde: * - textlen includes the first/last char to be wholly yanked * - start/endspaces is the number of columns of the first/last yanked char * that are to be yanked. diff --git a/src/testdir/Makefile b/src/testdir/Makefile --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -20,7 +20,7 @@ SCRIPTS = test1.out test2.out test3.out test48.out test49.out test51.out test52.out test53.out \ test54.out test55.out test56.out test57.out test58.out \ test59.out test60.out test61.out test62.out test63.out \ - test64.out test65.out + test64.out test65.out test66.out SCRIPTS_GUI = test16.out diff --git a/src/testdir/test66.in b/src/testdir/test66.in new file mode 100644 --- /dev/null +++ b/src/testdir/test66.in @@ -0,0 +1,25 @@ + +Test for visual block shift and tab characters. + +STARTTEST +:so small.vim +/^abcdefgh +4jI j<<11|D +7|a  +7|a  +7|a 4k13|4j< +:$-4,$w! test.out +:$-4,$s/\s\+//g +4kI j<< +7|a  +7|a  +7|a 4k13|4j3< +:$-4,$w >> test.out +:qa! +ENDTEST + +abcdefghijklmnopqrstuvwxyz +abcdefghijklmnopqrstuvwxyz +abcdefghijklmnopqrstuvwxyz +abcdefghijklmnopqrstuvwxyz +abcdefghijklmnopqrstuvwxyz diff --git a/src/testdir/test66.ok b/src/testdir/test66.ok new file mode 100644 --- /dev/null +++ b/src/testdir/test66.ok @@ -0,0 +1,10 @@ + abcdefghijklmnopqrstuvwxyz +abcdefghij + abc defghijklmnopqrstuvwxyz + abc defghijklmnopqrstuvwxyz + abc defghijklmnopqrstuvwxyz + abcdefghijklmnopqrstuvwxyz +abcdefghij + abc defghijklmnopqrstuvwxyz + abc defghijklmnopqrstuvwxyz + abc defghijklmnopqrstuvwxyz diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -677,6 +677,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 137, +/**/ 136, /**/ 135,