changeset 32981:2415680a2554 v9.0.1783

commit b557f4898208105b674df605403cac1b1292707b Author: zeertzjq <zeertzjq@outlook.com> Date: Tue Aug 22 22:07:34 2023 +0200 patch 9.0.1783: Display issues with virt text smoothscroll and showbreak Problem: Wrong display with wrapping virtual text or unprintable chars, 'showbreak' and 'smoothscroll'. Solution: Don't skip cells taken by 'showbreak' in screen lines before "w_skipcol". Combined "n_skip" and "skip_cells". closes: #12597 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
author Christian Brabandt <cb@256bit.org>
date Thu, 24 Aug 2023 07:47:10 +0200
parents c7a332a34fe7
children ebb36e3d5299
files src/charset.c src/drawline.c src/edit.c src/structs.h src/testdir/dumps/Test_prop_before_tab_skipcol_1.dump src/testdir/dumps/Test_prop_before_tab_skipcol_10.dump src/testdir/dumps/Test_prop_before_tab_skipcol_11.dump src/testdir/dumps/Test_prop_before_tab_skipcol_2.dump src/testdir/dumps/Test_prop_before_tab_skipcol_3.dump src/testdir/dumps/Test_prop_before_tab_skipcol_4.dump src/testdir/dumps/Test_prop_before_tab_skipcol_5.dump src/testdir/dumps/Test_prop_before_tab_skipcol_6.dump src/testdir/dumps/Test_prop_before_tab_skipcol_7.dump src/testdir/dumps/Test_prop_before_tab_skipcol_8.dump src/testdir/dumps/Test_prop_before_tab_skipcol_9.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_1.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_10.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_11.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_12.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_13.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_14.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_15.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_16.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_17.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_18.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_19.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_2.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_20.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_21.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_3.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_4.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_5.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_6.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_7.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_8.dump src/testdir/dumps/Test_prop_inserts_text_showbreak_9.dump src/testdir/test_listlbr.vim src/testdir/test_listlbr_utf8.vim src/testdir/test_textprop.vim src/version.c
diffstat 40 files changed, 534 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/src/charset.c
+++ b/src/charset.c
@@ -1097,9 +1097,14 @@ lbr_chartabsize_adv(chartabsize_T *cts)
  * inserts text.
  * This function is used very often, keep it fast!!!!
  *
