patch 8.2.0863: cannot set a separate color for underline/undercurl

Problem:    Cannot set a separate color for underline/undercurl.
Solution:   Add the t_AU and t_8u termcap codes. (Timur Celik, closes #6011)
diff --git a/src/globals.h b/src/globals.h
index 89aeb96..57577d4 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -485,9 +485,11 @@
 EXTERN int	cterm_normal_fg_color INIT(= 0);
 EXTERN int	cterm_normal_fg_bold INIT(= 0);
 EXTERN int	cterm_normal_bg_color INIT(= 0);
+EXTERN int	cterm_normal_ul_color INIT(= 0);
 #ifdef FEAT_TERMGUICOLORS
 EXTERN guicolor_T cterm_normal_fg_gui_color INIT(= INVALCOLOR);
 EXTERN guicolor_T cterm_normal_bg_gui_color INIT(= INVALCOLOR);
+EXTERN guicolor_T cterm_normal_ul_gui_color INIT(= INVALCOLOR);
 #endif
 #ifdef FEAT_TERMRESPONSE
 EXTERN int	is_mac_terminal INIT(= FALSE);  // recognized Terminal.app
diff --git a/src/highlight.c b/src/highlight.c
index 9da87f2..e446966 100644
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -50,14 +50,15 @@
     int		sg_cterm_bold;	// bold attr was set for light color
     int		sg_cterm_fg;	// terminal fg color number + 1
     int		sg_cterm_bg;	// terminal bg color number + 1
+    int		sg_cterm_ul;	// terminal ul color number + 1
     int		sg_cterm_attr;	// Screen attr for color term mode
 // for when using the GUI
 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
     guicolor_T	sg_gui_fg;	// GUI foreground color handle
     guicolor_T	sg_gui_bg;	// GUI background color handle
+    guicolor_T	sg_gui_sp;	// GUI special color handle
 #endif
 #ifdef FEAT_GUI
-    guicolor_T	sg_gui_sp;	// GUI special color handle
     GuiFont	sg_font;	// GUI font handle
 #ifdef FEAT_XFONTSET
     GuiFontset	sg_fontset;	// GUI fontset handle
@@ -1095,7 +1096,8 @@
 	    }
 #endif
 	}
-	else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0)
+	else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0
+						|| STRCMP(key, "CTERMUL") == 0)
 	{
 	  if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
 	  {
@@ -1134,6 +1136,17 @@
 		    break;
 		}
 	    }
+	    else if (STRICMP(arg, "ul") == 0)
+	    {
+		if (cterm_normal_ul_color > 0)
+		    color = cterm_normal_ul_color - 1;
+		else
+		{
+		    emsg(_("E453: UL color unknown"));
+		    error = TRUE;
+		    break;
+		}
+	    }
 	    else
 	    {
 		int bold = MAYBE;
@@ -1184,7 +1197,7 @@
 		    }
 		}
 	    }
-	    else
+	    else if (key[5] == 'B')
 	    {
 		HL_TABLE()[idx].sg_cterm_bg = color + 1;
 		if (is_normal_group)
@@ -1221,6 +1234,23 @@
 		    }
 		}
 	    }
+	    else // ctermul
+	    {
+		HL_TABLE()[idx].sg_cterm_ul = color + 1;
+		if (is_normal_group)
+		{
+		    cterm_normal_ul_color = color + 1;
+#ifdef FEAT_GUI
+		    // Don't do this if the GUI is used.
+		    if (!gui.in_use && !gui.starting)
+#endif
+		    {
+			must_redraw = CLEAR;
+			if (termcap_active && color >= 0)
+			    term_ul_color(color);
+		    }
+		}
+	    }
 	  }
 	}
 	else if (STRCMP(key, "GUIFG") == 0)
@@ -1335,9 +1365,10 @@
 		if (!init)
 		    HL_TABLE()[idx].sg_set |= SG_GUI;
 
-# ifdef FEAT_GUI
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
+		// In GUI guisp colors are only used when recognized
 		i = color_name2handle(arg);
-		if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !gui.in_use)
+		if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
 		{
 		    HL_TABLE()[idx].sg_gui_sp = i;
 # endif
@@ -1350,7 +1381,7 @@
 			    *namep = NULL;
 			did_change = TRUE;
 		    }
-# ifdef FEAT_GUI
+# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
 		}
 # endif
 	    }
@@ -1587,6 +1618,7 @@
 # ifdef FEAT_TERMGUICOLORS
     cterm_normal_fg_gui_color = INVALCOLOR;
     cterm_normal_bg_gui_color = INVALCOLOR;
