changeset 15502:bc17a9d37810 v8.1.0759

patch 8.1.0759: showing two characters for tab is limited commit https://github.com/vim/vim/commit/83a52171ba00b2b9fd2d1d22a07e38fc9fc69c1e Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jan 16 22:41:54 2019 +0100 patch 8.1.0759: showing two characters for tab is limited Problem: Showing two characters for tab is limited. Solution: Allow for a third character for "tab:" in 'listchars'. (Nathaniel Braun, Ken Takata, closes #3810)
author Bram Moolenaar <Bram@vim.org>
date Wed, 16 Jan 2019 22:45:07 +0100
parents f1ba08812cf2
children 65eb414db805
files runtime/doc/options.txt src/globals.h src/message.c src/option.c src/screen.c src/testdir/test_listchars.vim src/version.c
diffstat 7 files changed, 119 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5063,11 +5063,26 @@ A jump table for the options with a shor
 			omitted, there is no extra character at the end of the
 			line.
 							*lcs-tab*
-	  tab:xy	Two characters to be used to show a tab.  The first
-			char is used once.  The second char is repeated to
-			fill the space that the tab normally occupies.
-			"tab:>-" will show a tab that takes four spaces as
-			">---".  When omitted, a tab is show as ^I.
+	  tab:xy[z]	Two or three characters to be used to show a tab.
+			The third character is optional.
+
+	  tab:xy	The 'x' is always used, then 'y' as many times as will
+			fit.  Thus "tab:>-" displays:
+				>
+				>-
+				>--
+				etc.
+
+	  tab:xyz	The 'z' is always used, then 'x' is prepended, and
+			then 'y' is used as many times as will fit.  Thus
+			"tab:<->" displays:
+				>
+				<>
+				<->
+				<-->
+				etc.
+
+			When "tab:" is omitted, a tab is shown as ^I.
 							*lcs-space*
 	  space:c	Character to show for a space.  When omitted, spaces
 			are left blank.
--- a/src/globals.h
+++ b/src/globals.h
@@ -1163,6 +1163,7 @@ EXTERN int	lcs_nbsp INIT(= NUL);
 EXTERN int	lcs_space INIT(= NUL);
 EXTERN int	lcs_tab1 INIT(= NUL);
 EXTERN int	lcs_tab2 INIT(= NUL);
+EXTERN int	lcs_tab3 INIT(= NUL);
 EXTERN int	lcs_trail INIT(= NUL);
 #ifdef FEAT_CONCEAL
 EXTERN int	lcs_conceal INIT(= ' ');
--- a/src/message.c
+++ b/src/message.c
@@ -1771,6 +1771,7 @@ msg_prt_line(char_u *s, int list)
     int		col = 0;
     int		n_extra = 0;
     int		c_extra = 0;
+    int		c_final = 0;
     char_u	*p_extra = NULL;	    /* init to make SASC shut up */
     int		n;
     int		attr = 0;
@@ -1801,7 +1802,9 @@ msg_prt_line(char_u *s, int list)
 	if (n_extra > 0)
 	{
 	    --n_extra;
-	    if (c_extra)
+	    if (n_extra == 0 && c_final)
+		c = c_final;
+	    else if (c_extra)
 		c = c_extra;
 	    else
 		c = *p_extra++;
@@ -1844,11 +1847,13 @@ msg_prt_line(char_u *s, int list)
 		{
 		    c = ' ';
 		    c_extra = ' ';
+		    c_final = NUL;
 		}
 		else
 		{
-		    c = lcs_tab1;
+		    c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
 		    c_extra = lcs_tab2;
+		    c_final = lcs_tab3;
 		    attr = HL_ATTR(HLF_8);
 		}
 	    }