- * 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.
+ * If "headp" not NULL, set "*headp" to the size of 'showbreak'/'breakindent'
+ * included in the return value.
+ * When "cts->cts_max_head_vcol" is positive, only count in "*headp" the size
+ * of 'showbreak'/'breakindent' before "cts->cts_max_head_vcol".
+ * When "cts->cts_max_head_vcol" is negative, only count in "*headp" the size
+ * of 'showbreak'/'breakindent' before where cursor should be placed.
+ *
+ * Warning: "*headp" may not be set if it's 0, init to 0 before calling.
  */
     int
 win_lbr_chartabsize(
@@ -1118,9 +1123,7 @@ win_lbr_chartabsize(
     colnr_T	col2;
     colnr_T	col_adj = 0; // vcol + screen size of tab
     colnr_T	colmax;
-    int		added;
     int		mb_added = 0;
-    int		numberextra;
     char_u	*ps;
     int		tab_corr = (*s == TAB);
     int		n;
@@ -1256,7 +1259,7 @@ win_lbr_chartabsize(
 	 * Count all characters from first non-blank after a blank up to next
 	 * non-blank after a blank.
 	 */
-	numberextra = win_col_off(wp);
+	int numberextra = win_col_off(wp);
 	col2 = vcol;
 	colmax = (colnr_T)(wp->w_width - numberextra - col_adj);
 	if (vcol >= colmax)
@@ -1296,72 +1299,93 @@ win_lbr_chartabsize(
     /*
      * May have to add something for 'breakindent' and/or 'showbreak'
      * string at start of line.
-     * Set *headp to the size of what we add.
      * Do not use 'showbreak' at the NUL after the text.
      */
-    added = 0;
+    int head = mb_added;
     sbr = (c == NUL || no_sbr) ? empty_option : get_showbreak_value(wp);
-    if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0)
+    if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap)
     {
-	colnr_T sbrlen = 0;
-	int	numberwidth = win_col_off(wp);
-
-	numberextra = numberwidth;
-	vcol += numberextra + mb_added;
+	int	col_off_prev = win_col_off(wp);
+	int	width2 = wp->w_width - col_off_prev + win_col_off2(wp);
+	vcol += mb_added;
 #ifdef FEAT_PROP_POPUP
 	vcol -= wp->w_virtcol_first_char;
 #endif
-	if (vcol >= (colnr_T)wp->w_width)
+	colnr_T	wcol = vcol + col_off_prev;
+	// cells taken by 'showbreak'/'breakindent' before current char
+	int	head_prev = 0;
+	if (wcol >= wp->w_width)
 	{
-	    vcol -= wp->w_width;
-	    numberextra = wp->w_width - (numberextra - win_col_off2(wp));
-	    if (vcol >= numberextra && numberextra > 0)
-		vcol %= numberextra;
+	    wcol -= wp->w_width;
+	    col_off_prev = wp->w_width - width2;
+	    if (wcol >= width2 && width2 > 0)
+		wcol %= width2;
 	    if (*sbr != NUL)
+		head_prev += vim_strsize(sbr);
+	    if (wp->w_p_bri)
+		head_prev += get_breakindent_win(wp, line);
+	    if (wcol < head_prev)
+		wcol = head_prev;
+	    wcol += col_off_prev;
+	}
+
+	if ((vcol > 0 && wcol == col_off_prev + head_prev)
+						  || wcol + size > wp->w_width)
+	{
+	    int added = 0;
+	    colnr_T max_head_vcol = cts->cts_max_head_vcol;
+
+	    if (vcol > 0 && wcol == col_off_prev + head_prev)
 	    {
-		sbrlen = (colnr_T)MB_CHARLEN(sbr);
-		if (vcol >= sbrlen)
-		    vcol -= sbrlen;
+		added += head_prev;
+		if (max_head_vcol <= 0 || vcol < max_head_vcol)
+		    head += head_prev;
 	    }
-	    if (vcol >= numberextra && numberextra > 0)
-		vcol = vcol % numberextra;
-	    else if (vcol > 0 && numberextra > 0)
-		vcol += numberwidth - win_col_off2(wp);
 
-	    numberwidth -= win_col_off2(wp);
-	}
-	if (vcol == 0 || vcol + size + sbrlen > (colnr_T)wp->w_width)
-	{
-	    added = 0;
+	    // cells taken by 'showbreak'/'breakindent' halfway current char
+	    int	head_mid = 0;
 	    if (*sbr != NUL)
+		head_mid += vim_strsize(sbr);
+	    if (wp->w_p_bri)
+		head_mid += get_breakindent_win(wp, line);
+	    if (head_mid > 0)
 	    {
-		if (size + sbrlen + numberwidth > (colnr_T)wp->w_width)
+		if (wcol + size > wp->w_width)
 		{
 		    // calculate effective window width
-		    int width = (colnr_T)wp->w_width - sbrlen - numberwidth;
-		    int prev_width = vcol
-			       ? ((colnr_T)wp->w_width - (sbrlen + vcol)) : 0;
+		    int prev_rem = wp->w_width - wcol;
+		    int width = width2 - head_mid;
 
 		    if (width <= 0)
-			width = (colnr_T)1;
-		    added += ((size - prev_width) / width) * vim_strsize(sbr);
-		    if ((size - prev_width) % width)
-			// wrapped, add another length of 'sbr'
-			added += vim_strsize(sbr);
+			width = 1;
+		    // divide "size - prev_width" by "width", rounding up
+		    int cnt = (size - prev_rem + width - 1) / width;
+		    added += cnt * head_mid;
+
+		    if (max_head_vcol == 0
+					|| vcol + size + added < max_head_vcol)
+			head += cnt * head_mid;
+		    else if (max_head_vcol > vcol + head_prev + prev_rem)
+			head += (max_head_vcol - (vcol + head_prev + prev_rem)
+					     + width2 - 1) / width2 * head_mid;
+#ifdef FEAT_PROP_POPUP
+		    else if (max_head_vcol < 0)
+		    {
+			int off = 0;
+			if ((State & MODE_NORMAL) || cts->cts_start_incl)
+			    off += cts->cts_cur_text_width;
+			if (off >= prev_rem)
+			    head += (1 + (off - prev_rem) / width) * head_mid;
+		    }
+#endif
 		}
-		else
-		    added += vim_strsize(sbr);
 	    }
-	    if (wp->w_p_bri)
-		added += get_breakindent_win(wp, line);
 
 	    size += added;
-	    if (vcol != 0)
-		added = 0;
 	}
     }
     if (headp != NULL)
-	*headp = added + mb_added;
+	*headp = head;
     return size;
 # endif
 #endif
@@ -1483,6 +1507,7 @@ getvcol(
     }
 
     init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line);
+    cts.cts_max_head_vcol = -1;
 
     /*
      * This function is used very often, do some speed optimizations.
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -1110,14 +1110,10 @@ win_line(
     int		n_attr3 = 0;	    // chars with overruling special attr
     int		saved_attr3 = 0;    // char_attr saved for n_attr3
 
-    int		n_skip = 0;		// nr of cells to skip for 'nowrap' or
-					// concealing
-#ifdef FEAT_PROP_POPUP
-    int		skip_cells = 0;		// nr of cells to skip for virtual text
-					// after the line, when w_skipcol is
-					// larger than the text length
-#endif
-
+    int		skip_cells = 0;		// nr of cells to skip for w_leftcol or
+					// w_skipcol or concealing
+    int		skipped_cells = 0;	// nr of skipped cells for virtual text
+					// to be added to wlv.vcol later
     int		fromcol_prev = -2;	// start of inverting after cursor
     int		noinvcur = FALSE;	// don't invert the cursor
     int		lnum_in_visual_area = FALSE;
@@ -1665,11 +1661,14 @@ win_line(
 	char_u		*prev_ptr = ptr;
 	chartabsize_T	cts;
 	int		charsize = 0;
+	int		head = 0;
 
 	init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr);
+	cts.cts_max_head_vcol = v;
 	while (cts.cts_vcol < v && *cts.cts_ptr != NUL)
 	{
-	    charsize = win_lbr_chartabsize(&cts, NULL);
+	    head = 0;
+	    charsize = win_lbr_chartabsize(&cts, &head);
 	    cts.cts_vcol += charsize;
 	    prev_ptr = cts.cts_ptr;
 	    MB_PTR_ADV(cts.cts_ptr);
@@ -1698,20 +1697,9 @@ win_line(
 	{
 	    wlv.vcol -= charsize;
 	    ptr = prev_ptr;
-	    // If the character fits on the screen, don't need to skip it.
-	    // Except for a TAB.
-	    if (((*mb_ptr2cells)(ptr) >= charsize || *ptr == TAB)
-							       && wlv.col == 0)
-	       n_skip = v - wlv.vcol;
 	}
-
-#ifdef FEAT_PROP_POPUP
-	// If there the text doesn't reach to the desired column, need to skip
-	// "skip_cells" cells when virtual text follows.
-	if ((!wp->w_p_wrap || (lnum == wp->w_topline && wp->w_skipcol > 0))
-							       && v > wlv.vcol)
-	    skip_cells = v - wlv.vcol;
-#endif
+	if (v > wlv.vcol)
+	    skip_cells = v - wlv.vcol - head;
 
 	// Adjust for when the inverted text is before the screen,
 	// and when the start of the inverted text is before the screen.
@@ -2205,6 +2193,7 @@ win_line(
 				wlv.n_attr_skip -= skip_cells;
 				if (wlv.n_attr_skip < 0)
 				    wlv.n_attr_skip = 0;
+				skipped_cells += skip_cells;
 				skip_cells = 0;
 			    }
 			    else
@@ -2212,6 +2201,7 @@ win_line(
 				// the whole text is left of the window, drop
 				// it and advance to the next one
 				skip_cells -= wlv.n_extra;
+				skipped_cells += wlv.n_extra;
 				wlv.n_extra = 0;
 				wlv.n_attr_skip = 0;
 				bail_out = TRUE;
@@ -2592,11 +2582,15 @@ win_line(
 #ifdef FEAT_LINEBREAK
 	    c0 = *ptr;
 #endif
+	    if (c == NUL)
+	    {
 #ifdef FEAT_PROP_POPUP
-	    if (c == NUL)
 		// text is finished, may display a "below" virtual text
 		did_line = TRUE;
 #endif
+		// no more cells to skip
+		skip_cells = 0;
+	    }
 
 	    if (has_mbyte)
 	    {
@@ -2762,7 +2756,7 @@ win_line(
 		// If a double-width char doesn't fit at the left side display
 		// a '<' in the first column.  Don't do this for unprintable
 		// characters.
-		if (n_skip > 0 && mb_l > 1 && wlv.n_extra == 0)
+		if (skip_cells > 0 && mb_l > 1 && wlv.n_extra == 0)
 		{
 		    wlv.n_extra = 1;
 		    wlv.c_extra = MB_FILLER_CHAR;
@@ -3438,10 +3432,10 @@ win_line(
 		    wlv.n_extra = 0;
 		    n_attr = 0;
 		}
-		else if (n_skip == 0)
+		else if (skip_cells == 0)
 		{
 		    is_concealing = TRUE;
-		    n_skip = 1;
+		    skip_cells = 1;
 		}
 		mb_c = c;
 		if (enc_utf8 && utf_char2len(c) > 1)
@@ -3459,7 +3453,7 @@ win_line(
 		is_concealing = FALSE;
 	    }
 
-	    if (n_skip > 0 && did_decrement_ptr)
+	    if (skip_cells > 0 && did_decrement_ptr)
 		// not showing the '>', put pointer back to avoid getting stuck
 		++ptr;
 
@@ -3472,7 +3466,7 @@ win_line(
 	if (!did_wcol && wlv.draw_state == WL_LINE
 		&& wp == curwin && lnum == wp->w_cursor.lnum
 		&& conceal_cursor_line(wp)
-		&& (int)wp->w_virtcol <= wlv.vcol + n_skip)
+		&& (int)wp->w_virtcol <= wlv.vcol + skip_cells)
 	{
 # ifdef FEAT_RIGHTLEFT
 	    if (wp->w_p_rl)
@@ -3797,7 +3791,7 @@ win_line(
 
 	// Store character to be displayed.
 	// Skip characters that are left of the screen for 'nowrap'.
-	if (wlv.draw_state < WL_LINE || n_skip <= 0)
+	if (wlv.draw_state < WL_LINE || skip_cells <= 0)
 	{
 	    // Store the character.
 #if defined(FEAT_RIGHTLEFT)
@@ -3893,7 +3887,7 @@ win_line(
 #ifdef FEAT_CONCEAL
 	else if (wp->w_p_cole > 0 && is_concealing)
 	{
-	    --n_skip;
+	    --skip_cells;
 	    ++wlv.vcol_off_co;
 	    if (wlv.n_extra > 0)
 		wlv.vcol_off_co += wlv.n_extra;
@@ -3973,7 +3967,13 @@ win_line(
 	}
 #endif // FEAT_CONCEAL
 	else
-	    --n_skip;
+	    --skip_cells;
+
+	if (wlv.draw_state > WL_NR && skipped_cells > 0)
+	{
+	    wlv.vcol += skipped_cells;
+	    skipped_cells = 0;
+	}
 
 	// Only advance the "wlv.vcol" when after the 'number' or
 	// 'relativenumber' column.
--- a/src/edit.c
+++ b/src/edit.c
@@ -3705,8 +3705,13 @@ ins_esc(
 
     State = MODE_NORMAL;
     may_trigger_modechanged();
-    // need to position cursor again when on a TAB
-    if (gchar_cursor() == TAB)
+    // need to position cursor again when on a TAB and when on a char with
+    // virtual text.
+    if (gchar_cursor() == TAB
+#ifdef FEAT_PROP_POPUP
+	    || curbuf->b_has_textprop
+#endif
+       )
 	curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
 
     setmouse();
--- a/src/structs.h
+++ b/src/structs.h
@@ -4816,21 +4816,22 @@ typedef struct {
 // Argument for lbr_chartabsize().
 typedef struct {
     win_T	*cts_win;
-    char_u	*cts_line;	    // start of the line
-    char_u	*cts_ptr;	    // current position in line
+    char_u	*cts_line;		// start of the line
+    char_u	*cts_ptr;		// current position in line
 #ifdef FEAT_PROP_POPUP
     int		cts_text_prop_count;	// number of text props; when zero
 					// cts_text_props is not used
     textprop_T	*cts_text_props;	// text props (allocated)
-    char	cts_has_prop_with_text; // TRUE if a property inserts text
-    int		cts_cur_text_width;     // width of current inserted text
+    char	cts_has_prop_with_text;	// TRUE if a property inserts text
+    int		cts_cur_text_width;	// width of current inserted text
     int		cts_prop_lines;		// nr of properties above or below
     int		cts_first_char;		// width text props above the line
     int		cts_with_trailing;	// include size of trailing props with
 					// last character
     int		cts_start_incl;		// prop has true "start_incl" arg
 #endif
-    int		cts_vcol;	    // virtual column at current position
+    int		cts_vcol;		// virtual column at current position
+    int		cts_max_head_vcol;	// see win_lbr_chartabsize()
 } chartabsize_T;
 
 /*
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_1.dump
@@ -0,0 +1,6 @@
+|<+0#0000e05#ffffff0|-@5|>|<|-@5|>|<|-@5|>|1+0#e000e06&|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|<+0#0000e05&|-
+@5|>>a+0#0000000&| @22
+|~+0#4040ff13&| @28
+| +0#0000000&@14|1|,|5|-|9|7| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_10.dump
@@ -0,0 +1,6 @@
+|<+0#4040ff13#ffffff0@2|2+0#e000e06&|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2| +0#0000000&@1
+@5> |a| @22
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+| +0#0000000&@14|1|,|4|-|9|6| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_11.dump
@@ -0,0 +1,6 @@
+|<+0#4040ff13#ffffff0@2| +0#e000e06&@1> |a+0#0000000&| @22
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+|~| @28
+| +0#0000000&@14|1|,|4|-|9|6| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_2.dump
@@ -0,0 +1,6 @@
+|<+0#4040ff13#ffffff0@2|2+0#e000e06&|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|<+0#0000e05&|-
+@5|>>a+0#0000000&| @22
+|~+0#4040ff13&| @28
+|~| @28
+| +0#0000000&@14|1|,|5|-|9|7| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_3.dump
@@ -0,0 +1,6 @@
+|<+0#4040ff13#ffffff0@2|2+0#e000e06&|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|<+0#0000e05&|-
+@5|>>a+0#0000000&| @22
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+| +0#0000000&@14|1|,|5|-|9|7| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_4.dump
@@ -0,0 +1,6 @@
+|<+0#4040ff13#ffffff0@2|-+0#0000e05&@1|>>a+0#0000000&| @22
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+|~| @28
+| +0#0000000&@14|1|,|5|-|9|7| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_5.dump
@@ -0,0 +1,6 @@
+|<+0#0000e05#ffffff0|-@5|>|<|-@5|>|<|-@5|>|1+0#e000e06&|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2><+0#0000e05&|-
+@5|>|a+0#0000000&| @22
+|~+0#4040ff13&| @28
+| +0#0000000&@14|1|,|4|-|8|9| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_6.dump
@@ -0,0 +1,6 @@
+|<+0#0000e05#ffffff0|-@5|>|<|-@5|>|<|-@5|>>1+0#e000e06&|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|<+0#0000e05&|-
+@5|>|a+0#0000000&| @22
+|~+0#4040ff13&| @28
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@2|1|,|4|-|2|5| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_7.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@23>1+0#e000e06&|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2| +0#0000000&@1
+@6|a| @22
+|~+0#4040ff13&| @28
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@2|1|,|4|-|2|5| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_8.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@23|1+0#e000e06&|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2| +0#0000000&@1
+@5> |a| @22
+|~+0#4040ff13&| @28
+| +0#0000000&@14|1|,|4|-|9|6| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_before_tab_skipcol_9.dump
@@ -0,0 +1,6 @@
+|<+0#4040ff13#ffffff0@2|2+0#e000e06&|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2
+|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2|1|2| +0#0000000&@1
+@5> |a| @22
+|~+0#4040ff13&| @28
+|~| @28
+| +0#0000000&@14|1|,|4|-|9|6| @4|A|l@1| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_1.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| |a@25
+| @5|++0#4040ff13&|a+0#0000000&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&>a+0#0000000&| @20
+|:|s|e|t| |n|o|r|u|l|e|r| @17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_10.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&>a+0#0000000&| @21
+|~+0#4040ff13&| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_11.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&>a+0#0000000&| @21
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_12.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&>a+0#e000e06&| +0#0000000&@21
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_13.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| |a@2|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&>a+0#0000000&| @21
+|~+0#4040ff13&| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_14.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&>a+0#0000000&| @21
+|~+0#4040ff13&| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_15.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&>a+0#0000000&| @21
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_16.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&>a+0#e000e06&| +0#0000000&@21
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_17.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| |a@2>1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&|a+0#0000000&| @21
+|~+0#4040ff13&| @28
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_18.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| >1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|a+0#0000000&| @1
+|~+0#4040ff13&| @28
+|~| @28
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_19.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| |1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3>a+0#0000000&| @1
+|~+0#4040ff13&| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_2.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|a+0#0000000&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&>a+0#0000000&| @20
+|~+0#4040ff13&| @28
+|:+0#0000000&|s|e|t| |n|o|r|u|l|e|r| @17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_20.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3>a+0#0000000&| @1
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_21.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3>a+0#0000000&| @1
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+|~| @28
+| +0#0000000&@29
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_3.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&>a+0#0000000&| @20
+|~+0#4040ff13&| @28
+|~| @28
+|:+0#0000000&|s|e|t| |n|o|r|u|l|e|r| @17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_4.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&>a+0#0000000&| @20
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+|:+0#0000000&|s|e|t| |n|o|r|u|l|e|r| @17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_5.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|3+0#e000e06&>a+0#0000000&| @20
+|~+0#4040ff13&| @28
+|~| @28
+|~| @28
+|~| @28
+|:+0#0000000&|s|e|t| |n|o|r|u|l|e|r| @17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_6.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| |a@25
+| @5|++0#4040ff13&|a+0#0000000&>1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|a+0#0000000&| @20
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_7.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| |a@25
+| @5|++0#4040ff13&>1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&|a+0#0000000&| @21
+|-+2&&@1| |I|N|S|E|R|T| |-@1| +0&&@17
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_8.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@1|1| |a@25
+| @5|++0#4040ff13&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&>a+0#0000000&| @21
+@30
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_showbreak_9.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@5|++0#4040ff13&|1+0#e000e06&|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2
+| +0#0000000&@5|++0#4040ff13&|3+0#e000e06&|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1
+| +0#0000000&@5|++0#4040ff13&|2+0#e000e06&|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3
+| +0#0000000&@5|++0#4040ff13&>a+0#0000000&| @21
+|~+0#4040ff13&| @28
+| +0#0000000&@29
--- a/src/testdir/test_listlbr.vim
+++ b/src/testdir/test_listlbr.vim
@@ -15,7 +15,7 @@ function s:screen_lines(lnum, width) abo
 endfunction
 
 func s:compare_lines(expect, actual)
-  call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
+  call assert_equal(a:expect, a:actual)
 endfunc
 
 function s:test_windows(...)
@@ -331,4 +331,45 @@ func Test_list_with_tab_and_skipping_fir
   call s:close_windows()
 endfunc
 
+func Test_ctrl_char_on_wrap_column()
+  call s:test_windows("setl nolbr wrap sbr=")
+  call setline(1, 'aaa' .. repeat("\<C-A>", 150) .. 'bbb')
+  call cursor(1,1)
+  norm! $
+  redraw!
+  let expect=[
+\ '<<<^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^A^A^A^A^A^A^A^A^A^',
+\ 'A^Abbb              ']
+  let lines = s:screen_lines([1, 10], winwidth(0))
+  call s:compare_lines(expect, lines)
+  call assert_equal(len(expect), winline())
+  call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
+  setl sbr=!!
+  redraw!
+  let expect=[
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^A^A^A^',
+\ '!!A^A^A^A^A^A^Abbb  ']
+  let lines = s:screen_lines([1, 10], winwidth(0))
+  call s:compare_lines(expect, lines)
+  call assert_equal(len(expect), winline())
+  call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
+  call s:close_windows()
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/testdir/test_listlbr_utf8.vim
+++ b/src/testdir/test_listlbr_utf8.vim
@@ -249,7 +249,6 @@ endfunc
 
 func Test_chinese_char_on_wrap_column()
   call s:test_windows("setl nolbr wrap sbr=")
-  syntax off
   call setline(1, [
 \ 'aaaaaaaaaaaaaaaaaaa中'.
 \ 'aaaaaaaaaaaaaaaaa中'.
@@ -278,6 +277,84 @@ func Test_chinese_char_on_wrap_column()
 \ '中hello             ']
   let lines = s:screen_lines([1, 10], winwidth(0))
   call s:compare_lines(expect, lines)
+  call assert_equal(len(expect), winline())
+  call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
+  call s:close_windows()
+endfunc
+
+func Test_chinese_char_on_wrap_column_sbr()
+  call s:test_windows("setl nolbr wrap sbr=!!!")
+  call setline(1, [
+\ 'aaaaaaaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'aaaaaaaaaaaaaa中'.
+\ 'hello'])
+  call cursor(1,1)
+  norm! $
+  redraw!
+  let expect=[
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中aaaaaaaaaaaaaa>',
+\ '!!!中hello          ']
+  let lines = s:screen_lines([1, 10], winwidth(0))
+  call s:compare_lines(expect, lines)
+  call assert_equal(len(expect), winline())
+  call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
+  call s:close_windows()
+endfunc
+
+func Test_unprintable_char_on_wrap_column()
+  call s:test_windows("setl nolbr wrap sbr=")
+  call setline(1, 'aaa' .. repeat("\uFEFF", 50) .. 'bbb')
+  call cursor(1,1)
+  norm! $
+  redraw!
+  let expect=[
+\ '<<<<feff><feff><feff',
+\ '><feff><feff><feff><',
+\ 'feff><feff><feff><fe',
+\ 'ff><feff><feff><feff',
+\ '><feff><feff><feff><',
+\ 'feff><feff><feff><fe',
+\ 'ff><feff><feff><feff',
+\ '><feff><feff><feff><',
+\ 'feff><feff><feff><fe',
+\ 'ff>bbb              ']
+  let lines = s:screen_lines([1, 10], winwidth(0))
+  call s:compare_lines(expect, lines)
+  call assert_equal(len(expect), winline())
+  call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
+  setl sbr=!!
+  redraw!
+  let expect=[
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff><feff',
+\ '!!><feff><feff>bbb  ']
+  let lines = s:screen_lines([1, 10], winwidth(0))
+  call s:compare_lines(expect, lines)
+  call assert_equal(len(expect), winline())
+  call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
   call s:close_windows()
 endfunc
 
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -2630,6 +2630,110 @@ func Test_prop_inserts_text_visual_block
   call StopVimInTerminal(buf)
 endfunc
 
+func Run_test_prop_inserts_text_showbreak(cmd)
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+    highlight! link LineNr Normal
+    call setline(1, repeat('a', 28))
+    call prop_type_add('theprop', #{highlight: 'Special'})
+    call prop_add(1, 28, #{type: 'theprop', text: repeat('123', 23), text_wrap: 'wrap'})
+    setlocal number showbreak=+ breakindent breakindentopt=shift:2
+    setlocal scrolloff=0 smoothscroll
+    normal! $
+  END
+  let lines = insert(lines, a:cmd)
+  call writefile(lines, 'XscriptPropsShowbreak', 'D')
+  let buf = RunVimInTerminal('-S XscriptPropsShowbreak', #{rows: 6, cols: 30})
+  call term_sendkeys(buf, ":set noruler\<CR>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_1', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_2', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_3', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_4', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_5', {})
+  call term_sendkeys(buf, "zbi")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_6', {})
+  call term_sendkeys(buf, "\<BS>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_7', {})
+  call term_sendkeys(buf, "\<Esc>l")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_8', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_9', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_10', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_11', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_12', {})
+  call term_sendkeys(buf, "023x$")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_13', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_14', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_15', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_16', {})
+  call term_sendkeys(buf, "zbi")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_17', {})
+  call term_sendkeys(buf, "\<C-U>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_18', {})
+  call term_sendkeys(buf, "\<Esc>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_19', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_20', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_inserts_text_showbreak_21', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+func Test_prop_inserts_text_showbreak()
+  call Run_test_prop_inserts_text_showbreak('')
+  " because of 'breakindent' the screendumps are the same
+  call Run_test_prop_inserts_text_showbreak('set cpoptions+=n')
+endfunc
+
+func Test_prop_before_tab_skipcol()
+  CheckRunVimInTerminal
+
+  let lines =<< trim END
+    call setline(1, repeat("\t", 4) .. 'a')
+    call prop_type_add('theprop', #{highlight: 'Special'})
+    call prop_add(1, 4, #{type: 'theprop', text: repeat('12', 32), text_wrap: 'wrap'})
+    setlocal list listchars=tab:<-> scrolloff=0 smoothscroll
+    normal! $
+  END
+  call writefile(lines, 'XscriptPropsBeforeTabSkipcol', 'D')
+  let buf = RunVimInTerminal('-S XscriptPropsBeforeTabSkipcol', #{rows: 6, cols: 30})
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_1', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_2', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_3', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_4', {})
+  call term_sendkeys(buf, "zbh")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_5', {})
+  call term_sendkeys(buf, "i")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_6', {})
+  call term_sendkeys(buf, "\<C-O>:setlocal nolist\<CR>")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_7', {})
+  call term_sendkeys(buf, "\<Esc>l")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_8', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_9', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_10', {})
+  call term_sendkeys(buf, "\<C-E>")
+  call VerifyScreenDump(buf, 'Test_prop_before_tab_skipcol_11', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
 func Test_prop_add_with_text_fails()
   call prop_type_add('failing', #{highlight: 'ErrorMsg'})
   call assert_fails("call prop_add(1, 0, #{type: 'failing', text: 'X', end_lnum: 1})", 'E1305:')
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1783,
+/**/
     1782,
 /**/
     1781,