Commits

Ken Takata committed 644d076

import the latest breakindent patch by Christian Brabandt

https://groups.google.com/d/msg/vim_dev/ZGIQQPtVhkI/tM1WKRa1LkIJ

Comments (0)

Files changed (3)

breakindent_patch.diff

-# HG changeset patch
-# Parent a1b7e6004549af1fd1aab85133d7ac82bda08751
-* * *
-Add a new 'breakindentopt' setting, that will include all
-previous 'breakindent' settings and addtionally make it possible
-to configure, how the 'sbr' setting will be drawn.
-
-diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
---- a/runtime/doc/eval.txt
-+++ b/runtime/doc/eval.txt
-@@ -1979,7 +1979,8 @@ sqrt( {expr})			Float	square root of {ex
- str2float( {expr})		Float	convert String to Float
- str2nr( {expr} [, {base}])	Number	convert String to Number
- strchars( {expr})		Number	character length of the String {expr}
--strdisplaywidth( {expr} [, {col}]) Number display length of the String {expr}
-+strdisplaywidth( {expr} [, {col} [, {lnum}]])
-+				Number	display length of the String {expr}
- strftime( {format}[, {time}])	String	time in specified format
- stridx( {haystack}, {needle}[, {start}])
- 				Number	index of {needle} in {haystack}
-@@ -5698,13 +5699,15 @@ strchars({expr})					*strchars()*
- 		separately.
- 		Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
- 
--strdisplaywidth({expr}[, {col}])			*strdisplaywidth()*
-+strdisplaywidth({expr}[, {col}[, {lnum}]])		*strdisplaywidth()*
- 		The result is a Number, which is the number of display cells
- 		String {expr} occupies on the screen when it starts a {col}.
- 		When {col} is omitted zero is used.  Otherwise it is the
--		screen column where to start.  This matters for Tab
--		characters.
--		The option settings of the current window are used.  This
-+		screen column where to start. This matters for Tab chars
-+
-+		When {lnum} is omitted the cursor line is used. Otherwise
-+		it is the line where to start. This matters for the indent.
-+		The option settings of the current window are used. This
- 		matters for anything that's displayed differently, such as
- 		'tabstop' and 'display'.
- 		When {expr} contains characters with East Asian Width Class
-@@ -6553,8 +6556,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/doc/options.txt b/runtime/doc/options.txt
---- a/runtime/doc/options.txt
-+++ b/runtime/doc/options.txt
-@@ -1200,6 +1200,38 @@ A jump table for the options with a shor
- 	break if 'linebreak' is on.  Only works for ASCII and also for 8-bit
- 	characters when 'encoding' is an 8-bit encoding.
- 
-+						*'breakindent'* *'bri'*
-+'breakindent' 'bri'	boolean (default off)
-+			local to window
-+			{not in Vi}
-+			{not available when compiled without the |+linebreak|
-+			feature}
-+	Every wrapped line will continue visually indented (same amount of
-+	space as the beginning of that line), thus preserving horizontal blocks
-+	of text.
-+
-+						*'breakindentmin'* *'brimin'*
-+'breakindentopt' 'briopt' string (default "min:20,shift:0")
-+			local to window
-+			{not in Vi}
-+			{not available when compiled without the |+linebreak|
-+			feature}
-+	Settings for 'breakindent'. It can consist of the following optional
-+	items and must be seperated by a comma:
-+		min:{n}	    Minimum text width that will be kept after
-+			    applying 'breakindent', even if the resulting
-+			    text should normally be narrower. This prevents
-+			    text indented almost to the right window border
-+			    occupying lot of vertical space when broken.
-+		shift:{n}   After applying 'breakindent', wrapped line
-+			    beginning will be shift by given number of
-+			    characters. It permits dynamic French paragraph
-+			    indentation (negative) or emphasizing the line
-+			    continuation (positive).
-+		sbr	    Display the 'showbreak' value before applying the 
-+			    additional indent.
-+	If empty, the default for min is 20 and shift is 0
-+
- 						*'browsedir'* *'bsdir'*
- 'browsedir' 'bsdir'	string	(default: "last")
- 			global
-@@ -4574,12 +4606,13 @@ A jump table for the options with a shor
- 			{not in Vi}
- 			{not available when compiled without the |+linebreak|
- 			feature}
--	If on Vim will wrap long lines at a character in 'breakat' rather
-+	If on, Vim will wrap long lines at a character in 'breakat' rather
- 	than at the last character that fits on the screen.  Unlike
- 	'wrapmargin' and 'textwidth', this does not insert <EOL>s in the file,
--	it only affects the way the file is displayed, not its contents.  The
--	value of 'showbreak' is used to put in front of wrapped lines.
--	This option is not used when the 'wrap' option is off or 'list' is on.
-+	it only affects the way the file is displayed, not its contents.
-+	If 'breakindent' is set, line is visually indented. Then, the value
-+	of 'showbreak' is used to put in front of wrapped lines. This option
-+	is not used when the 'wrap' option is off or 'list' is on.
- 	Note that <Tab> characters after an <EOL> are mostly not displayed
- 	with the right amount of white space.
- 
-diff --git a/runtime/optwin.vim b/runtime/optwin.vim
---- a/runtime/optwin.vim
-+++ b/runtime/optwin.vim
-@@ -324,6 +324,12 @@ call <SID>BinOptionG("wrap", &wrap)
- call append("$", "linebreak\twrap long lines at a character in 'breakat'")
- call append("$", "\t(local to window)")
- call <SID>BinOptionL("lbr")
-+call append("$", "breakindent\tpreserve indentation in wrapped text")
-+call append("$", "\t(local to window)")
-+call <SID>BinOptionL("bri")
-+call append("$", "breakindentopt\tadjust breakindent behaviour")
-+call append("$", "\t(local to window)")
-+call <SID>OptionL("briopt")
- call append("$", "breakat\twhich characters might cause a line break")
- call <SID>OptionG("brk", &brk)
- call append("$", "showbreak\tstring to put before wrapped screen lines")
-diff --git a/src/buffer.c b/src/buffer.c
---- a/src/buffer.c
-+++ b/src/buffer.c
-@@ -2713,6 +2713,9 @@ get_winopts(buf)
- #ifdef FEAT_SYN_HL
-     check_colorcolumn(curwin);
- #endif
-+#ifdef FEAT_LINEBREAK
-+    briopt_changed();
-+#endif
- }
- 
- /*
-diff --git a/src/charset.c b/src/charset.c
---- a/src/charset.c
-+++ b/src/charset.c
-@@ -862,24 +862,26 @@ win_chartabsize(wp, p, col)
-  * taking into account the size of a tab.
-  */
-     int
--linetabsize(s)
-+linetabsize(s, lnum)
-     char_u	*s;
-+    linenr_T	lnum;
- {
--    return linetabsize_col(0, s);
-+    return linetabsize_col(0, s, lnum);
- }
- 
- /*
-  * Like linetabsize(), but starting at column "startcol".
-  */
-     int
--linetabsize_col(startcol, s)
-+linetabsize_col(startcol, s, lnum)
-     int		startcol;
-     char_u	*s;
-+    linenr_T	lnum;
- {
-     colnr_T	col = startcol;
- 
-     while (*s != NUL)
--	col += lbr_chartabsize_adv(&s, col);
-+	col += lbr_chartabsize_adv(&s, col, lnum);
-     return (int)col;
- }
- 
-@@ -887,16 +889,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, p, len, lnum)
-     win_T	*wp;
-     char_u	*p;
-     colnr_T	len;
-+    linenr_T	lnum;
- {
-     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);
-+	col += win_lbr_chartabsize(wp, s, col, NULL, lnum);
-     return (int)col;
- }
- 
-@@ -1031,12 +1034,13 @@ vim_isprintc_strict(c)
-  * like chartabsize(), but also check for line breaks on the screen
-  */
-     int
--lbr_chartabsize(s, col)
-+lbr_chartabsize(s, col, lnum)
-     unsigned char	*s;
-     colnr_T		col;
-+    linenr_T		lnum;
- {
- #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
-@@ -1046,7 +1050,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, s, col, NULL, lnum);
- #endif
- }
- 
-@@ -1054,13 +1058,14 @@ lbr_chartabsize(s, col)
-  * Call lbr_chartabsize() and advance the pointer.
-  */
-     int
--lbr_chartabsize_adv(s, col)
-+lbr_chartabsize_adv(s, col, lnum)
-     char_u	**s;
-     colnr_T	col;
-+    linenr_T	lnum;
- {
-     int		retval;
- 
--    retval = lbr_chartabsize(*s, col);
-+    retval = lbr_chartabsize(*s, col, lnum);
-     mb_ptr_adv(*s);
-     return retval;
- }
-@@ -1071,13 +1076,17 @@ lbr_chartabsize_adv(s, col)
-  * If "headp" not NULL, set *headp to the size of what we for 'showbreak'
-  * string at start of line.  Warning: *headp is only set if it's a non-zero
-  * value, init to 0 before calling.
-+ *
-+ * linenr argument needed if in visual highlighting and breakindent=on, then
-+ * the line calculated is not current; if 0, normal functionality is preserved.
-  */
-     int
--win_lbr_chartabsize(wp, s, col, headp)
-+win_lbr_chartabsize(wp, s, col, headp, lnum)
-     win_T	*wp;
-     char_u	*s;
-     colnr_T	col;
-     int		*headp UNUSED;
-+    linenr_T	lnum;
- {
- #ifdef FEAT_LINEBREAK
-     int		c;
-@@ -1099,9 +1108,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
-@@ -1176,11 +1185,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;
-@@ -1193,7 +1203,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, lnum);
-+
- 	    if (tab_corr)
- 	    {
- # ifdef FEAT_VARTABS
-@@ -1317,12 +1332,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
-        )
-     {
-@@ -1388,7 +1404,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, ptr, vcol, &head, pos->lnum);
- 	    /* 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
-@@ -430,7 +430,7 @@ edit(cmdchar, startln, count)
- 	if (startln)
- 	    Insstart.col = 0;
-     }
--    Insstart_textlen = (colnr_T)linetabsize(ml_get_curline());
-+    Insstart_textlen = (colnr_T)linetabsize(ml_get_curline(), Insstart.lnum);
-     Insstart_blank_vcol = MAXCOL;
-     if (!did_ai)
- 	ai_col = 0;
-@@ -1962,7 +1962,8 @@ 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 + new_cursor_col, (colnr_T)vcol,
-+							curwin->w_cursor.lnum);
- 	}
- 	vcol = last_vcol;
- 
-@@ -6772,7 +6773,8 @@ stop_arrow()
- 	    ins_need_undo = FALSE;
- 	}
- 	Insstart = curwin->w_cursor;	/* new insertion starts here */
--	Insstart_textlen = (colnr_T)linetabsize(ml_get_curline());
-+	Insstart_textlen = (colnr_T)linetabsize(ml_get_curline(),
-+							curwin->w_cursor.lnum);
- 	ai_col = 0;
- #ifdef FEAT_VREPLACE
- 	if (State & VREPLACE_FLAG)
-@@ -7127,9 +7129,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
-@@ -9807,11 +9810,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((char_u *)"\t", vcol, cursor->lnum);
- 	    if (vcol + i > want_vcol)
- 		break;
- 	    if (*ptr != TAB)
-@@ -9837,7 +9840,7 @@ ins_tab()
- 	    /* Skip over the spaces we need. */
- 	    while (vcol < want_vcol && *ptr == ' ')
- 	    {
--		vcol += lbr_chartabsize(ptr, vcol);
-+		vcol += lbr_chartabsize(ptr, vcol, cursor->lnum);
- 		++ptr;
- 		++repl_off;
- 	    }
-@@ -10093,7 +10096,7 @@ ins_copychar(lnum)
-     while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
-     {
- 	prev_ptr = ptr;
--	temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp);
-+	temp += lbr_chartabsize_adv(&ptr, (colnr_T)temp, lnum);
-     }
-     if ((colnr_T)temp > curwin->w_virtcol)
- 	ptr = prev_ptr;
-diff --git a/src/eval.c b/src/eval.c
---- a/src/eval.c
-+++ b/src/eval.c
-@@ -8125,7 +8125,7 @@ static struct fst
- #endif
-     {"str2nr",		1, 2, f_str2nr},
-     {"strchars",	1, 1, f_strchars},
--    {"strdisplaywidth",	1, 2, f_strdisplaywidth},
-+    {"strdisplaywidth",	1, 3, f_strdisplaywidth},
- #ifdef HAVE_STRFTIME
-     {"strftime",	1, 2, f_strftime},
- #endif
-@@ -17845,11 +17845,17 @@ f_strdisplaywidth(argvars, rettv)
- {
-     char_u	*s = get_tv_string(&argvars[0]);
-     int		col = 0;
-+    linenr_T	lnum = 0;
- 
-     if (argvars[1].v_type != VAR_UNKNOWN)
-+    {
- 	col = get_tv_number(&argvars[1]);
- 
--    rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
-+	if (argvars[2].v_type != VAR_UNKNOWN)
-+	    lnum = get_tv_lnum(&argvars[2]);
-+    }
-+
-+    rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s, lnum) - col);
- }
- 
- /*
-diff --git a/src/ex_cmds.c b/src/ex_cmds.c
---- a/src/ex_cmds.c
-+++ b/src/ex_cmds.c
-@@ -261,7 +261,7 @@ linelen(has_tab)
- 	;
-     save = *last;
-     *last = NUL;
--    len = linetabsize(line);		/* get line length */
-+    len = linetabsize(line, curwin->w_cursor.lnum); /* get line length */
-     if (has_tab != NULL)		/* check for embedded TAB */
- 	*has_tab = (vim_strrchr(first, TAB) != NULL);
-     *last = save;
-diff --git a/src/getchar.c b/src/getchar.c
---- a/src/getchar.c
-+++ b/src/getchar.c
-@@ -2676,7 +2676,8 @@ vgetorpeek(advance)
- 				    if (!vim_iswhite(ptr[col]))
- 					curwin->w_wcol = vcol;
- 				    vcol += lbr_chartabsize(ptr + col,
--							       (colnr_T)vcol);
-+							       (colnr_T)vcol,
-+							       curwin->w_cursor.lnum);
- #ifdef FEAT_MBYTE
- 				    if (has_mbyte)
- 					col += (*mb_ptr2len)(ptr + col);
-diff --git a/src/gui_beval.c b/src/gui_beval.c
---- a/src/gui_beval.c
-+++ b/src/gui_beval.c
-@@ -342,7 +342,7 @@ get_beval_info(beval, getword, winp, lnu
- 	{
- 	    /* Not past end of the file. */
- 	    lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
--	    if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
-+	    if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL, lnum))
- 	    {
- 		/* Not past end of line. */
- 		if (getword)
-diff --git a/src/misc1.c b/src/misc1.c
---- a/src/misc1.c
-+++ b/src/misc1.c
-@@ -615,6 +615,48 @@ get_number_indent(lnum)
-     return (int)col;
- }
- 
-+#ifdef FEAT_LINEBREAK
-+/*
-+ * Return appropriate space number for breakindent, taking influencing
-+ * parameters into account. Window must be specified, since it is not
-+ * necessarily always the current one. If lnum==0, current line is calculated,
-+ * specified line otherwise.
-+ */
-+    int
-+get_breakindent_win(wp, lnum)
-+    win_T*	wp;
-+    linenr_T	lnum;
-+{
-+    int bri;
-+    /* window width minus barren 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) : 0);
-+
-+    bri = get_indent_buf(wp->w_buffer, lnum ? lnum : wp->w_cursor.lnum) +
-+	wp->w_p_brishift;
-+
-+    /* minus the length of the showbreak string */
-+    if (wp->w_p_brisbr)
-+	bri -= (*p_sbr == NUL ? 0 : 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));
-@@ -2107,7 +2149,7 @@ plines_win_nofold(wp, lnum)
-     s = ml_get_buf(wp->w_buffer, lnum, FALSE);
-     if (*s == NUL)		/* empty line */
- 	return 1;
--    col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
-+    col = win_linetabsize(wp, s, (colnr_T)MAXCOL, lnum);
- 
-     /*
-      * If list mode is on, then the '$' at the end of the line may take up one
-@@ -2163,7 +2205,7 @@ plines_win_col(wp, lnum, column)
-     col = 0;
-     while (*s != NUL && --column >= 0)
-     {
--	col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL);
-+	col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL, lnum);
- 	mb_ptr_adv(s);
-     }
- 
-@@ -2175,7 +2217,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, s, (colnr_T)col, NULL, lnum) - 1;
- 
-     /*
-      * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
-@@ -9154,7 +9196,8 @@ get_lisp_indent()
- 		amount = 0;
- 		while (*that && col)
- 		{
--		    amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
-+		    amount += lbr_chartabsize_adv(&that, (colnr_T)amount,
-+								    pos->lnum);
- 		    col--;
- 		}
- 
-@@ -9177,7 +9220,8 @@ get_lisp_indent()
- 
- 		    while (vim_iswhite(*that))
- 		    {
--			amount += lbr_chartabsize(that, (colnr_T)amount);
-+			amount += lbr_chartabsize(that, (colnr_T)amount,
-+								    pos->lnum);
- 			++that;
- 		    }
- 
-@@ -9216,14 +9260,17 @@ get_lisp_indent()
- 				    --parencount;
- 				if (*that == '\\' && *(that+1) != NUL)
- 				    amount += lbr_chartabsize_adv(&that,
--							     (colnr_T)amount);
-+							     (colnr_T)amount,
-+							     pos->lnum);
- 				amount += lbr_chartabsize_adv(&that,
--							     (colnr_T)amount);
-+							     (colnr_T)amount,
-+							     pos->lnum);
- 			    }
- 			}
- 			while (vim_iswhite(*that))
- 			{
--			    amount += lbr_chartabsize(that, (colnr_T)amount);
-+			    amount += lbr_chartabsize(that, (colnr_T)amount,
-+							    pos->lnum);
- 			    that++;
- 			}
- 			if (!*that || *that == ';')
-diff --git a/src/misc2.c b/src/misc2.c
---- a/src/misc2.c
-+++ b/src/misc2.c
-@@ -162,7 +162,7 @@ coladvance2(pos, addspaces, finetune, wc
- #ifdef FEAT_VIRTUALEDIT
- 	    if ((addspaces || finetune) && !VIsual_active)
- 	    {
--		curwin->w_curswant = linetabsize(line) + one_more;
-+		curwin->w_curswant = linetabsize(line, pos->lnum) + one_more;
- 		if (curwin->w_curswant > 0)
- 		    --curwin->w_curswant;
- 	    }
-@@ -180,7 +180,7 @@ coladvance2(pos, addspaces, finetune, wc
- # endif
- 		&& wcol >= (colnr_T)width)
- 	{
--	    csize = linetabsize(line);
-+	    csize = linetabsize(line, pos->lnum);
- 	    if (csize > 0)
- 		csize--;
- 
-@@ -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, ptr, col, &head, pos->lnum);
- 	    mb_ptr_adv(ptr);
- #else
--	    csize = lbr_chartabsize_adv(&ptr, col);
-+	    csize = lbr_chartabsize_adv(&ptr, col, pos->lnum);
- #endif
- 	    col += csize;
- 	}
-diff --git a/src/normal.c b/src/normal.c
---- a/src/normal.c
-+++ b/src/normal.c
-@@ -4386,7 +4386,7 @@ nv_screengo(oap, dir, dist)
-     int		dir;
-     long	dist;
- {
--    int		linelen = linetabsize(ml_get_curline());
-+    int		linelen = linetabsize(ml_get_curline(), curwin->w_cursor.lnum);
-     int		retval = OK;
-     int		atend = FALSE;
-     int		n;
-@@ -4459,7 +4459,7 @@ nv_screengo(oap, dir, dist)
- 		    (void)hasFolding(curwin->w_cursor.lnum,
- 						&curwin->w_cursor.lnum, NULL);
- #endif
--		linelen = linetabsize(ml_get_curline());
-+		linelen = linetabsize(ml_get_curline(), curwin->w_cursor.lnum);
- 		if (linelen > width1)
- 		    curwin->w_curswant += (((linelen - width1 - 1) / width2)
- 								+ 1) * width2;
-@@ -4489,7 +4489,7 @@ nv_screengo(oap, dir, dist)
- 		}
- 		curwin->w_cursor.lnum++;
- 		curwin->w_curswant %= width2;
--		linelen = linetabsize(ml_get_curline());
-+		linelen = linetabsize(ml_get_curline(), curwin->w_cursor.lnum);
- 	    }
- 	}
-       }
-diff --git a/src/ops.c b/src/ops.c
---- a/src/ops.c
-+++ b/src/ops.c
-@@ -423,7 +423,8 @@ shift_block(oap, amount)
- 	}
- 	for ( ; vim_iswhite(*bd.textstart); )
- 	{
--	    incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol));
-+	    incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol),
-+							curwin->w_cursor.lnum);
- 	    total += incr;
- 	    bd.start_vcol += incr;
- 	}
-@@ -490,7 +491,8 @@ shift_block(oap, amount)
- 
- 	while (vim_iswhite(*non_white))
- 	{
--	    incr = lbr_chartabsize_adv(&non_white, non_white_col);
-+	    incr = lbr_chartabsize_adv(&non_white, non_white_col,
-+						    curwin->w_cursor.lnum);
- 	    non_white_col += incr;
- 	}
- 
-@@ -515,7 +517,8 @@ 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);
-+	    incr = lbr_chartabsize(verbatim_copy_end, verbatim_copy_width,
-+						    curwin->w_cursor.lnum);
- 	    if (verbatim_copy_width + incr > destination_col)
- 		break;
- 	    verbatim_copy_width += incr;
-@@ -3633,7 +3636,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(&ptr, (colnr_T)vcol, lnum);
- 		vcol += incr;
- 	    }
- 	    bd.textcol = (colnr_T)(ptr - oldp);
-@@ -3667,7 +3670,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(&y_array[i][j], 0, lnum);
- 	    if (spaces < 0)
- 		spaces = 0;
- 
-@@ -5219,7 +5222,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(pstart, (colnr_T)bdp->start_vcol, lnum);
- 	bdp->start_vcol += incr;
- #ifdef FEAT_VISUALEXTRA
- 	if (vim_iswhite(*pstart))
-@@ -5288,7 +5291,7 @@ 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);
-+		incr = lbr_chartabsize_adv(&pend, (colnr_T)bdp->end_vcol, lnum);
- 		bdp->end_vcol += incr;
- 	    }
- 	    if (bdp->end_vcol <= oap->end_vcol
-@@ -6898,7 +6901,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, curwin->w_cursor.lnum));
- 
- 	    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
-@@ -192,6 +192,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
-@@ -659,6 +663,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 *)"min:20,shift:0", (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,
-@@ -5736,6 +5758,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_changed() == FAIL)
-+	    errmsg = e_invarg;
-+    }
-+#endif
- 
-     /*
-      * 'isident', 'iskeyword', 'isprint or 'isfname' option: refill chartab[]
-@@ -10129,6 +10159,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);
-@@ -10322,6 +10354,11 @@ copy_winopt(from, to)
- #endif
- #ifdef FEAT_LINEBREAK
-     to->wo_lbr = from->wo_lbr;
-+    to->wo_bri = from->wo_bri;
-+    to->wo_brimin = from->wo_brimin;
-+    to->wo_brishift = from->wo_brishift;
-+    to->wo_briopt = vim_strsave(from->wo_briopt);
-+    to->wo_brisbr = from->wo_brisbr;
- #endif
- #ifdef FEAT_SCROLLBIND
-     to->wo_scb = from->wo_scb;
-@@ -10409,6 +10446,9 @@ check_winopt(wop)
- #ifdef FEAT_CONCEAL
-     check_string_option(&wop->wo_cocu);
- #endif
-+#ifdef FEAT_LINEBREAK
-+    check_string_option(&wop->wo_briopt);
-+#endif
- }
- 
- /*
-@@ -10428,6 +10468,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
-@@ -12402,3 +12445,47 @@ find_mps_values(initc, findc, backwards,
- 	    ++ptr;
-     }
- }
-+#ifdef FEAT_LINEBREAK
-+/*
-+ * This is called when 'breakindentopt' is changed.
-+ */
-+    int
-+briopt_changed()
-+{
-+    char_u	*p;
-+    /* Defaults */
-+    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
-@@ -1055,6 +1055,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
-@@ -14,9 +14,9 @@ int ptr2cells __ARGS((char_u *p));
- int vim_strsize __ARGS((char_u *s));
- int vim_strnsize __ARGS((char_u *s, int len));
- 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 linetabsize __ARGS((char_u *s, linenr_T lnum));
-+int linetabsize_col __ARGS((int startcol, char_u *s, linenr_T lnum));
-+int win_linetabsize __ARGS((win_T *wp, char_u *p, colnr_T len, linenr_T lnum));
- 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((unsigned char *s, colnr_T col, linenr_T lnum));
-+int lbr_chartabsize_adv __ARGS((char_u **s, colnr_T col, linenr_T lnum));
-+int win_lbr_chartabsize __ARGS((win_T *wp, char_u *s, colnr_T col, int *headp, linenr_T lnum));
- 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
-@@ -8,6 +8,7 @@ int get_indent_str_vtab __ARGS((char_u *
- #endif
- int set_indent __ARGS((int size, int flags));
- int get_number_indent __ARGS((linenr_T lnum));
-+int get_breakindent_win __ARGS((win_T *wp, linenr_T lnum));
- 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
-@@ -74,4 +74,5 @@ int tabstop_first __ARGS((int *ts));
- 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_changed __ARGS((void));
- /* vim: set ft=c : */
-diff --git a/src/regexp.c b/src/regexp.c
---- a/src/regexp.c
-+++ b/src/regexp.c
-@@ -4232,7 +4232,8 @@ reg_match_visual()
- 	    end = end2;
- 	if (top.col == MAXCOL || bot.col == MAXCOL)
- 	    end = MAXCOL;
--	cols = win_linetabsize(wp, regline, (colnr_T)(reginput - regline));
-+	cols = win_linetabsize(wp, regline, (colnr_T)(reginput - regline),
-+						reglnum + reg_firstlnum);
- 	if (cols < start || cols > end - (*p_sel == 'e'))
- 	    return FALSE;
-     }
-@@ -4437,7 +4438,8 @@ regmatch(scan)
- 	  case RE_VCOL:
- 	    if (!re_num_cmp((long_u)win_linetabsize(
- 			    reg_win == NULL ? curwin : reg_win,
--			    regline, (colnr_T)(reginput - regline)) + 1, scan))
-+			    regline, (colnr_T)(reginput - regline),
-+			    reglnum + reg_firstlnum) + 1, scan))
- 		status = RA_NOMATCH;
- 	    break;
- 
-diff --git a/src/regexp_nfa.c b/src/regexp_nfa.c
---- a/src/regexp_nfa.c
-+++ b/src/regexp_nfa.c
-@@ -6422,7 +6422,8 @@ nfa_regmatch(prog, start, submatch, m)
- 		result = nfa_re_num_cmp(t->state->val, t->state->c - NFA_VCOL,
- 		    (long_u)win_linetabsize(
- 			    reg_win == NULL ? curwin : reg_win,
--			    regline, (colnr_T)(reginput - regline)) + 1);
-+			    regline, (colnr_T)(reginput - regline),
-+			    reglnum + reg_firstlnum) + 1);
- 		if (result)
- 		{
- 		    add_here = TRUE;
-diff --git a/src/screen.c b/src/screen.c
---- a/src/screen.c
-+++ b/src/screen.c
-@@ -2959,10 +2959,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 */
-@@ -3298,7 +3303,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, ptr, (colnr_T)vcol, NULL, lnum);
- 	    vcol += c;
- #ifdef FEAT_MBYTE
- 	    prev_ptr = ptr;
-@@ -3668,6 +3673,51 @@ 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
-+		/* FIXME: handle (filler_todo > 0): or modify showbreak so that
-+		 * ---- lines are shorter by the amount needed? */
-+# endif
-+		/* FIXME: what is startrow? Don't we need it as well?? */
-+		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, lnum);
-+		    /* FIXME: why do we need to adjust vcol if showbreak does not??
-+		     * vcol += n_extra;
-+		     * FIXME: is this relevant here? copied shamelessly from showbreak
-+		     *
-+		     * 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)
- 	    {
-@@ -4379,7 +4429,7 @@ win_line(wp, lnum, startrow, endrow, noc
- # ifdef FEAT_MBYTE
- 				has_mbyte ? mb_l :
- # endif
--				1), (colnr_T)vcol, NULL) - 1;
-+				1), (colnr_T)vcol, NULL, lnum) - 1;
- 		    c_extra = ' ';
- 		    if (vim_iswhite(c))
- 		    {
-diff --git a/src/structs.h b/src/structs.h
---- a/src/structs.h
-+++ b/src/structs.h
-@@ -134,6 +134,18 @@ 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' */
-+    long	wo_brimin;
-+# define w_p_brimin w_onebuf_opt.wo_brimin /* 'breakindentmin' */
-+    long	wo_brishift;
-+# define w_p_brishift w_onebuf_opt.wo_brishift /* 'breakindentshift' */
-+    char_u		*wo_briopt;
-+# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */
-+    int			wo_brisbr;
-+# define w_p_brisbr w_onebuf_opt.wo_brisbr /* sbr in breakindent */
-+#endif
- #ifdef FEAT_DIFF
-     int		wo_diff;
- # define w_p_diff w_onebuf_opt.wo_diff	/* 'diff' */
-diff --git a/src/ui.c b/src/ui.c
---- a/src/ui.c
-+++ b/src/ui.c
-@@ -3167,7 +3167,7 @@ vcol2col(wp, lnum, vcol)
-     start = 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, ptr, count, NULL, lnum);
- 	mb_ptr_adv(ptr);
-     }
-     return (int)(ptr - start);