+    cterm_normal_ul_gui_color = INVALCOLOR;
 # endif
 #endif
 }
@@ -1638,9 +1670,9 @@
 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
     HL_TABLE()[idx].sg_gui_fg = INVALCOLOR;
     HL_TABLE()[idx].sg_gui_bg = INVALCOLOR;
+    HL_TABLE()[idx].sg_gui_sp = INVALCOLOR;
 #endif
 #ifdef FEAT_GUI
-    HL_TABLE()[idx].sg_gui_sp = INVALCOLOR;
     gui_mch_free_font(HL_TABLE()[idx].sg_font);
     HL_TABLE()[idx].sg_font = NOFONT;
 # ifdef FEAT_XFONTSET
@@ -2098,11 +2130,15 @@
 						  == taep->ae_u.cterm.fg_color
 			    && aep->ae_u.cterm.bg_color
 						  == taep->ae_u.cterm.bg_color
+			    && aep->ae_u.cterm.ul_color
+						  == taep->ae_u.cterm.ul_color
 #ifdef FEAT_TERMGUICOLORS
 			    && aep->ae_u.cterm.fg_rgb
 						    == taep->ae_u.cterm.fg_rgb
 			    && aep->ae_u.cterm.bg_rgb
 						    == taep->ae_u.cterm.bg_rgb
+			    && aep->ae_u.cterm.ul_rgb
+						    == taep->ae_u.cterm.ul_rgb
 #endif
 		       )))
 
@@ -2169,9 +2205,11 @@
     {
 	taep->ae_u.cterm.fg_color = aep->ae_u.cterm.fg_color;
 	taep->ae_u.cterm.bg_color = aep->ae_u.cterm.bg_color;
+	taep->ae_u.cterm.ul_color = aep->ae_u.cterm.ul_color;
 #ifdef FEAT_TERMGUICOLORS
 	taep->ae_u.cterm.fg_rgb = aep->ae_u.cterm.fg_rgb;
 	taep->ae_u.cterm.bg_rgb = aep->ae_u.cterm.bg_rgb;
+	taep->ae_u.cterm.ul_rgb = aep->ae_u.cterm.ul_rgb;
 #endif
     }
     ++table->ga_len;
@@ -2344,6 +2382,7 @@
 #ifdef FEAT_TERMGUICOLORS
 	    new_en.ae_u.cterm.bg_rgb = INVALCOLOR;
 	    new_en.ae_u.cterm.fg_rgb = INVALCOLOR;
+	    new_en.ae_u.cterm.ul_rgb = INVALCOLOR;
 #endif
 	    if (char_attr <= HL_ALL)
 		new_en.ae_attr = char_attr;
@@ -2362,6 +2401,8 @@
 		    new_en.ae_u.cterm.fg_color = spell_aep->ae_u.cterm.fg_color;
 		if (spell_aep->ae_u.cterm.bg_color > 0)
 		    new_en.ae_u.cterm.bg_color = spell_aep->ae_u.cterm.bg_color;
+		if (spell_aep->ae_u.cterm.ul_color > 0)
+		    new_en.ae_u.cterm.ul_color = spell_aep->ae_u.cterm.ul_color;
 #ifdef FEAT_TERMGUICOLORS
 		// If both fg and bg are not set fall back to cterm colors.
 		// Helps for SpellBad which uses undercurl in the GUI.
@@ -2380,6 +2421,8 @@
 		    if (spell_aep->ae_u.cterm.bg_rgb != INVALCOLOR)
 			new_en.ae_u.cterm.bg_rgb = spell_aep->ae_u.cterm.bg_rgb;
 		}
+		if (spell_aep->ae_u.cterm.ul_rgb != INVALCOLOR)
+		    new_en.ae_u.cterm.ul_rgb = spell_aep->ae_u.cterm.ul_rgb;
 #endif
 	    }
 	}
@@ -2497,6 +2540,8 @@
 				    sgp->sg_cterm_fg, NULL, "ctermfg");
     didh = highlight_list_arg(id, didh, LIST_INT,
 				    sgp->sg_cterm_bg, NULL, "ctermbg");
