diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1984,7 +1984,8 @@
 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}
@@ -5792,13 +5793,15 @@
 		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
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1232,6 +1232,38 @@
 			    additional indent.
 	The default value for min is 20 and shift is 0.
 
+						*'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
diff --git a/src/buffer.c b/src/buffer.c
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2704,6 +2704,9 @@
 #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
@@ -852,25 +852,26 @@
  * 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;
-    char_u	*line = s; /* pointer to start of line, for breakindent */
 
     while (*s != NUL)
-	col += lbr_chartabsize_adv(line, &s, col);
+	col += lbr_chartabsize_adv(&s, col, lnum);
     return (int)col;
 }
 
@@ -878,17 +879,17 @@
  * Like linetabsize(), but for a given window instead of the current one.
  */
     int
-win_linetabsize(wp, line, len)
+win_linetabsize(wp, p, len, lnum)
     win_T	*wp;
-    char_u	*line;
+    char_u	*p;
     colnr_T	len;
+    linenr_T	lnum;
 {
     colnr_T	col = 0;
     char_u	*s;
 
-    for (s = line; *s != NUL && (len == MAXCOL || s < line + len);
-								mb_ptr_adv(s))
-	col += win_lbr_chartabsize(wp, line, s, col, NULL);
+    for (s = p; *s != NUL && (len == MAXCOL || s < p + len); mb_ptr_adv(s))
+	col += win_lbr_chartabsize(wp, s, col, NULL, lnum);
     return (int)col;
 }
 
@@ -1023,10 +1024,10 @@
  * like chartabsize(), but also check for line breaks on the screen
  */
     int
-lbr_chartabsize(line, s, col)
-    char_u		*line; /* start of the line */
+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 && !curwin->w_p_bri)
@@ -1039,7 +1040,7 @@
 	RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col)
 #ifdef FEAT_LINEBREAK
     }
-    return win_lbr_chartabsize(curwin, line == NULL ? s : line, s, col, NULL);
+    return win_lbr_chartabsize(curwin, s, col, NULL, lnum);
 #endif
 }
 
@@ -1047,14 +1048,14 @@
  * Call lbr_chartabsize() and advance the pointer.
  */
     int
-lbr_chartabsize_adv(line, s, col)
-    char_u	*line; /* start of the line */
+lbr_chartabsize_adv(s, col, lnum)
     char_u	**s;
     colnr_T	col;
+    linenr_T	lnum;
 {
     int		retval;
 
-    retval = lbr_chartabsize(line, *s, col);
+    retval = lbr_chartabsize(*s, col, lnum);
     mb_ptr_adv(*s);
     return retval;
 }
@@ -1065,14 +1066,17 @@
  * 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, line, s, col, headp)
+win_lbr_chartabsize(wp, s, col, headp, lnum)
     win_T	*wp;
-    char_u	*line; /* start of the line */
     char_u	*s;
     colnr_T	col;
     int		*headp UNUSED;
+    linenr_T	lnum;
 {
 #ifdef FEAT_LINEBREAK
     int		c;
@@ -1190,7 +1194,7 @@
 	    if (*p_sbr != NUL)
 		added += vim_strsize(p_sbr);
 	    if (wp->w_p_bri)
-		added += get_breakindent_win(wp, line);
+		added += get_breakindent_win(wp, lnum);
 
 	    if (tab_corr)
 		size += (added / wp->w_buffer->b_p_ts) * wp->w_buffer->b_p_ts;
@@ -1285,14 +1289,13 @@
     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;
-    line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
+    ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
     if (pos->col == MAXCOL)
 	posptr = NULL;  /* continue until the NUL */
     else
@@ -1368,7 +1371,7 @@
 	{
 	    /* A tab gets expanded, depending on the current column */
 	    head = 0;
-	    incr = win_lbr_chartabsize(wp, line, 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 @@
 	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;
@@ -1956,7 +1956,8 @@
 	    else
 #endif
 		++new_cursor_col;
-	    vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
+	    vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_T)vcol,
+							curwin->w_cursor.lnum);
 	}
 	vcol = last_vcol;
 
@@ -6771,7 +6772,8 @@
 	    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)