breakindent_updated.diff

+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/doc/options.txt b/runtime/doc/options.txt
+--- a/runtime/doc/options.txt
++++ b/runtime/doc/options.txt
+@@ -1200,6 +1200,38 @@ A jump table for the options with a shor
+ 	break if 'linebreak' is on.  Only works for ASCII and also for 8-bit
+ 	characters when 'encoding' is an 8-bit encoding.
+ 
++						*'breakindent'* *'bri'*
++'breakindent' 'bri'	boolean (default off)
++			local to window
++			{not in Vi}
++			{not available when compiled without the |+linebreak|
++			feature}
++	Every wrapped line will continue visually indented (same amount of
++	space as the beginning of that line), thus preserving horizontal blocks
++	of text.
++
++						*'breakindentmin'* *'brimin'*
++'breakindentopt' 'briopt' string (default "min:20,shift:0")
++			local to window
++			{not in Vi}
++			{not available when compiled without the |+linebreak|
++			feature}
++	Settings for 'breakindent'. It can consist of the following optional
++	items and must be seperated by a comma:
++		min:{n}	    Minimum text width that will be kept after
++			    applying 'breakindent', even if the resulting
++			    text should normally be narrower. This prevents
++			    text indented almost to the right window border
++			    occupying lot of vertical space when broken.
++		shift:{n}   After applying 'breakindent', wrapped line
++			    beginning will be shift by given number of
++			    characters. It permits dynamic French paragraph
++			    indentation (negative) or emphasizing the line
++			    continuation (positive).
++		sbr	    Display the 'showbreak' value before applying the 
++			    additional indent.
++	If empty, the default for min is 20 and shift is 0
++
+ 						*'browsedir'* *'bsdir'*
+ 'browsedir' 'bsdir'	string	(default: "last")
+ 			global
+@@ -4574,12 +4606,13 @@ A jump table for the options with a shor
+ 			{not in Vi}
+ 			{not available when compiled without the |+linebreak|
+ 			feature}
+-	If on Vim will wrap long lines at a character in 'breakat' rather
++	If on, Vim will wrap long lines at a character in 'breakat' rather
+ 	than at the last character that fits on the screen.  Unlike
+ 	'wrapmargin' and 'textwidth', this does not insert <EOL>s in the file,
+-	it only affects the way the file is displayed, not its contents.  The
+-	value of 'showbreak' is used to put in front of wrapped lines.
+-	This option is not used when the 'wrap' option is off or 'list' is on.
++	it only affects the way the file is displayed, not its contents.
++	If 'breakindent' is set, line is visually indented. Then, the value
++	of 'showbreak' is used to put in front of wrapped lines. This option
++	is not used when the 'wrap' option is off or 'list' is on.
+ 	Note that <Tab> characters after an <EOL> are mostly not displayed
+ 	with the right amount of white space.
+ 
+diff --git a/runtime/optwin.vim b/runtime/optwin.vim
+--- a/runtime/optwin.vim
++++ b/runtime/optwin.vim
+@@ -324,6 +324,12 @@ call <SID>BinOptionG("wrap", &wrap)
+ call append("$", "linebreak\twrap long lines at a character in 'breakat'")
+ call append("$", "\t(local to window)")
+ call <SID>BinOptionL("lbr")
++call append("$", "breakindent\tpreserve indentation in wrapped text")
++call append("$", "\t(local to window)")
++call <SID>BinOptionL("bri")
++call append("$", "breakindentopt\tadjust breakindent behaviour")
++call append("$", "\t(local to window)")
++call <SID>OptionL("briopt")
+ call append("$", "breakat\twhich characters might cause a line break")
+ call <SID>OptionG("brk", &brk)
+ call append("$", "showbreak\tstring to put before wrapped screen lines")
+diff --git a/src/buffer.c b/src/buffer.c
+--- a/src/buffer.c
++++ b/src/buffer.c
+@@ -2704,6 +2704,9 @@ get_winopts(buf)
+ #ifdef FEAT_SYN_HL
+     check_colorcolumn(curwin);
+ #endif
++#ifdef FEAT_LINEBREAK
++    briopt_check();
++#endif
+ }
+ 
+ /*
+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	*p = s; /* pointer to start of line, needed for breakindent */
+ 
+     while (*s != NUL)
+-	col += lbr_chartabsize_adv(&s, col);
++	col += lbr_chartabsize_adv(&s, col, p);
+     return (int)col;
+ }
+ 
+@@ -886,7 +887,7 @@ win_linetabsize(wp, p, len)
+     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);
++	col += win_lbr_chartabsize(wp, s, col, NULL, p);
+     return (int)col;
+ }
+ 
+@@ -1021,12 +1022,13 @@ vim_isprintc_strict(c)
+  * like chartabsize(), but also check for line breaks on the screen
+  */
+     int
+-lbr_chartabsize(s, col)
++lbr_chartabsize(s, col, p)
+     unsigned char	*s;
+     colnr_T		col;
++    char_u		*p;
+ {
+ #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 +1038,9 @@ lbr_chartabsize(s, col)
+ 	RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col)
+ #ifdef FEAT_LINEBREAK
+     }
+-    return win_lbr_chartabsize(curwin, s, col, NULL);
++    if (p == NULL)
++	p = s;
++    return win_lbr_chartabsize(curwin, s, col, NULL, p);
+ #endif
+ }
+ 
+@@ -1044,13 +1048,14 @@ lbr_chartabsize(s, col)
+  * Call lbr_chartabsize() and advance the pointer.
+  */
+     int
+-lbr_chartabsize_adv(s, col)
++lbr_chartabsize_adv(s, col, p)
+     char_u	**s;
+     colnr_T	col;
++    char_u	*p;
+ {
+     int		retval;
+ 
+-    retval = lbr_chartabsize(*s, col);
++    retval = lbr_chartabsize(*s, col, p);
+     mb_ptr_adv(*s);
+     return retval;
+ }
+@@ -1063,11 +1068,12 @@ lbr_chartabsize_adv(s, col)
+  * value, init to 0 before calling.
+  */
+     int
+-win_lbr_chartabsize(wp, s, col, headp)
++win_lbr_chartabsize(wp, s, col, headp, p)
+     win_T	*wp;
+     char_u	*s;
+     colnr_T	col;
+     int		*headp UNUSED;
++    char_u	*p;
+ {
+ #ifdef FEAT_LINEBREAK
+     int		c;
+@@ -1086,9 +1092,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 +1169,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 +1187,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, p);
++
+ 	    if (tab_corr)
+ 		size += (added / wp->w_buffer->b_p_ts) * wp->w_buffer->b_p_ts;
+ 	    else
+@@ -1274,13 +1286,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	*p;		/* holds complete ptr 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);
++    p = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
+     if (pos->col == MAXCOL)
+ 	posptr = NULL;  /* continue until the NUL */
+     else
+@@ -1288,12 +1301,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 +1369,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, ptr, vcol, &head, p);
+ 	    /* 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 + new_cursor_col, (colnr_T)vcol, ptr);
+ 	}
+ 	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((char_u *)"\t", vcol, NULL);
+ 	    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 *p = ptr;
+ 
+ 	    /* Skip over the spaces we need. */
+ 	    while (vcol < want_vcol && *ptr == ' ')
+ 	    {
+-		vcol += lbr_chartabsize(ptr, vcol);
++		vcol += lbr_chartabsize(ptr, vcol, p);
+ 		++ptr;
+ 		++repl_off;
+ 	    }
+@@ -10029,6 +10031,7 @@ ins_copychar(lnum)
+     int	    c;
+     int	    temp;
+     char_u  *ptr, *prev_ptr;
++    char_u  *p;
+ 
+     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);
++    p = 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(&ptr, (colnr_T)temp, p);
+     }
+     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
+@@ -2295,10 +2295,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);
+ 
+@@ -2350,11 +2350,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
+@@ -2676,7 +2676,7 @@ vgetorpeek(advance)
+ 				    if (!vim_iswhite(ptr[col]))
+ 					curwin->w_wcol = vcol;
+ 				    vcol += lbr_chartabsize(ptr + col,
+-							       (colnr_T)vcol);
++							       (colnr_T)vcol, ptr);
+ #ifdef FEAT_MBYTE
+ 				    if (has_mbyte)
+ 					col += (*mb_ptr2len)(ptr + col);
+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,57 @@ get_number_indent(lnum)
+     return (int)col;
+ }
+ 
++#ifdef FEAT_LINEBREAK
++/*
++ * 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, s)
++    win_T	*wp;
++    char_u	*s;
++{
++    static int	    indent = 0;  /* cached indent value */
++    static long	    ts     = 0L; /* if tabstop changes, need to refresh indent */
++    static char_u   *ptr = NULL; /* cached pointer to string */
++    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);
++
++    if (ptr != s || ts != wp->w_buffer->b_p_ts)
++    {
++	/* line changed, so must refresh indent */
++	ptr = s;
++	indent = get_indent_str(ptr, (int)wp->w_buffer->b_p_ts, wp->w_p_list) + wp->w_p_brishift;
++	ts = wp->w_buffer->b_p_ts;
++    }
++
++    bri = indent;
++    /* minus the length of the showbreak string */
++    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 +736,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 +1259,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 +2052,7 @@ plines_win_col(wp, lnum, column)
+     char_u	*s;
+     int		lines = 0;
+     int		width;
++    char_u	*p;
+ 
+ #ifdef FEAT_DIFF
+     /* Check for filler lines above this buffer line.  When folded the result
+@@ -2009,12 +2068,12 @@ plines_win_col(wp, lnum, column)
+ 	return lines + 1;
+ #endif
+ 
+-    s = ml_get_buf(wp->w_buffer, lnum, FALSE);
++    p = 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, s, (colnr_T)col, NULL, p);
+ 	mb_ptr_adv(s);
+     }
+ 
+@@ -2026,7 +2085,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, s, (colnr_T)col, NULL, p) - 1;
+ 
+     /*
+      * Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
+@@ -9002,10 +9061,11 @@ get_lisp_indent()
+ 		amount = 2;
+ 	    else
+ 	    {
++		char_u *p = that;
+ 		amount = 0;
+ 		while (*that && col)
+ 		{
+-		    amount += lbr_chartabsize_adv(&that, (colnr_T)amount);
++		    amount += lbr_chartabsize_adv(&that, (colnr_T)amount, p);
+ 		    col--;
+ 		}
+ 
+@@ -9028,7 +9088,7 @@ get_lisp_indent()
+ 
+ 		    while (vim_iswhite(*that))
+ 		    {
+-			amount += lbr_chartabsize(that, (colnr_T)amount);
++			amount += lbr_chartabsize(that, (colnr_T)amount, p);
+ 			++that;
+ 		    }
+ 
+@@ -9067,14 +9127,14 @@ get_lisp_indent()
+ 				    --parencount;
+ 				if (*that == '\\' && *(that+1) != NUL)
+ 				    amount += lbr_chartabsize_adv(&that,
+-							     (colnr_T)amount);
++							     (colnr_T)amount, p);
+ 				amount += lbr_chartabsize_adv(&that,
+-							     (colnr_T)amount);
++							     (colnr_T)amount, p);
+ 			    }
+ 			}
+ 			while (vim_iswhite(*that))
+ 			{
+-			    amount += lbr_chartabsize(that, (colnr_T)amount);
++			    amount += lbr_chartabsize(that, (colnr_T)amount, p);
+ 			    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, ptr, col, &head, line);
+ 	    mb_ptr_adv(ptr);
+ #else
+-	    csize = lbr_chartabsize_adv(&ptr, col);
++	    csize = lbr_chartabsize_adv(&ptr, col, line);
+ #endif
+ 	    col += csize;
+ 	}
+diff --git a/src/ops.c b/src/ops.c
+--- a/src/ops.c
++++ b/src/ops.c
+@@ -420,7 +420,7 @@ shift_block(oap, amount)
+ 	}
+ 	for ( ; vim_iswhite(*bd.textstart); )
+ 	{
+-	    incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol));
++	    incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol), bd.textstart);
+ 	    total += incr;
+ 	    bd.start_vcol += incr;
+ 	}
+@@ -480,7 +480,7 @@ shift_block(oap, amount)
+ 
+ 	while (vim_iswhite(*non_white))
+ 	{
+-	    incr = lbr_chartabsize_adv(&non_white, non_white_col);
++	    incr = lbr_chartabsize_adv(&non_white, non_white_col, bd.textstart);
+ 	    non_white_col += incr;
+ 	}
+ 
+@@ -505,7 +505,8 @@ 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 *p = verbatim_copy_end;
++	    incr = lbr_chartabsize(verbatim_copy_end, verbatim_copy_width, p);
+ 	    if (verbatim_copy_width + incr > destination_col)
+ 		break;
+ 	    verbatim_copy_width += incr;
+@@ -3617,7 +3618,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(&ptr, (colnr_T)vcol, oldp);
+ 		vcol += incr;
+ 	    }
+ 	    bd.textcol = (colnr_T)(ptr - oldp);
+@@ -3651,7 +3652,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(&y_array[i][j], 0, NULL);
+ 	    if (spaces < 0)
+ 		spaces = 0;
+ 
+@@ -5203,7 +5204,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(pstart, (colnr_T)bdp->start_vcol, line);
+ 	bdp->start_vcol += incr;
+ #ifdef FEAT_VISUALEXTRA
+ 	if (vim_iswhite(*pstart))
+@@ -5272,7 +5273,7 @@ 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);
++		incr = lbr_chartabsize_adv(&pend, (colnr_T)bdp->end_vcol, prev_pend);
+ 		bdp->end_vcol += incr;
+ 	    }
+ 	    if (bdp->end_vcol <= oap->end_vcol
+@@ -6882,7 +6883,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 *)"min:20,shift:0", (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,
+@@ -5709,6 +5731,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[]
+@@ -10013,6 +10043,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);
+@@ -10202,6 +10234,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;
+@@ -10289,6 +10323,9 @@ check_winopt(wop)
+ #ifdef FEAT_CONCEAL
+     check_string_option(&wop->wo_cocu);
+ #endif
++#ifdef FEAT_LINEBREAK
++    check_string_option(&wop->wo_briopt);
++#endif
+ }
+ 
+ /*
+@@ -10308,6 +10345,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
+@@ -11922,3 +11962,47 @@ find_mps_values(initc, findc, backwards,
+ 	    ++ptr;
+     }
+ }
++#ifdef FEAT_LINEBREAK
++/*
++ * This is called when 'breakindentopt' is changed.
++ */
++    int
++briopt_check()
++{
++    char_u	*p;
++    /* Defaults */
++    int		bri_shift = 0;
++    long	bri_min = 0;
++    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
+@@ -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((unsigned char *s, colnr_T col, char_u *p));
++int lbr_chartabsize_adv __ARGS((char_u **s, colnr_T col, char_u *p));
++int win_lbr_chartabsize __ARGS((win_T *wp, char_u *s, colnr_T col, int *headp, char_u *p));
+ 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, ptr, (colnr_T)vcol, NULL, line);
+ 	    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,12 @@ 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);
++		    n_extra = win_lbr_chartabsize(wp, p, (colnr_T)vcol, NULL, p) - 1;
+ 		    c_extra = ' ';
+ 		    if (vim_iswhite(c))
+ 		    {
+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_vms.mms b/src/testdir/Make_vms.mms
+--- a/src/testdir/Make_vms.mms