+    didh = highlight_list_arg(id, didh, LIST_INT,
+				    sgp->sg_cterm_ul, NULL, "ctermul");
 
 #if defined(FEAT_GUI) || defined(FEAT_EVAL)
     didh = highlight_list_arg(id, didh, LIST_ATTR,
@@ -2662,11 +2707,7 @@
 	    if (fg)
 		color = HL_TABLE()[id - 1].sg_gui_fg;
 	    else if (sp)
-#  ifdef FEAT_GUI
 		color = HL_TABLE()[id - 1].sg_gui_sp;
-#  else
-		color = INVALCOLOR;
-#  endif
 	    else
 		color = HL_TABLE()[id - 1].sg_gui_bg;
 	    if (color == INVALCOLOR)
@@ -2847,10 +2888,11 @@
      * For the color term mode: If there are other than "normal"
      * highlighting attributes, need to allocate an attr number.
      */
-    if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0
+    if (sgp->sg_cterm_fg == 0 && sgp->sg_cterm_bg == 0 && sgp->sg_cterm_ul == 0
 # ifdef FEAT_TERMGUICOLORS
 	    && sgp->sg_gui_fg == INVALCOLOR
 	    && sgp->sg_gui_bg == INVALCOLOR
+	    && sgp->sg_gui_sp == INVALCOLOR
 # endif
 	    )
 	sgp->sg_cterm_attr = sgp->sg_cterm;
@@ -2859,6 +2901,7 @@
 	at_en.ae_attr = sgp->sg_cterm;
 	at_en.ae_u.cterm.fg_color = sgp->sg_cterm_fg;
 	at_en.ae_u.cterm.bg_color = sgp->sg_cterm_bg;
+	at_en.ae_u.cterm.ul_color = sgp->sg_cterm_ul;
 # ifdef FEAT_TERMGUICOLORS
 #  ifdef MSWIN
 #   ifdef VIMDLL
@@ -2883,6 +2926,7 @@
 #  endif
 	at_en.ae_u.cterm.fg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_fg);
 	at_en.ae_u.cterm.bg_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_bg);
+	at_en.ae_u.cterm.ul_rgb = GUI_MCH_GET_RGB2(sgp->sg_gui_sp);
 	if (at_en.ae_u.cterm.fg_rgb == INVALCOLOR
 		&& at_en.ae_u.cterm.bg_rgb == INVALCOLOR)
 	{
@@ -3067,9 +3111,7 @@
 #if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
     HL_TABLE()[highlight_ga.ga_len].sg_gui_bg = INVALCOLOR;
     HL_TABLE()[highlight_ga.ga_len].sg_gui_fg = INVALCOLOR;
-# ifdef FEAT_GUI
     HL_TABLE()[highlight_ga.ga_len].sg_gui_sp = INVALCOLOR;
-# endif
 #endif
     ++highlight_ga.ga_len;
 
@@ -3230,14 +3272,12 @@
 			    color_name2handle(HL_TABLE()[idx].sg_gui_bg_name);
 	didit = TRUE;
     }
-# ifdef FEAT_GUI
     if (HL_TABLE()[idx].sg_gui_sp_name != NULL)
     {
 	HL_TABLE()[idx].sg_gui_sp =
 			    color_name2handle(HL_TABLE()[idx].sg_gui_sp_name);
 	didit = TRUE;
     }
-# endif
     if (didit)	// need to get a new attr number
 	set_hl_attr(idx);
 }
diff --git a/src/optiondefs.h b/src/optiondefs.h
index 374764b..5ed9be9 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -2924,6 +2924,7 @@
 
     p_term("t_AB", T_CAB)
     p_term("t_AF", T_CAF)
+    p_term("t_AU", T_CAU)
     p_term("t_AL", T_CAL)
     p_term("t_al", T_AL)
     p_term("t_bc", T_BC)
@@ -3002,6 +3003,7 @@
     p_term("t_ZR", T_CZR)
     p_term("t_8f", T_8F)
     p_term("t_8b", T_8B)
+    p_term("t_8u", T_8U)
 
 // terminal key codes are not in here
 
diff --git a/src/proto/term.pro b/src/proto/term.pro
index fa7c69d..d84823c 100644
--- a/src/proto/term.pro
+++ b/src/proto/term.pro
@@ -26,9 +26,11 @@
 void term_set_winsize(int height, int width);
 void term_fg_color(int n);
 void term_bg_color(int n);
+void term_ul_color(int n);
 char_u *term_bg_default(void);
 void term_fg_rgb_color(guicolor_T rgb);
 void term_bg_rgb_color(guicolor_T rgb);
+void term_ul_rgb_color(guicolor_T rgb);
 void term_settitle(char_u *title);
 void term_push_title(int which);
 void term_pop_title(int which);