@@ -9763,7 +9765,7 @@
 	 * and 'linebreak' adding extra virtual columns. */
 	while (vim_iswhite(*ptr))
 	{
-	    i = lbr_chartabsize(NULL, (char_u *)"\t", vcol);
+	    i = lbr_chartabsize((char_u *)"\t", vcol, cursor->lnum);
 	    if (vcol + i > want_vcol)
 		break;
 	    if (*ptr != TAB)
@@ -9785,12 +9787,11 @@
 	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(line, ptr, vcol);
+		vcol += lbr_chartabsize(ptr, vcol, cursor->lnum);
 		++ptr;
 		++repl_off;
 	    }
@@ -10031,7 +10032,6 @@
     int	    c;
     int	    temp;
     char_u  *ptr, *prev_ptr;
-    char_u  *line;
 
     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
     {
@@ -10041,13 +10041,13 @@
 
     /* try to advance to the cursor column */
     temp = 0;
-    line = ptr = ml_get(lnum);
+    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(line, &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
@@ -8146,7 +8146,7 @@
 #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
@@ -18037,11 +18037,17 @@
 {
     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 @@
 	;
     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
@@ -2675,8 +2675,9 @@
 				{
 				    if (!vim_iswhite(ptr[col]))
 					curwin->w_wcol = vcol;
-				    vcol += lbr_chartabsize(ptr, ptr + col,
-							       (colnr_T)vcol);
+				    vcol += lbr_chartabsize(ptr + col,
+							       (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
@@ -335,7 +335,7 @@
 	{
 	    /* 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
@@ -487,39 +487,26 @@
 /*
  * Return appropriate space number for breakindent, taking influencing
  * parameters into account. Window must be specified, since it is not
- * necessarily always the current one.
+ * necessarily always the current one. If lnum==0, current line is calculated,
+ * specified line otherwise.
  */
     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 */
-    static int	    prev_tick = 0;   /* changedtick of cached value */
-    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_tick != wp->w_buffer->b_changedtick)
-    {
-	prev_line = line;
-	prev_ts = wp->w_buffer->b_p_ts;
-	prev_tick = wp->w_buffer->b_changedtick;
-	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;
+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 -= vim_strsize(p_sbr);
+	bri -= (*p_sbr == NUL ? 0 : vim_strsize(p_sbr));
 
     /* Add offset for number column, if 'n' is in 'cpoptions' */
     bri += win_col_off2(wp);
@@ -2020,7 +2007,7 @@
     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
@@ -2056,7 +2043,6 @@
     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
@@ -2072,12 +2058,12 @@
 	return lines + 1;
 #endif
 
-    line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
+    s = ml_get_buf(wp->w_buffer, lnum, FALSE);
 
     col = 0;
     while (*s != NUL && --column >= 0)
     {
-	col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
+	col += win_lbr_chartabsize(wp, s, (colnr_T)col, NULL, lnum);
 	mb_ptr_adv(s);
     }
 
@@ -2089,7 +2075,7 @@
      * 'ts') -- webb.
      */
     if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1))
-	col += win_lbr_chartabsize(wp, line, 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.
@@ -9065,12 +9051,11 @@
 		amount = 2;
 	    else
 	    {
-		char_u *line = that;
-
 		amount = 0;
 		while (*that && col)
 		{
-		    amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
+		    amount += lbr_chartabsize_adv(&that, (colnr_T)amount,
+								    pos->lnum);
 		    col--;
 		}
 
@@ -9093,7 +9078,8 @@
 
 		    while (vim_iswhite(*that))
 		    {
-			amount += lbr_chartabsize(line, that, (colnr_T)amount);
+			amount += lbr_chartabsize(that, (colnr_T)amount,
+								    pos->lnum);
 			++that;
 		    }
 
@@ -9131,16 +9117,18 @@
 							       && !quotecount)
 				    --parencount;
 				if (*that == '\\' && *(that+1) != NUL)
-				    amount += lbr_chartabsize_adv(
-						line, &that, (colnr_T)amount);
-				amount += lbr_chartabsize_adv(
-						line, &that, (colnr_T)amount);
+				    amount += lbr_chartabsize_adv(&that,
+							     (colnr_T)amount,
+							     pos->lnum);
+				amount += lbr_chartabsize_adv(&that,
+							     (colnr_T)amount,
+							     pos->lnum);
 			    }
 			}
 			while (vim_iswhite(*that))
 			{
-			    amount += lbr_chartabsize(
-						 line, 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 @@
 #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 @@
 # endif
 		&& wcol >= (colnr_T)width)
 	{
-	    csize = linetabsize(line);
+	    csize = linetabsize(line, pos->lnum);
 	    if (csize > 0)
 		csize--;
 
@@ -201,10 +201,10 @@
 	{
 	    /* Count a tab for what it's worth (if list mode not on) */
 #ifdef FEAT_LINEBREAK
-	    csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
+	    csize = win_lbr_chartabsize(curwin, ptr, col, &head, pos->lnum);
 	    mb_ptr_adv(ptr);
 #else
-	    csize = lbr_chartabsize_adv(line, &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 @@
     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 @@
 		    (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 @@
 		}
 		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
@@ -420,9 +420,8 @@
 	}
 	for ( ; vim_iswhite(*bd.textstart); )
 	{
-	    /* TODO: is passing bd.textstart for start of the line OK? */
-	    incr = lbr_chartabsize_adv(bd.textstart, &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;
 	}
@@ -482,7 +481,8 @@
 
 	while (vim_iswhite(*non_white))
 	{
-	    incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col);
+	    incr = lbr_chartabsize_adv(&non_white, non_white_col,
+						    curwin->w_cursor.lnum);
 	    non_white_col += incr;
 	}
 
@@ -507,11 +507,8 @@
 	    verbatim_copy_width -= bd.start_char_vcols;
 	while (verbatim_copy_width < destination_col)
 	{
-	    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);
+	    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;
@@ -3623,7 +3620,7 @@
 	    for (ptr = oldp; vcol < col && *ptr; )
 	    {
 		/* Count a tab for what it's worth (if list mode not on) */
-		incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
+		incr = lbr_chartabsize_adv(&ptr, (colnr_T)vcol, lnum);
 		vcol += incr;
 	    }
 	    bd.textcol = (colnr_T)(ptr - oldp);
@@ -3657,7 +3654,7 @@
 	    /* calculate number of spaces required to fill right side of block*/
 	    spaces = y_width + 1;
 	    for (j = 0; j < yanklen; j++)
-		spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
+		spaces -= lbr_chartabsize(&y_array[i][j], 0, lnum);
 	    if (spaces < 0)
 		spaces = 0;
 
@@ -5209,7 +5206,7 @@
     while (bdp->start_vcol < oap->start_vcol && *pstart)
     {
 	/* Count a tab for what it's worth (if list mode not on) */
-	incr = lbr_chartabsize(line, 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))
@@ -5278,10 +5275,7 @@
 	    {
 		/* Count a tab for what it's worth (if list mode not on) */
 		prev_pend = pend;
-		/* 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);
+		incr = lbr_chartabsize_adv(&pend, (colnr_T)bdp->end_vcol, lnum);
 		bdp->end_vcol += incr;
 	    }
 	    if (bdp->end_vcol <= oap->end_vcol
@@ -6892,7 +6886,7 @@
 	    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));
+				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
@@ -664,7 +664,7 @@
     {"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}
+			    {(char_u *)"min:20,shift:0", (char_u *)NULL}
 #else
 			    (char_u *)NULL, PV_NONE,
 			    {(char_u *)"", (char_u *)NULL}
@@ -5279,9 +5279,6 @@
     /* set cedit_key */
     (void)check_cedit();
 #endif
-#ifdef FEAT_LINEBREAK
-    briopt_check();
-#endif
 }
 
 /*
@@ -5739,7 +5736,7 @@
     /* 'breakindentopt' */
     else if (varp == &curwin->w_p_briopt)
     {
-	if (briopt_check() == FAIL)
+	if (briopt_changed() == FAIL)
 	    errmsg = e_invarg;
     }
 #endif
@@ -8994,12 +8991,12 @@
 }
 
 /*
- * Iterate over options. First argument is a pointer to a pointer to a structure 
+ * Iterate over options. First argument is a pointer to a pointer to a structure
  * inside options[] array, second is option type like in the above function.
  *
- * If first argument points to NULL it is assumed that iteration just started 
+ * If first argument points to NULL it is assumed that iteration just started
  * and caller needs the very first value.
- * If first argument points to the end marker function returns NULL and sets 
+ * If first argument points to the end marker function returns NULL and sets
  * first argument to NULL.
  *
  * Returns full option name for current option on each call.
@@ -10244,7 +10241,10 @@
 #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;
@@ -11974,13 +11974,13 @@
 
 #if defined(FEAT_LINEBREAK) || defined(PROTO)
 /*
- * This is called when 'breakindentopt' is changed and when a window is
- * initialized.
+ * This is called when 'breakindentopt' is changed.
  */
     int
-briopt_check()
+briopt_changed()
 {
     char_u	*p;
+    /* Defaults */
     int		bri_shift = 0;
     long	bri_min = 20;
     int		bri_sbr = FALSE;
@@ -11988,8 +11988,7 @@
     p = curwin->w_p_briopt;
     while (*p != NUL)
     {
-	if (STRNCMP(p, "shift:", 6) == 0
-		 && ((p[6] == '-' && VIM_ISDIGIT(p[7])) || VIM_ISDIGIT(p[6])))
+	if (STRNCMP(p, "shift:", 6) == 0 && ((p[6] == '-' && VIM_ISDIGIT(p[7])) || VIM_ISDIGIT(p[6])))
 	{
 	    p += 6;
 	    bri_shift = getdigits(&p);
@@ -12012,7 +12011,7 @@
 
     curwin->w_p_brishift = bri_shift;
     curwin->w_p_brimin   = bri_min;
-    curwin->w_p_brisbr   = bri_sbr;
+    curwin->w_p_brisbr	 = bri_sbr;
 
     return OK;
 }
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 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 *line, 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_or_wc __ARGS((int c));
 int vim_isprintc __ARGS((int c));
 int vim_isprintc_strict __ARGS((int c));
-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 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
@@ -5,7 +5,7 @@
 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 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
@@ -62,5 +62,5 @@
 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));
+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
@@ -4231,7 +4231,8 @@
 	    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;
     }
@@ -4436,7 +4437,8 @@
 	  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
@@ -6421,7 +6421,8 @@
 		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
@@ -3306,7 +3306,7 @@
 #endif
 	while (vcol < v && *ptr != NUL)
 	{
-	    c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
+	    c = win_lbr_chartabsize(wp, ptr, (colnr_T)vcol, NULL, lnum);
 	    vcol += c;
 #ifdef FEAT_MBYTE
 	    prev_ptr = ptr;
@@ -3676,11 +3676,12 @@
 	    }
 
 #ifdef FEAT_LINEBREAK
-	    if (wp->w_p_brisbr && draw_state == WL_BRI - 1
-					     && n_extra == 0 && *p_sbr != NUL)
+	    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)
+	    else if (wp->w_p_brisbr && draw_state == WL_SBR &&
+		    n_extra == 0)
 		/* After the showbreak, draw the breakindent */
 		draw_state = WL_BRI - 1;
 
@@ -3689,7 +3690,10 @@
 	    {
 		draw_state = WL_BRI;
 # ifdef FEAT_DIFF
-# endif
+		/* 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
@@ -3703,9 +3707,12 @@
 #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',
+		    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;
@@ -4425,14 +4432,11 @@
 		if (wp->w_p_lbr && vim_isbreak(c) && !vim_isbreak(*ptr)
 							     && !wp->w_p_list)
 		{
-		    char_u *p = ptr - (
+		    n_extra = win_lbr_chartabsize(wp, ptr - (
 # ifdef FEAT_MBYTE
 				has_mbyte ? mb_l :
 # endif
-				1);
-		    /* TODO: is passing p for start of the line OK? */
-		    n_extra = win_lbr_chartabsize(wp, p, p, (colnr_T)vcol,
-								    NULL) - 1;
+				1), (colnr_T)vcol, NULL, lnum) - 1;
 		    c_extra = ' ';
 		    if (vim_iswhite(c))
 		    {
@@ -8962,8 +8966,8 @@
 	{
 	    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
@@ -137,8 +137,14 @@
 #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;
@@ -2195,11 +2201,6 @@
 #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/ui.c b/src/ui.c
--- a/src/ui.c
+++ b/src/ui.c
@@ -3162,15 +3162,15 @@
     /* try to advance to the specified column */
     int		count = 0;
     char_u	*ptr;
-    char_u	*line;
+    char_u	*start;
 
-    line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
+    start = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
     while (count < vcol && *ptr != NUL)
     {
-	count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
+	count += win_lbr_chartabsize(wp, ptr, count, NULL, lnum);
 	mb_ptr_adv(ptr);
     }
-    return (int)(ptr - line);
+    return (int)(ptr - start);
 }
 #endif
 