@@ -1861,6 +1866,7 @@ msg_prt_line(char_u *s, int list)
 	    {
 		p_extra = (char_u *)"";
 		c_extra = NUL;
+		c_final = NUL;
 		n_extra = 1;
 		c = lcs_eol;
 		attr = HL_ATTR(HLF_AT);
@@ -1871,6 +1877,7 @@ msg_prt_line(char_u *s, int list)
 		n_extra = n - 1;
 		p_extra = transchar_byte(c);
 		c_extra = NUL;
+		c_final = NUL;
 		c = *p_extra++;
 		/* Use special coloring to be able to distinguish <hex> from
 		 * the same in plain text. */
--- a/src/option.c
+++ b/src/option.c
@@ -7949,7 +7949,7 @@ set_chars_option(char_u **varp)
 {
     int		round, i, len, entries;
     char_u	*p, *s;
-    int		c1, c2 = 0;
+    int		c1 = 0, c2 = 0, c3 = 0;
     struct charstab
     {
 	int	*cp;
@@ -8001,8 +8001,12 @@ set_chars_option(char_u **varp)
 	    for (i = 0; i < entries; ++i)
 		if (tab[i].cp != NULL)
 		    *(tab[i].cp) = (varp == &p_lcs ? NUL : ' ');
+
 	    if (varp == &p_lcs)
+	    {
 		lcs_tab1 = NUL;
+		lcs_tab3 = NUL;
+	    }
 	    else
 		fill_diff = '-';
 	}
@@ -8016,6 +8020,7 @@ set_chars_option(char_u **varp)
 			&& p[len] == ':'
 			&& p[len + 1] != NUL)
 		{
+		    c1 = c2 = c3 = 0;
 		    s = p + len + 1;
 #ifdef FEAT_MBYTE
 		    c1 = mb_ptr2char_adv(&s);
@@ -8035,7 +8040,18 @@ set_chars_option(char_u **varp)
 #else
 			c2 = *s++;
 #endif
+			if (!(*s == ',' || *s == NUL))
+			{
+#ifdef FEAT_MBYTE
+			    c3 = mb_ptr2char_adv(&s);
+			    if (mb_char2cells(c3) > 1)
+				continue;
+#else
+			    c3 = *s++;
+#endif
+			}
 		    }
+
 		    if (*s == ',' || *s == NUL)
 		    {
 			if (round)
@@ -8044,6 +8060,7 @@ set_chars_option(char_u **varp)
 			    {
 				lcs_tab1 = c1;
 				lcs_tab2 = c2;
+				lcs_tab3 = c3;
 			    }
 			    else if (tab[i].cp != NULL)
 				*(tab[i].cp) = c1;
--- a/src/screen.c
+++ b/src/screen.c
@@ -3049,6 +3049,7 @@ win_line(
     char_u	*p_extra = NULL;	/* string of extra chars, plus NUL */
     char_u	*p_extra_free = NULL;   /* p_extra needs to be freed */
     int		c_extra = NUL;		/* extra chars, all the same */
+    int		c_final = NUL;		/* final char, mandatory if set */
     int		extra_attr = 0;		/* attributes when n_extra != 0 */
     static char_u *at_end_str = (char_u *)""; /* used for p_extra when
 					   displaying lcs_eol at end-of-line */
@@ -3059,6 +3060,7 @@ win_line(
     int		saved_n_extra = 0;
     char_u	*saved_p_extra = NULL;
     int		saved_c_extra = 0;
+    int		saved_c_final = 0;
     int		saved_char_attr = 0;
 
     int		n_attr = 0;		/* chars with special attr */
@@ -3814,6 +3816,7 @@ win_line(
 		    /* Draw the cmdline character. */
 		    n_extra = 1;
 		    c_extra = cmdwin_type;
+		    c_final = NUL;
 		    char_attr = HL_ATTR(HLF_AT);
 		}
 	    }
@@ -3839,6 +3842,7 @@ win_line(
 			p_extra_free[n_extra] = NUL;
 			p_extra = p_extra_free;
 			c_extra = NUL;
+			c_final = NUL;
 			char_attr = HL_ATTR(HLF_FC);
 		    }
 		}
@@ -3860,6 +3864,7 @@ win_line(
 
 		    /* Draw two cells with the sign value or blank. */
 		    c_extra = ' ';
+		    c_final = NUL;
 		    char_attr = HL_ATTR(HLF_SC);
 		    n_extra = 2;
 
@@ -3878,9 +3883,13 @@ win_line(
 			{
 			    /* Use the image in this position. */
 			    c_extra = SIGN_BYTE;
+			    c_final = NUL;
 #  ifdef FEAT_NETBEANS_INTG
 			    if (buf_signcount(wp->w_buffer, lnum) > 1)
+			    {
 				c_extra = MULTISIGN_BYTE;
+				c_final = NUL;
+			    }
 #  endif
 			    char_attr = icon_sign;
 			}
@@ -3892,6 +3901,7 @@ win_line(
 			    if (p_extra != NULL)
 			    {
 				c_extra = NUL;
+				c_final = NUL;
 				n_extra = (int)STRLEN(p_extra);
 			    }
 			    char_attr = sign_get_attr(text_sign, FALSE);
@@ -3949,9 +3959,13 @@ win_line(
 #endif
 			p_extra = extra;
 			c_extra = NUL;
+			c_final = NUL;
 		    }
 		    else
+		    {
 			c_extra = ' ';
+			c_final = NUL;
+		    }
 		    n_extra = number_width(wp) + 1;
 		    char_attr = HL_ATTR(HLF_N);
 #ifdef FEAT_SYN_HL
@@ -4020,9 +4034,15 @@ win_line(
 		{
 		    /* Draw "deleted" diff line(s). */
 		    if (char2cells(fill_diff) > 1)
+		    {
 			c_extra = '-';
+			c_final = NUL;
+		    }
 		    else
+		    {
 			c_extra = fill_diff;
+			c_final = NUL;
+		    }
 #  ifdef FEAT_RIGHTLEFT
 		    if (wp->w_p_rl)
 			n_extra = col + 1;
@@ -4038,6 +4058,7 @@ win_line(
 		    /* Draw 'showbreak' at the start of each broken line. */
 		    p_extra = p_sbr;
 		    c_extra = NUL;
+		    c_final = NUL;
 		    n_extra = (int)STRLEN(p_sbr);
 		    char_attr = HL_ATTR(HLF_AT);
 		    need_showbreak = FALSE;
@@ -4065,6 +4086,7 @@ win_line(
 		    /* Continue item from end of wrapped line. */
 		    n_extra = saved_n_extra;
 		    c_extra = saved_c_extra;
+		    c_final = saved_c_final;
 		    p_extra = saved_p_extra;
 		    char_attr = saved_char_attr;
 		}
@@ -4364,15 +4386,16 @@ win_line(
 	 * The "p_extra" points to the extra stuff that is inserted to
 	 * represent special characters (non-printable stuff) and other
 	 * things.  When all characters are the same, c_extra is used.
+	 * If c_final is set, it will compulsorily be used at the end.
 	 * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past
 	 * "p_extra[n_extra]".
 	 * For the '$' of the 'list' option, n_extra == 1, p_extra == "".
 	 */
 	if (n_extra > 0)
 	{
-	    if (c_extra != NUL)
-	    {
-		c = c_extra;
+	    if (c_extra != NUL || (n_extra == 1 && c_final != NUL))
+	    {
+		c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra;
 #ifdef FEAT_MBYTE
 		mb_c = c;	/* doesn't handle non-utf-8 multi-byte! */
 		if (enc_utf8 && utf_char2len(c) > 1)
@@ -4537,6 +4560,7 @@ win_line(
 			mb_utf8 = (c >= 0x80);
 			n_extra = (int)STRLEN(p_extra);
 			c_extra = NUL;
+			c_final = NUL;
 			if (area_attr == 0 && search_attr == 0)
 			{
 			    n_attr = n_extra + 1;
@@ -4605,6 +4629,7 @@ win_line(
 			    p_extra = extra;
 			    n_extra = (int)STRLEN(extra) - 1;
 			    c_extra = NUL;
+			    c_final = NUL;
 			    c = *p_extra++;
 			    if (area_attr == 0 && search_attr == 0)
 			    {
@@ -4645,6 +4670,7 @@ win_line(
 		{
 		    n_extra = 1;
 		    c_extra = MB_FILLER_CHAR;
+		    c_final = NUL;
 		    c = ' ';
 		    if (area_attr == 0 && search_attr == 0)
 		    {
@@ -4856,6 +4882,7 @@ win_line(
 # else
 		    c_extra = ' ';
 # endif
+		    c_final = NUL;
 		    if (VIM_ISWHITE(c))
 		    {
 #ifdef FEAT_CONCEAL
@@ -5040,13 +5067,14 @@ win_line(
 #endif
 		    if (wp->w_p_list)
 		    {
-			c = lcs_tab1;
+			c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1;
 #ifdef FEAT_LINEBREAK
 			if (wp->w_p_lbr)
 			    c_extra = NUL; /* using p_extra from above */
 			else
 #endif
 			    c_extra = lcs_tab2;
+			c_final = lcs_tab3;
 			n_attr = tab_len + 1;
 			extra_attr = HL_ATTR(HLF_8);
 			saved_attr2 = char_attr; /* save current attr */
@@ -5062,6 +5090,7 @@ win_line(
 		    }
 		    else
 		    {
+			c_final = NUL;
 			c_extra = ' ';
 			c = ' ';
 		    }
@@ -5111,6 +5140,7 @@ win_line(
 			    p_extra = at_end_str;
 			    n_extra = 1;
 			    c_extra = NUL;
+			    c_final = NUL;
 			}
 		    }
 		    if (wp->w_p_list && lcs_eol > 0)
@@ -5146,6 +5176,7 @@ win_line(
 			rl_mirror(p_extra);	/* reverse "<12>" */
 #endif
 		    c_extra = NUL;
+		    c_final = NUL;
 #ifdef FEAT_LINEBREAK
 		    if (wp->w_p_lbr)
 		    {
@@ -5407,6 +5438,7 @@ win_line(
 		/* Double-width character being overwritten by the "precedes"
 		 * character, need to fill up half the character. */
 		c_extra = MB_FILLER_CHAR;
+		c_final = NUL;
 		n_extra = 1;
 		n_attr = 2;
 		extra_attr = HL_ATTR(HLF_AT);
@@ -6064,6 +6096,7 @@ win_line(
 	    saved_n_extra = n_extra;
 	    saved_p_extra = p_extra;
 	    saved_c_extra = c_extra;
+	    saved_c_final = c_final;
 	    saved_char_attr = char_attr;
 	    n_extra = 0;
 	    lcs_prec_todo = lcs_prec;
--- a/src/testdir/test_listchars.vim
+++ b/src/testdir/test_listchars.vim
@@ -42,6 +42,38 @@ func Test_listchars()
     call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
   endfor
 
+  " tab with 3rd character.
+  set listchars-=tab:>-
+  set listchars+=tab:<=>,trail:-
+  let expected = [
+	      \ '<======>aa<====>$',
+	      \ '..bb<==>--$',
+	      \ '...cccc>-$',
+	      \ 'dd........ee--<>$',
+	      \ '-$'
+	      \ ]
+  redraw!
+  for i in range(1, 5)
+    call cursor(i, 1)
+    call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+  endfor
+
+  set listchars-=trail:-
+  let expected = [
+	      \ '<======>aa<====>$',
+	      \ '..bb<==>..$',
+	      \ '...cccc>.$',
+	      \ 'dd........ee..<>$',
+	      \ '.$'
+	      \ ]
+  redraw!
+  for i in range(1, 5)
+    call cursor(i, 1)
+    call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+  endfor
+
+  set listchars-=tab:<=>
+  set listchars+=tab:>-
   set listchars+=trail:<
   set nolist
   normal ggdG
--- a/src/version.c
+++ b/src/version.c
@@ -796,6 +796,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    759,
+/**/
     758,
 /**/
     757,