diff --git a/src/screen.c b/src/screen.c
index 9dac324..ea7aaa6 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1866,6 +1866,19 @@
 		    if (aep->ae_u.cterm.bg_color)
 			term_bg_color(aep->ae_u.cterm.bg_color - 1);
 		}
+#ifdef FEAT_TERMGUICOLORS
+		if (p_tgc && aep->ae_u.cterm.ul_rgb != CTERMCOLOR)
+		{
+		    if (aep->ae_u.cterm.ul_rgb != INVALCOLOR)
+			term_ul_rgb_color(aep->ae_u.cterm.ul_rgb);
+		}
+		else
+#endif
+		if (t_colors > 1)
+		{
+		    if (aep->ae_u.cterm.ul_color)
+			term_ul_color(aep->ae_u.cterm.ul_color - 1);
+		}
 
 		if (!IS_CTERM)
 		{
@@ -2021,6 +2034,8 @@
 		    term_fg_rgb_color(cterm_normal_fg_gui_color);
 		if (cterm_normal_bg_gui_color != INVALCOLOR)
 		    term_bg_rgb_color(cterm_normal_bg_gui_color);
+		if (cterm_normal_ul_gui_color != INVALCOLOR)
+		    term_ul_rgb_color(cterm_normal_ul_gui_color);
 	    }
 	    else
 #endif
@@ -2032,6 +2047,8 @@
 			term_fg_color(cterm_normal_fg_color - 1);
 		    if (cterm_normal_bg_color != 0)
 			term_bg_color(cterm_normal_bg_color - 1);
+		    if (cterm_normal_ul_color != 0)
+			term_ul_color(cterm_normal_ul_color - 1);
 		    if (cterm_normal_fg_bold)
 			out_str(T_MD);
 		}
diff --git a/src/structs.h b/src/structs.h
index eb4f60e..f67aba3 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -1068,9 +1068,11 @@
 	    // These colors need to be > 8 bits to hold 256.
 	    short_u	    fg_color;	// foreground color number
 	    short_u	    bg_color;	// background color number
+	    short_u	    ul_color;	// underline color number
 # ifdef FEAT_TERMGUICOLORS
 	    guicolor_T	    fg_rgb;	// foreground color RGB
 	    guicolor_T	    bg_rgb;	// background color RGB
+	    guicolor_T	    ul_rgb;	// underline color RGB
 # endif
 	} cterm;
 # ifdef FEAT_GUI
diff --git a/src/term.c b/src/term.c
index f93fde8..c024fce 100644
--- a/src/term.c
+++ b/src/term.c
@@ -928,7 +928,9 @@
     // These are printf strings, not terminal codes.
     {(int)KS_8F,	IF_EB("\033[38;2;%lu;%lu;%lum", ESC_STR "[38;2;%lu;%lu;%lum")},
     {(int)KS_8B,	IF_EB("\033[48;2;%lu;%lu;%lum", ESC_STR "[48;2;%lu;%lu;%lum")},
+    {(int)KS_8U,	IF_EB("\033[58;2;%lu;%lu;%lum", ESC_STR "[58;2;%lu;%lu;%lum")},
 #  endif
+    {(int)KS_CAU,	IF_EB("\033[58;5;%dm", ESC_STR "[58;5;%dm")},
     {(int)KS_CBE,	IF_EB("\033[?2004h", ESC_STR "[?2004h")},
     {(int)KS_CBD,	IF_EB("\033[?2004l", ESC_STR "[?2004l")},
     {(int)KS_CST,	IF_EB("\033[22;2t", ESC_STR "[22;2t")},
@@ -1187,6 +1189,7 @@
     {(int)KS_CSB,	"[CSB%d]"},
     {(int)KS_CSF,	"[CSF%d]"},
 #  endif
+    {(int)KS_CAU,	"[CAU%d]"},
     {(int)KS_OP,	"[OP]"},
     {(int)KS_LE,	"[LE]"},
     {(int)KS_CL,	"[CL]"},
@@ -1617,7 +1620,8 @@
 			{KS_KE, "ke"}, {KS_TI, "ti"}, {KS_TE, "te"},
 			{KS_CTI, "TI"}, {KS_CTE, "TE"},
 			{KS_BC, "bc"}, {KS_CSB,"Sb"}, {KS_CSF,"Sf"},
