# HG changeset patch # User Bram Moolenaar # Date 1403699990 -7200 # Node ID ef83b423ebf7de11c1063c795dd2186a9b59b90f # Parent ca18c797aafe3df7d8db0dbfcdfb68b712776967 updated for version 7.4.338 Problem: Cannot wrap lines taking indent into account. Solution: Add the 'breakindent' option. (many authors, final improvements by Christian Brabandt) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -6651,8 +6651,8 @@ jumplist Compiled with |jumplist| suppo keymap Compiled with 'keymap' support. langmap Compiled with 'langmap' support. libcall Compiled with |libcall()| support. -linebreak Compiled with 'linebreak', 'breakat' and 'showbreak' - support. +linebreak Compiled with 'linebreak', 'breakat', 'showbreak' and + 'breakindent' support. lispindent Compiled with support for lisp indenting. listcmds Compiled with commands for the buffer list |:files| and the argument list |arglist|. diff --git a/runtime/optwin.vim b/runtime/optwin.vim --- a/runtime/optwin.vim +++ b/runtime/optwin.vim @@ -324,6 +324,12 @@ call BinOptionG("wrap", &wrap) call append("$", "linebreak\twrap long lines at a character in 'breakat'") call append("$", "\t(local to window)") call BinOptionL("lbr") +call append("$", "breakindent\tpreserve indentation in wrapped text") +call append("$", "\t(local to window)") +call BinOptionL("bri") +call append("$", "breakindentopt\tadjust breakindent behaviour") +call append("$", "\t(local to window)") +call OptionL("briopt") call append("$", "breakat\twhich characters might cause a line break") call OptionG("brk", &brk) call append("$", "showbreak\tstring to put before wrapped screen lines") diff --git a/src/charset.c b/src/charset.c --- a/src/charset.c +++ b/src/charset.c @@ -867,9 +867,10 @@ linetabsize_col(startcol, s) char_u *s; { colnr_T col = startcol; + char_u *line = s; /* pointer to start of line, for breakindent */ while (*s != NUL) - col += lbr_chartabsize_adv(&s, col); + col += lbr_chartabsize_adv(line, &s, col); return (int)col; } @@ -877,16 +878,17 @@ linetabsize_col(startcol, s) * Like linetabsize(), but for a given window instead of the current one. */ int -win_linetabsize(wp, p, len) +win_linetabsize(wp, line, len) win_T *wp; - char_u *p; + char_u *line; colnr_T len; { colnr_T col = 0; char_u *s; - for (s = p; *s != NUL && (len == MAXCOL || s < p + len); mb_ptr_adv(s)) - col += win_lbr_chartabsize(wp, s, col, NULL); + for (s = line; *s != NUL && (len == MAXCOL || s < line + len); + mb_ptr_adv(s)) + col += win_lbr_chartabsize(wp, line, s, col, NULL); return (int)col; } @@ -1021,12 +1023,13 @@ vim_isprintc_strict(c) * like chartabsize(), but also check for line breaks on the screen */ int -lbr_chartabsize(s, col) +lbr_chartabsize(line, s, col) + char_u *line; /* start of the line */ unsigned char *s; colnr_T col; { #ifdef FEAT_LINEBREAK - if (!curwin->w_p_lbr && *p_sbr == NUL) + if (!curwin->w_p_lbr && *p_sbr == NUL && !curwin->w_p_bri) { #endif #ifdef FEAT_MBYTE @@ -1036,7 +1039,7 @@ lbr_chartabsize(s, col) RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col) #ifdef FEAT_LINEBREAK } - return win_lbr_chartabsize(curwin, s, col, NULL); + return win_lbr_chartabsize(curwin, line == NULL ? s : line, s, col, NULL); #endif } @@ -1044,13 +1047,14 @@ lbr_chartabsize(s, col) * Call lbr_chartabsize() and advance the pointer. */ int -lbr_chartabsize_adv(s, col) +lbr_chartabsize_adv(line, s, col) + char_u *line; /* start of the line */ char_u **s; colnr_T col; { int retval; - retval = lbr_chartabsize(*s, col); + retval = lbr_chartabsize(line, *s, col); mb_ptr_adv(*s); return retval; } @@ -1063,8 +1067,9 @@ lbr_chartabsize_adv(s, col) * value, init to 0 before calling. */ int -win_lbr_chartabsize(wp, s, col, headp) +win_lbr_chartabsize(wp, line, s, col, headp) win_T *wp; + char_u *line; /* start of the line */ char_u *s; colnr_T col; int *headp UNUSED; @@ -1086,9 +1091,9 @@ win_lbr_chartabsize(wp, s, col, headp) int n; /* - * No 'linebreak' and 'showbreak': return quickly. + * No 'linebreak', 'showbreak' and 'breakindent': return quickly. */ - if (!wp->w_p_lbr && *p_sbr == NUL) + if (!wp->w_p_lbr && !wp->w_p_bri && *p_sbr == NUL) #endif { #ifdef FEAT_MBYTE @@ -1163,11 +1168,12 @@ win_lbr_chartabsize(wp, s, col, headp) # endif /* - * May have to add something for 'showbreak' string at start of line + * May have to add something for 'breakindent' and/or 'showbreak' + * string at start of line. * Set *headp to the size of what we add. */ added = 0; - if (*p_sbr != NUL && wp->w_p_wrap && col != 0) + if ((*p_sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && col != 0) { numberextra = win_col_off(wp); col += numberextra + mb_added; @@ -1180,7 +1186,12 @@ win_lbr_chartabsize(wp, s, col, headp) } if (col == 0 || col + size > (colnr_T)W_WIDTH(wp)) { - added = vim_strsize(p_sbr); + added = 0; + if (*p_sbr != NUL) + added += vim_strsize(p_sbr); + if (wp->w_p_bri) + added += get_breakindent_win(wp, line); + if (tab_corr) size += (added / wp->w_buffer->b_p_ts) * wp->w_buffer->b_p_ts; else @@ -1274,13 +1285,14 @@ getvcol(wp, pos, start, cursor, end) colnr_T vcol; char_u *ptr; /* points to current char */ char_u *posptr; /* points to char at pos->col */ + char_u *line; /* start of the line */ int incr; int head; int ts = wp->w_buffer->b_p_ts; int c; vcol = 0; - ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE); + line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE); if (pos->col == MAXCOL) posptr = NULL; /* continue until the NUL */ else @@ -1288,12 +1300,13 @@ getvcol(wp, pos, start, cursor, end) /* * This function is used very often, do some speed optimizations. - * When 'list', 'linebreak' and 'showbreak' are not set use a simple loop. + * When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set + * use a simple loop. * Also use this when 'list' is set but tabs take their normal size. */ if ((!wp->w_p_list || lcs_tab1 != NUL) #ifdef FEAT_LINEBREAK - && !wp->w_p_lbr && *p_sbr == NUL + && !wp->w_p_lbr && *p_sbr == NUL && !wp->w_p_bri #endif ) { @@ -1355,7 +1368,7 @@ getvcol(wp, pos, start, cursor, end) { /* A tab gets expanded, depending on the current column */ head = 0; - incr = win_lbr_chartabsize(wp, ptr, vcol, &head); + incr = win_lbr_chartabsize(wp, line, ptr, vcol, &head); /* make sure we don't go past the end of the line */ if (*ptr == NUL) { diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -1956,7 +1956,7 @@ change_indent(type, amount, round, repla else #endif ++new_cursor_col; - vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol); + vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol); } vcol = last_vcol; @@ -7126,9 +7126,10 @@ oneleft() for (;;) { coladvance(v - width); - /* getviscol() is slow, skip it when 'showbreak' is empty and - * there are no multi-byte characters */ - if ((*p_sbr == NUL + /* getviscol() is slow, skip it when 'showbreak' is empty, + * 'breakindent' is not set and there are no multi-byte + * characters */ + if ((*p_sbr == NUL && !curwin->w_p_bri # ifdef FEAT_MBYTE && !has_mbyte # endif @@ -9758,11 +9759,11 @@ ins_tab() getvcol(curwin, &fpos, &vcol, NULL, NULL); getvcol(curwin, cursor, &want_vcol, NULL, NULL); - /* Use as many TABs as possible. Beware of 'showbreak' and - * 'linebreak' adding extra virtual columns. */ + /* Use as many TABs as possible. Beware of 'breakindent', 'showbreak' + * and 'linebreak' adding extra virtual columns. */ while (vim_iswhite(*ptr)) { - i = lbr_chartabsize((char_u *)"\t", vcol); + i = lbr_chartabsize(NULL, (char_u *)"\t", vcol); if (vcol + i > want_vcol) break; if (*ptr != TAB) @@ -9784,11 +9785,12 @@ ins_tab() if (change_col >= 0) { int repl_off = 0; + char_u *line = ptr; /* Skip over the spaces we need. */ while (vcol < want_vcol && *ptr == ' ') { - vcol += lbr_chartabsize(ptr, vcol); + vcol += lbr_chartabsize(line, ptr, vcol); ++ptr; ++repl_off; } @@ -10029,6 +10031,7 @@ ins_copychar(lnum) int c; int temp; char_u *ptr, *prev_ptr; + char_u *line; if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { @@ -10038,13 +10041,13 @@ ins_copychar(lnum) /* try to advance to the cursor column */ temp = 0; - ptr = ml_get(lnum); + line = ptr = ml_get(lnum); prev_ptr = ptr; validate_virtcol(); while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) { prev_ptr = ptr; - temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp); + temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp); } if ((colnr_T)temp > curwin->w_virtcol) ptr = prev_ptr; diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -2302,10 +2302,10 @@ getexmodeline(promptc, cookie, indent) p = (char_u *)line_ga.ga_data; p[line_ga.ga_len] = NUL; - indent = get_indent_str(p, 8); + indent = get_indent_str(p, 8, FALSE); indent += sw - indent % sw; add_indent: - while (get_indent_str(p, 8) < indent) + while (get_indent_str(p, 8, FALSE) < indent) { char_u *s = skipwhite(p); @@ -2357,11 +2357,11 @@ redraw: else { p[line_ga.ga_len] = NUL; - indent = get_indent_str(p, 8); + indent = get_indent_str(p, 8, FALSE); --indent; indent -= indent % get_sw_value(curbuf); } - while (get_indent_str(p, 8) > indent) + while (get_indent_str(p, 8, FALSE) > indent) { char_u *s = skipwhite(p); diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -2675,7 +2675,7 @@ vgetorpeek(advance) { if (!vim_iswhite(ptr[col])) curwin->w_wcol = vcol; - vcol += lbr_chartabsize(ptr + col, + vcol += lbr_chartabsize(ptr, ptr + col, (colnr_T)vcol); #ifdef FEAT_MBYTE if (has_mbyte) diff --git a/src/misc1.c b/src/misc1.c --- a/src/misc1.c +++ b/src/misc1.c @@ -32,7 +32,7 @@ static garray_T ga_users; int get_indent() { - return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts); + return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts, FALSE); } /* @@ -42,7 +42,7 @@ get_indent() get_indent_lnum(lnum) linenr_T lnum; { - return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts); + return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts, FALSE); } #if defined(FEAT_FOLDING) || defined(PROTO) @@ -55,7 +55,7 @@ get_indent_buf(buf, lnum) buf_T *buf; linenr_T lnum; { - return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts); + return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts, FALSE); } #endif @@ -64,16 +64,23 @@ get_indent_buf(buf, lnum) * 'tabstop' at "ts" */ int -get_indent_str(ptr, ts) +get_indent_str(ptr, ts, list) char_u *ptr; int ts; + int list; /* if TRUE, count only screen size for tabs */ { int count = 0; for ( ; *ptr; ++ptr) { - if (*ptr == TAB) /* count a tab for what it is worth */ - count += ts - (count % ts); + if (*ptr == TAB) + { + if (!list || lcs_tab1) /* count a tab for what it is worth */ + count += ts - (count % ts); + else + /* in list mode, when tab is not set, count screen char width for Tab: ^I */ + count += ptr2cells(ptr); + } else if (*ptr == ' ') ++count; /* count a space for one */ else @@ -476,6 +483,58 @@ get_number_indent(lnum) return (int)col; } +#if defined(FEAT_LINEBREAK) || defined(PROTO) +/* + * Return appropriate space number for breakindent, taking influencing + * parameters into account. Window must be specified, since it is not + * necessarily always the current one. + */ + int +get_breakindent_win(wp, line) + win_T *wp; + char_u *line; /* start of the line */ +{ + static int prev_indent = 0; /* cached indent value */ + static long prev_ts = 0L; /* cached tabstop value */ + static char_u *prev_line = NULL; /* cached pointer to line */ + int bri = 0; + /* window width minus window margin space, i.e. what rests for text */ + const int eff_wwidth = W_WIDTH(wp) + - ((wp->w_p_nu || wp->w_p_rnu) + && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL) + ? number_width(wp) + 1 : 0); + + /* used cached indent, unless pointer or 'tabstop' changed */ + if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts) + { + prev_line = line; + prev_ts = wp->w_buffer->b_p_ts; + prev_indent = get_indent_str(line, + (int)wp->w_buffer->b_p_ts, wp->w_p_list) + wp->w_p_brishift; + } + + /* indent minus the length of the showbreak string */ + bri = prev_indent; + if (wp->w_p_brisbr) + bri -= vim_strsize(p_sbr); + + /* Add offset for number column, if 'n' is in 'cpoptions' */ + bri += win_col_off2(wp); + + /* never indent past left window margin */ + if (bri < 0) + bri = 0; + /* always leave at least bri_min characters on the left, + * if text width is sufficient */ + else if (bri > eff_wwidth - wp->w_p_brimin) + bri = (eff_wwidth - wp->w_p_brimin < 0) + ? 0 : eff_wwidth - wp->w_p_brimin; + + return bri; +} +#endif + + #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) static int cin_is_cinword __ARGS((char_u *line)); @@ -678,7 +737,7 @@ open_line(dir, flags, second_line_indent /* * count white space on current line */ - newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts); + newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE); if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) newindent = second_line_indent; /* for ^^D command in insert mode */ @@ -1201,7 +1260,7 @@ open_line(dir, flags, second_line_indent || do_si #endif ) - newindent = get_indent_str(leader, (int)curbuf->b_p_ts); + newindent = get_indent_str(leader, (int)curbuf->b_p_ts, FALSE); /* Add the indent offset */ if (newindent + off < 0) @@ -1994,6 +2053,7 @@ plines_win_col(wp, lnum, column) char_u *s; int lines = 0; int width; + char_u *line; #ifdef FEAT_DIFF /* Check for filler lines above this buffer line. When folded the result @@ -2009,12 +2069,12 @@ plines_win_col(wp, lnum, column) return lines + 1; #endif - s = ml_get_buf(wp->w_buffer, lnum, FALSE); + line = s = ml_get_buf(wp->w_buffer, lnum, FALSE); col = 0; while (*s != NUL && --column >= 0) { - col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL); + col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL); mb_ptr_adv(s); } @@ -2026,7 +2086,7 @@ plines_win_col(wp, lnum, column) * 'ts') -- webb. */ if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1)) - col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL) - 1; + col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1; /* * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc. @@ -9002,10 +9062,12 @@ get_lisp_indent() amount = 2; else { + char_u *line = that; + amount = 0; while (*that && col) { - amount += lbr_chartabsize_adv(&that, (colnr_T)amount); + amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); col--; } @@ -9028,7 +9090,7 @@ get_lisp_indent() while (vim_iswhite(*that)) { - amount += lbr_chartabsize(that, (colnr_T)amount); + amount += lbr_chartabsize(line, that, (colnr_T)amount); ++that; } @@ -9066,15 +9128,16 @@ get_lisp_indent() && !quotecount) --parencount; if (*that == '\\' && *(that+1) != NUL) - amount += lbr_chartabsize_adv(&that, - (colnr_T)amount); - amount += lbr_chartabsize_adv(&that, - (colnr_T)amount); + amount += lbr_chartabsize_adv( + line, &that, (colnr_T)amount); + amount += lbr_chartabsize_adv( + line, &that, (colnr_T)amount); } } while (vim_iswhite(*that)) { - amount += lbr_chartabsize(that, (colnr_T)amount); + amount += lbr_chartabsize( + line, that, (colnr_T)amount); that++; } if (!*that || *that == ';') diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -201,10 +201,10 @@ coladvance2(pos, addspaces, finetune, wc { /* Count a tab for what it's worth (if list mode not on) */ #ifdef FEAT_LINEBREAK - csize = win_lbr_chartabsize(curwin, ptr, col, &head); + csize = win_lbr_chartabsize(curwin, line, ptr, col, &head); mb_ptr_adv(ptr); #else - csize = lbr_chartabsize_adv(&ptr, col); + csize = lbr_chartabsize_adv(line, &ptr, col); #endif col += csize; } @@ -2156,7 +2156,8 @@ ga_append(gap, c) } } -#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(WIN3264) +#if (defined(UNIX) && !defined(USE_SYSTEM)) || defined(WIN3264) \ + || defined(PROTO) /* * Append the text in "gap" below the cursor line and clear "gap". */ diff --git a/src/ops.c b/src/ops.c --- a/src/ops.c +++ b/src/ops.c @@ -420,7 +420,9 @@ shift_block(oap, amount) } for ( ; vim_iswhite(*bd.textstart); ) { - incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol)); + /* TODO: is passing bd.textstart for start of the line OK? */ + incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, + (colnr_T)(bd.start_vcol)); total += incr; bd.start_vcol += incr; } @@ -480,7 +482,7 @@ shift_block(oap, amount) while (vim_iswhite(*non_white)) { - incr = lbr_chartabsize_adv(&non_white, non_white_col); + incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col); non_white_col += incr; } @@ -505,7 +507,11 @@ shift_block(oap, amount) verbatim_copy_width -= bd.start_char_vcols; while (verbatim_copy_width < destination_col) { - incr = lbr_chartabsize(verbatim_copy_end, verbatim_copy_width); + char_u *line = verbatim_copy_end; + + /* TODO: is passing verbatim_copy_end for start of the line OK? */ + incr = lbr_chartabsize(line, verbatim_copy_end, + verbatim_copy_width); if (verbatim_copy_width + incr > destination_col) break; verbatim_copy_width += incr; @@ -3617,7 +3623,7 @@ do_put(regname, dir, count, flags) for (ptr = oldp; vcol < col && *ptr; ) { /* Count a tab for what it's worth (if list mode not on) */ - incr = lbr_chartabsize_adv(&ptr, (colnr_T)vcol); + incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol); vcol += incr; } bd.textcol = (colnr_T)(ptr - oldp); @@ -3651,7 +3657,7 @@ do_put(regname, dir, count, flags) /* calculate number of spaces required to fill right side of block*/ spaces = y_width + 1; for (j = 0; j < yanklen; j++) - spaces -= lbr_chartabsize(&y_array[i][j], 0); + spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0); if (spaces < 0) spaces = 0; @@ -5203,7 +5209,7 @@ block_prep(oap, bdp, lnum, is_del) while (bdp->start_vcol < oap->start_vcol && *pstart) { /* Count a tab for what it's worth (if list mode not on) */ - incr = lbr_chartabsize(pstart, (colnr_T)bdp->start_vcol); + incr = lbr_chartabsize(line, pstart, (colnr_T)bdp->start_vcol); bdp->start_vcol += incr; #ifdef FEAT_VISUALEXTRA if (vim_iswhite(*pstart)) @@ -5272,7 +5278,10 @@ block_prep(oap, bdp, lnum, is_del) { /* Count a tab for what it's worth (if list mode not on) */ prev_pend = pend; - incr = lbr_chartabsize_adv(&pend, (colnr_T)bdp->end_vcol); + /* TODO: is passing prev_pend for start of the line OK? + * perhaps it should be "line". */ + incr = lbr_chartabsize_adv(prev_pend, &pend, + (colnr_T)bdp->end_vcol); bdp->end_vcol += incr; } if (bdp->end_vcol <= oap->end_vcol @@ -6882,7 +6891,8 @@ cursor_pos_info() validate_virtcol(); col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); - col_print(buf2, sizeof(buf2), (int)STRLEN(p), linetabsize(p)); + col_print(buf2, sizeof(buf2), (int)STRLEN(p), + linetabsize(p)); if (char_count_cursor == byte_count_cursor && char_count == byte_count) diff --git a/src/option.c b/src/option.c --- a/src/option.c +++ b/src/option.c @@ -188,6 +188,10 @@ #ifdef FEAT_ARABIC # define PV_ARAB OPT_WIN(WV_ARAB) #endif +#ifdef FEAT_LINEBREAK +# define PV_BRI OPT_WIN(WV_BRI) +# define PV_BRIOPT OPT_WIN(WV_BRIOPT) +#endif #ifdef FEAT_DIFF # define PV_DIFF OPT_WIN(WV_DIFF) #endif @@ -648,6 +652,24 @@ static struct vimoption {(char_u *)0L, (char_u *)0L} #endif SCRIPTID_INIT}, + {"breakindent", "bri", P_BOOL|P_VI_DEF|P_VIM|P_RWIN, +#ifdef FEAT_LINEBREAK + (char_u *)VAR_WIN, PV_BRI, + {(char_u *)FALSE, (char_u *)0L} +#else + (char_u *)NULL, PV_NONE, + {(char_u *)0L, (char_u *)0L} +#endif + SCRIPTID_INIT}, + {"breakindentopt", "briopt", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_COMMA|P_NODUP, +#ifdef FEAT_LINEBREAK + (char_u *)VAR_WIN, PV_BRIOPT, + {(char_u *)"", (char_u *)NULL} +#else + (char_u *)NULL, PV_NONE, + {(char_u *)"", (char_u *)NULL} +#endif + SCRIPTID_INIT}, {"browsedir", "bsdir",P_STRING|P_VI_DEF, #ifdef FEAT_BROWSE (char_u *)&p_bsdir, PV_NONE, @@ -5256,6 +5278,9 @@ didset_options() /* set cedit_key */ (void)check_cedit(); #endif +#ifdef FEAT_LINEBREAK + briopt_check(); +#endif } /* @@ -5709,6 +5734,14 @@ did_set_string_option(opt_idx, varp, new *p_pm == '.' ? p_pm + 1 : p_pm) == 0) errmsg = (char_u *)N_("E589: 'backupext' and 'patchmode' are equal"); } +#ifdef FEAT_LINEBREAK + /* 'breakindentopt' */ + else if (varp == &curwin->w_p_briopt) + { + if (briopt_check() == FAIL) + errmsg = e_invarg; + } +#endif /* * 'isident', 'iskeyword', 'isprint or 'isfname' option: refill chartab[] @@ -10018,6 +10051,8 @@ get_varp(p) case PV_WRAP: return (char_u *)&(curwin->w_p_wrap); #ifdef FEAT_LINEBREAK case PV_LBR: return (char_u *)&(curwin->w_p_lbr); + case PV_BRI: return (char_u *)&(curwin->w_p_bri); + case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt); #endif #ifdef FEAT_SCROLLBIND case PV_SCBIND: return (char_u *)&(curwin->w_p_scb); @@ -10207,6 +10242,8 @@ copy_winopt(from, to) #endif #ifdef FEAT_LINEBREAK to->wo_lbr = from->wo_lbr; + to->wo_bri = from->wo_bri; + to->wo_briopt = vim_strsave(from->wo_briopt); #endif #ifdef FEAT_SCROLLBIND to->wo_scb = from->wo_scb; @@ -10294,6 +10331,9 @@ check_winopt(wop) #ifdef FEAT_CONCEAL check_string_option(&wop->wo_cocu); #endif +#ifdef FEAT_LINEBREAK + check_string_option(&wop->wo_briopt); +#endif } /* @@ -10313,6 +10353,9 @@ clear_winopt(wop) # endif clear_string_option(&wop->wo_fmr); #endif +#ifdef FEAT_LINEBREAK + clear_string_option(&wop->wo_briopt); +#endif #ifdef FEAT_RIGHTLEFT clear_string_option(&wop->wo_rlc); #endif @@ -11927,3 +11970,49 @@ find_mps_values(initc, findc, backwards, ++ptr; } } + +#if defined(FEAT_LINEBREAK) || defined(PROTO) +/* + * This is called when 'breakindentopt' is changed and when a window is + * initialized. + */ + int +briopt_check() +{ + char_u *p; + int bri_shift = 0; + long bri_min = 20; + int bri_sbr = FALSE; + + p = curwin->w_p_briopt; + while (*p != NUL) + { + if (STRNCMP(p, "shift:", 6) == 0 + && ((p[6] == '-' && VIM_ISDIGIT(p[7])) || VIM_ISDIGIT(p[6]))) + { + p += 6; + bri_shift = getdigits(&p); + } + else if (STRNCMP(p, "min:", 4) == 0 && VIM_ISDIGIT(p[4])) + { + p += 4; + bri_min = getdigits(&p); + } + else if (STRNCMP(p, "sbr", 3) == 0) + { + p += 3; + bri_sbr = TRUE; + } + if (*p != ',' && *p != NUL) + return FAIL; + if (*p == ',') + ++p; + } + + curwin->w_p_brishift = bri_shift; + curwin->w_p_brimin = bri_min; + curwin->w_p_brisbr = bri_sbr; + + return OK; +} +#endif diff --git a/src/option.h b/src/option.h --- a/src/option.h +++ b/src/option.h @@ -1052,6 +1052,10 @@ enum #ifdef FEAT_CURSORBIND , WV_CRBIND #endif +#ifdef FEAT_LINEBREAK + , WV_BRI + , WV_BRIOPT +#endif #ifdef FEAT_DIFF , WV_DIFF #endif diff --git a/src/proto/charset.pro b/src/proto/charset.pro --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -16,7 +16,7 @@ int vim_strnsize __ARGS((char_u *s, int int chartabsize __ARGS((char_u *p, colnr_T col)); int linetabsize __ARGS((char_u *s)); int linetabsize_col __ARGS((int startcol, char_u *s)); -int win_linetabsize __ARGS((win_T *wp, char_u *p, colnr_T len)); +int win_linetabsize __ARGS((win_T *wp, char_u *line, colnr_T len)); int vim_isIDc __ARGS((int c)); int vim_iswordc __ARGS((int c)); int vim_iswordc_buf __ARGS((int c, buf_T *buf)); @@ -26,9 +26,9 @@ int vim_isfilec __ARGS((int c)); int vim_isfilec_or_wc __ARGS((int c)); int vim_isprintc __ARGS((int c)); int vim_isprintc_strict __ARGS((int c)); -int lbr_chartabsize __ARGS((unsigned char *s, colnr_T col)); -int lbr_chartabsize_adv __ARGS((char_u **s, colnr_T col)); -int win_lbr_chartabsize __ARGS((win_T *wp, char_u *s, colnr_T col, int *headp)); +int lbr_chartabsize __ARGS((char_u *line, unsigned char *s, colnr_T col)); +int lbr_chartabsize_adv __ARGS((char_u *line, char_u **s, colnr_T col)); +int win_lbr_chartabsize __ARGS((win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp)); int in_win_border __ARGS((win_T *wp, colnr_T vcol)); void getvcol __ARGS((win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end)); colnr_T getvcol_nolist __ARGS((pos_T *posp)); diff --git a/src/proto/misc1.pro b/src/proto/misc1.pro --- a/src/proto/misc1.pro +++ b/src/proto/misc1.pro @@ -2,9 +2,10 @@ int get_indent __ARGS((void)); int get_indent_lnum __ARGS((linenr_T lnum)); int get_indent_buf __ARGS((buf_T *buf, linenr_T lnum)); -int get_indent_str __ARGS((char_u *ptr, int ts)); +int get_indent_str __ARGS((char_u *ptr, int ts, int list)); int set_indent __ARGS((int size, int flags)); int get_number_indent __ARGS((linenr_T lnum)); +int get_breakindent_win __ARGS((win_T *wp, char_u *ptr)); int open_line __ARGS((int dir, int flags, int second_line_indent)); int get_leader_len __ARGS((char_u *line, char_u **flags, int backward, int include_space)); int get_last_leader_offset __ARGS((char_u *line, char_u **flags)); diff --git a/src/proto/option.pro b/src/proto/option.pro --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -63,4 +63,5 @@ int check_ff_value __ARGS((char_u *p)); long get_sw_value __ARGS((buf_T *buf)); long get_sts_value __ARGS((void)); void find_mps_values __ARGS((int *initc, int *findc, int *backwards, int switchit)); +int briopt_check __ARGS((void)); /* vim: set ft=c : */ diff --git a/src/screen.c b/src/screen.c --- a/src/screen.c +++ b/src/screen.c @@ -2962,10 +2962,15 @@ win_line(wp, lnum, startrow, endrow, noc # define WL_SIGN WL_FOLD /* column for signs */ #endif #define WL_NR WL_SIGN + 1 /* line number */ +#ifdef FEAT_LINEBREAK +# define WL_BRI WL_NR + 1 /* 'breakindent' */ +#else +# define WL_BRI WL_NR +#endif #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) -# define WL_SBR WL_NR + 1 /* 'showbreak' or 'diff' */ +# define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */ #else -# define WL_SBR WL_NR +# define WL_SBR WL_BRI #endif #define WL_LINE WL_SBR + 1 /* text in the line */ int draw_state = WL_START; /* what to draw next */ @@ -3301,7 +3306,7 @@ win_line(wp, lnum, startrow, endrow, noc #endif while (vcol < v && *ptr != NUL) { - c = win_lbr_chartabsize(wp, ptr, (colnr_T)vcol, NULL); + c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL); vcol += c; #ifdef FEAT_MBYTE prev_ptr = ptr; @@ -3670,6 +3675,44 @@ win_line(wp, lnum, startrow, endrow, noc } } +#ifdef FEAT_LINEBREAK + if (wp->w_p_brisbr && draw_state == WL_BRI - 1 + && n_extra == 0 && *p_sbr != NUL) + /* draw indent after showbreak value */ + draw_state = WL_BRI; + else if (wp->w_p_brisbr && draw_state == WL_SBR && n_extra == 0) + /* After the showbreak, draw the breakindent */ + draw_state = WL_BRI - 1; + + /* draw 'breakindent': indent wrapped text accordingly */ + if (draw_state == WL_BRI - 1 && n_extra == 0) + { + draw_state = WL_BRI; +# ifdef FEAT_DIFF +# endif + if (wp->w_p_bri && n_extra == 0 && row != startrow +#ifdef FEAT_DIFF + && filler_lines == 0 +#endif + ) + { + char_attr = 0; /* was: hl_attr(HLF_AT); */ +#ifdef FEAT_DIFF + if (diff_hlf != (hlf_T)0) + char_attr = hl_attr(diff_hlf); +#endif + p_extra = NUL; + c_extra = ' '; + n_extra = get_breakindent_win(wp, + ml_get_buf(wp->w_buffer, lnum, FALSE)); + /* Correct end of highlighted area for 'breakindent', + * required when 'linebreak' is also set. */ + if (tocol == vcol) + tocol += n_extra; + } + } +#endif + #if defined(FEAT_LINEBREAK) || defined(FEAT_DIFF) if (draw_state == WL_SBR - 1 && n_extra == 0) { @@ -4382,11 +4425,14 @@ win_line(wp, lnum, startrow, endrow, noc if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr) && !wp->w_p_list) { - n_extra = win_lbr_chartabsize(wp, ptr - ( + char_u *p = ptr - ( # ifdef FEAT_MBYTE has_mbyte ? mb_l : # endif - 1), (colnr_T)vcol, NULL) - 1; + 1); + /* TODO: is passing p for start of the line OK? */ + n_extra = win_lbr_chartabsize(wp, p, p, (colnr_T)vcol, + NULL) - 1; c_extra = ' '; if (vim_iswhite(c)) { @@ -8916,8 +8962,8 @@ windgoto(row, col) { if (noinvcurs) screen_stop_highlight(); - if (row == screen_cur_row && (col > screen_cur_col) && - *T_CRI != NUL) + if (row == screen_cur_row && (col > screen_cur_col) + && *T_CRI != NUL) term_cursor_right(col - screen_cur_col); else term_windgoto(row, col); diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -134,6 +134,12 @@ typedef struct int wo_arab; # define w_p_arab w_onebuf_opt.wo_arab /* 'arabic' */ #endif +#ifdef FEAT_LINEBREAK + int wo_bri; +# define w_p_bri w_onebuf_opt.wo_bri /* 'breakindent' */ + char_u *wo_briopt; +# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */ +#endif #ifdef FEAT_DIFF int wo_diff; # define w_p_diff w_onebuf_opt.wo_diff /* 'diff' */ @@ -2189,6 +2195,11 @@ struct window_S #ifdef FEAT_SYN_HL int *w_p_cc_cols; /* array of columns to highlight or NULL */ #endif +#ifdef FEAT_LINEBREAK + int w_p_brimin; /* minimum width for breakindent */ + int w_p_brishift; /* additional shift for breakindent */ + int w_p_brisbr; /* sbr in 'briopt' */ +#endif /* transform a pointer to a "onebuf" option into a "allbuf" option */ #define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T)) diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak --- a/src/testdir/Make_amiga.mak +++ b/src/testdir/Make_amiga.mak @@ -37,6 +37,7 @@ SCRIPTS = test1.out test3.out test4.out test99.out test100.out test101.out test102.out test103.out \ test104.out test105.out test106.out test107.out \ test_autoformat_join.out \ + test_breakindent.out \ test_eval.out \ test_options.out @@ -163,5 +164,6 @@ test105.out: test105.in test106.out: test106.in test107.out: test107.in test_autoformat_join.out: test_autoformat_join.in +test_breakindent.out: test_breakindent.in test_eval.out: test_eval.in test_options.out: test_options.in diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak --- a/src/testdir/Make_dos.mak +++ b/src/testdir/Make_dos.mak @@ -36,6 +36,7 @@ SCRIPTS = test3.out test4.out test5.out test100.out test101.out test102.out test103.out test104.out \ test105.out test106.out test107.out\ test_autoformat_join.out \ + test_breakindent.out \ test_eval.out \ test_options.out diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak --- a/src/testdir/Make_ming.mak +++ b/src/testdir/Make_ming.mak @@ -56,6 +56,7 @@ SCRIPTS = test3.out test4.out test5.out test100.out test101.out test102.out test103.out test104.out \ test105.out test106.out test107.out \ test_autoformat_join.out \ + test_breakindent.out \ test_eval.out \ test_options.out diff --git a/src/testdir/Make_os2.mak b/src/testdir/Make_os2.mak --- a/src/testdir/Make_os2.mak +++ b/src/testdir/Make_os2.mak @@ -39,6 +39,7 @@ SCRIPTS = test1.out test3.out test4.out test105.out test106.out test107.out \ test_autoformat_join.out \ test_eval.out \ + test_breakindent.out \ test_options.out .SUFFIXES: .in .out diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms --- a/src/testdir/Make_vms.mms +++ b/src/testdir/Make_vms.mms @@ -97,6 +97,7 @@ SCRIPT = test1.out test2.out test3.out test100.out test101.out test103.out test104.out \ test105.out test106.out test107.out \ test_autoformat_join.out \ + test_breakindent.out \ test_eval.out \ test_options.out diff --git a/src/testdir/Makefile b/src/testdir/Makefile --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -34,6 +34,7 @@ SCRIPTS = test1.out test2.out test3.out test99.out test100.out test101.out test102.out test103.out \ test104.out test105.out test106.out test107.out \ test_autoformat_join.out \ + test_breakindent.out \ test_eval.out \ test_options.out diff --git a/src/testdir/test_breakindent.in b/src/testdir/test_breakindent.in new file mode 100644 --- /dev/null +++ b/src/testdir/test_breakindent.in @@ -0,0 +1,79 @@ +Test for breakindent + +STARTTEST +:so small.vim +:if !exists("+breakindent") | e! test.ok | w! test.out | qa! | endif +:10new|:vsp|:vert resize 20 +:put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\" +:set ts=4 sw=4 sts=4 breakindent +:fu! ScreenChar(width) +: let c='' +: for i in range(1,a:width) +: let c.=nr2char(screenchar(line('.'), i)) +: endfor +: let c.="\n" +: for i in range(1,a:width) +: let c.=nr2char(screenchar(line('.')+1, i)) +: endfor +: let c.="\n" +: for i in range(1,a:width) +: let c.=nr2char(screenchar(line('.')+2, i)) +: endfor +: return c +:endfu +:fu DoRecordScreen() +: wincmd l +: $put =printf(\"\n%s\", g:test) +: $put =g:line1 +: wincmd p +:endfu +:let g:test="Test 1: Simple breakindent" +:let line1=ScreenChar(8) +:call DoRecordScreen() +:let g:test="Test 2: Simple breakindent + sbr=>>" +:set sbr=>> +:let line1=ScreenChar(8) +:call DoRecordScreen() +:let g:test ="Test 3: Simple breakindent + briopt:sbr" +:set briopt=sbr,min:0 sbr=++ +:let line1=ScreenChar(8) +:call DoRecordScreen() +:let g:test ="Test 4: Simple breakindent + min width: 18" +:set sbr= briopt=min:18 +:let line1=ScreenChar(8) +:call DoRecordScreen() +:let g:test =" Test 5: Simple breakindent + shift by 2" +:set briopt=shift:2,min:0 +:let line1=ScreenChar(8) +:call DoRecordScreen() +:let g:test=" Test 6: Simple breakindent + shift by -1" +:set briopt=shift:-1,min:0 +:let line1=ScreenChar(8) +:call DoRecordScreen() +:let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr" +:set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4 +:let line1=ScreenChar(10) +:call DoRecordScreen() +:let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr" +:set briopt=shift:1,sbr,min:0 nu sbr=# list +:let line1=ScreenChar(10) +:call DoRecordScreen() +:let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list" +:set briopt-=sbr +:let line1=ScreenChar(10) +:call DoRecordScreen() +:let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n" +:set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0 +:let line1=ScreenChar(10) +:call DoRecordScreen() +:wincmd p +:let g:test="\n Test 11: strdisplaywidth when breakindent is on" +:set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4 +:let text=getline(2) "skip leading tab when calculating text width +:let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3 " text wraps 3 times +:$put =g:test +:$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width) +:%w! test.out +:qa! +ENDTEST +dummy text diff --git a/src/testdir/test_breakindent.ok b/src/testdir/test_breakindent.ok new file mode 100644 --- /dev/null +++ b/src/testdir/test_breakindent.ok @@ -0,0 +1,55 @@ + + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP + +Test 1: Simple breakindent + abcd + qrst + GHIJ + +Test 2: Simple breakindent + sbr=>> + abcd + >>qr + >>EF + +Test 3: Simple breakindent + briopt:sbr + abcd +++ qrst +++ GHIJ + +Test 4: Simple breakindent + min width: 18 + abcd + qrstuv + IJKLMN + + Test 5: Simple breakindent + shift by 2 + abcd + qr + EF + + Test 6: Simple breakindent + shift by -1 + abcd + qrstu + HIJKL + + Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr + 2 ab +? m +? x + + Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr + 2 ^Iabcd +# opq +# BCD + + Test 9: breakindent + shift by +1 + 'nu' + sbr=# list + 2 ^Iabcd + #op + #AB + + Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n + 2 ab +~ mn +~ yz + + Test 11: strdisplaywidth when breakindent is on +strdisplaywidth: 46 == calculated: 64 diff --git a/src/ui.c b/src/ui.c --- a/src/ui.c +++ b/src/ui.c @@ -3162,15 +3162,15 @@ vcol2col(wp, lnum, vcol) /* try to advance to the specified column */ int count = 0; char_u *ptr; - char_u *start; + char_u *line; - start = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE); + line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE); while (count < vcol && *ptr != NUL) { - count += win_lbr_chartabsize(wp, ptr, count, NULL); + count += win_lbr_chartabsize(wp, line, ptr, count, NULL); mb_ptr_adv(ptr); } - return (int)(ptr - start); + return (int)(ptr - line); } #endif diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -735,6 +735,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 338, +/**/ 337, /**/ 336,