-			{KS_CAB,"AB"}, {KS_CAF,"AF"}, {KS_LE, "le"},
+			{KS_CAB,"AB"}, {KS_CAF,"AF"}, {KS_CAU,"AU"},
+			{KS_LE, "le"},
 			{KS_ND, "nd"}, {KS_OP, "op"}, {KS_CRV, "RV"},
 			{KS_VS, "vs"}, {KS_CVS, "VS"},
 			{KS_CIS, "IS"}, {KS_CIE, "IE"},
@@ -1626,7 +1630,7 @@
 			{KS_CWP, "WP"}, {KS_CWS, "WS"},
 			{KS_CSI, "SI"}, {KS_CEI, "EI"},
 			{KS_U7, "u7"}, {KS_RFG, "RF"}, {KS_RBG, "RB"},
-			{KS_8F, "8f"}, {KS_8B, "8b"},
+			{KS_8F, "8f"}, {KS_8B, "8b"}, {KS_8U, "8u"},
 			{KS_CBE, "BE"}, {KS_CBD, "BD"},
 			{KS_CPS, "PS"}, {KS_CPE, "PE"},
 			{KS_CST, "ST"}, {KS_CRT, "RT"},
@@ -2881,6 +2885,13 @@
 	term_color(T_CSB, n);
 }
 
+    void
+term_ul_color(int n)
+{
+    if (*T_CAU)
+	term_color(T_CAU, n);
+}
+
 /*
  * Return "dark" or "light" depending on the kind of terminal.
  * This is just guessing!  Recognized are:
@@ -2952,6 +2963,12 @@
 {
     term_rgb_color(T_8B, rgb);
 }
+
+    void
+term_ul_rgb_color(guicolor_T rgb)
+{
+    term_rgb_color(T_8U, rgb);
+}
 #endif
 
 #if (defined(FEAT_TITLE) && (defined(UNIX) || defined(VMS) \
diff --git a/src/term.h b/src/term.h
index dca48d1..bff901e 100644
--- a/src/term.h
+++ b/src/term.h
@@ -78,6 +78,7 @@
     KS_MB,	// blink mode
     KS_CAF,	// set foreground color (ANSI)
     KS_CAB,	// set background color (ANSI)
+    KS_CAU,	// set underline color (ANSI)
     KS_LE,	// cursor left (mostly backspace)
     KS_ND,	// cursor right
     KS_CIS,	// set icon text start
@@ -100,6 +101,7 @@
     KS_U7,	// request cursor position
     KS_8F,	// set foreground color (RGB)
     KS_8B,	// set background color (RGB)
+    KS_8U,	// set underline color (RGB)
     KS_CBE,	// enable bracketed paste mode
     KS_CBD,	// disable bracketed paste mode
     KS_CPS,	// start of bracketed paste
@@ -179,6 +181,7 @@
 #define T_MB	(TERM_STR(KS_MB))	// blink mode
 #define T_CAF	(TERM_STR(KS_CAF))	// set foreground color (ANSI)
 #define T_CAB	(TERM_STR(KS_CAB))	// set background color (ANSI)
+#define T_CAU	(TERM_STR(KS_CAU))	// set underline color (ANSI)
 #define T_LE	(TERM_STR(KS_LE))	// cursor left
 #define T_ND	(TERM_STR(KS_ND))	// cursor right
 #define T_CIS	(TERM_STR(KS_CIS))	// set icon text start
@@ -200,6 +203,7 @@
 #define T_U7	(TERM_STR(KS_U7))	// request cursor position
 #define T_8F	(TERM_STR(KS_8F))	// set foreground color (RGB)
 #define T_8B	(TERM_STR(KS_8B))	// set background color (RGB)
+#define T_8U	(TERM_STR(KS_8U))	// set underline color (RGB)
 #define T_BE	(TERM_STR(KS_CBE))	// enable bracketed paste mode
 #define T_BD	(TERM_STR(KS_CBD))	// disable bracketed paste mode
 #define T_PS	(TERM_STR(KS_CPS))	// start of bracketed paste
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 17ae094..d18b15f 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -275,7 +275,7 @@
 
   " Expand terminal options.
   call feedkeys(":set t_A\<C-A>\<C-B>\"\<CR>", 'tx')
-  call assert_equal('"set t_AB t_AF t_AL', @:)
+  call assert_equal('"set t_AB t_AF t_AU t_AL', @:)
   call assert_fails('call feedkeys(":set <t_afoo>=\<C-A>\<CR>", "xt")', 'E474:')
 
   " Expand directories.
diff --git a/src/version.c b/src/version.c
index c39e712..e6caf8d 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    863,
+/**/
     862,
 /**/
     861,