OUTPUT1 (tty, tty->TS_enter_dim_mode);
}
- if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
- OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
+ if (face->underline && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
+ {
+ if (face->underline == FACE_UNDERLINE_SINGLE
+ || !tty->TF_set_underline_style)
+ OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
+ else if (tty->TF_set_underline_style)
+ {
+ char *p;
+ p = tparam (tty->TF_set_underline_style, NULL, 0, face->underline, 0, 0, 0);
+ OUTPUT (tty, p);
+ xfree (p);
+ }
+ }
if (face->tty_strike_through_p
&& MAY_USE_WITH_COLORS_P (tty, NC_STRIKE_THROUGH))
OUTPUT (tty, p);
xfree (p);
}
+
+ ts = tty->TF_set_underline_color;
+ if (ts && face->underline_color)
+ {
+ p = tparam (ts, NULL, 0, face->underline_color, 0, 0, 0);
+ OUTPUT (tty, p);
+ xfree (p);
+ }
}
}
if (face->tty_bold_p
|| face->tty_italic_p
|| face->tty_reverse_p
- || face->tty_underline_p
+ || face->underline
|| face->tty_strike_through_p)
{
OUTPUT1_IF (tty, tty->TS_exit_attribute_mode);
{
/* If we don't have "me" we can only have those appearances
that have exit sequences defined. */
- if (face->tty_underline_p)
+ if (face->underline)
OUTPUT_IF (tty, tty->TS_exit_underline_mode);
}
TTY_CAPABLE_P_TRY (tty,
TTY_CAP_UNDERLINE, tty->TS_enter_underline_mode,
NC_UNDERLINE);
+ TTY_CAPABLE_P_TRY (tty,
+ TTY_CAP_UNDERLINE_STYLED, tty->TF_set_underline_style,
+ NC_UNDERLINE);
TTY_CAPABLE_P_TRY (tty,
TTY_CAP_BOLD, tty->TS_enter_bold_mode, NC_BOLD);
TTY_CAPABLE_P_TRY (tty,
tty->TF_underscore = tgetflag ("ul");
tty->TF_teleray = tgetflag ("xt");
+ /* Styled underlines. Support for this is provided either by the
+ escape sequence in Smulx or the Su flag. The latter results in a
+ common default escape sequence and is not recommended. */
+#ifdef TERMINFO
+ tty->TF_set_underline_style = tigetstr ("Smulx");
+ if (tty->TF_set_underline_style == (char *) (intptr_t) -1)
+ tty->TF_set_underline_style = NULL;
+#else
+ tty->TF_set_underline_style = tgetstr ("Smulx", address);
+#endif
+ if (!tty->TF_set_underline_style && tgetflag ("Su"))
+ /* Default to the kitty escape sequence. See
+ https://sw.kovidgoyal.net/kitty/underlines/. */
+ tty->TF_set_underline_style = "\x1b[4:%p1%dm";
+
+ if (tty->TF_set_underline_style)
+ /* Standard escape sequence to set the underline color.
+ Requires a single parameter, the color index. */
+ tty->TF_set_underline_color = "\x1b[58:2::%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%dm";
+
#else /* DOS_NT */
#ifdef WINDOWSNT
{
}
else if (EQ (key, QCstyle)
- && !(EQ (val, Qline) || EQ (val, Qwave)))
+ && !(EQ (val, Qline)
+ || EQ (val, Qdouble_line)
+ || EQ (val, Qwave)
+ || EQ (val, Qdots)
+ || EQ (val, Qdashes)))
{
valid_p = false;
break;
Lisp_Object attrs[LFACE_VECTOR_SIZE],
struct face *def_face)
{
+ Lisp_Object val;
Lisp_Object *def_attrs = def_face->lface;
Lisp_Object lattrs[LFACE_VECTOR_SIZE];
return false;
}
+ /* Check supported underline styles. */
+ val = attrs[LFACE_UNDERLINE_INDEX];
+ if (!UNSPECIFIEDP (val)
+ && EQ (CAR_SAFE (val), QCstyle)
+ && !(EQ (CAR_SAFE (CDR_SAFE (val)), Qline)
+ || EQ (CAR_SAFE (CDR_SAFE (val)), Qwave)))
+ return false; /* Unsupported underline style. */
+
/* Everything checks out, this face is supported. */
return true;
}
if (!UNSPECIFIEDP (val))
{
if (STRINGP (val))
- return false; /* ttys can't use colored underlines */
- else if (EQ (CAR_SAFE (val), QCstyle) && EQ (CAR_SAFE (CDR_SAFE (val)), Qwave))
- return false; /* ttys can't use wave underlines */
+ test_caps |= TTY_CAP_UNDERLINE_STYLED;
+ else if (EQ (CAR_SAFE (val), QCstyle))
+ {
+ if (!(EQ (CAR_SAFE (CDR_SAFE (val)), Qline)
+ || EQ (CAR_SAFE (CDR_SAFE (val)), Qdouble_line)
+ || EQ (CAR_SAFE (CDR_SAFE (val)), Qwave)
+ || EQ (CAR_SAFE (CDR_SAFE (val)), Qdots)
+ || EQ (CAR_SAFE (CDR_SAFE (val)), Qdashes)))
+ return false; /* Face uses an unsupported underline style. */
+
+ test_caps |= TTY_CAP_UNDERLINE_STYLED;
+ }
else if (face_attr_equal_p (val, def_attrs[LFACE_UNDERLINE_INDEX]))
return false; /* same as default */
else
if (EQ (underline, Qt))
{
/* Use default color (same as foreground color). */
- face->underline = FACE_UNDER_LINE;
+ face->underline = FACE_UNDERLINE_SINGLE;
face->underline_defaulted_p = true;
face->underline_color = 0;
face->underline_at_descent_line_p = false;
else if (STRINGP (underline))
{
/* Use specified color. */
- face->underline = FACE_UNDER_LINE;
+ face->underline = FACE_UNDERLINE_SINGLE;
face->underline_defaulted_p = false;
face->underline_color
= load_color (f, face, underline,
{
/* `(:color COLOR :style STYLE)'.
STYLE being one of `line' or `wave'. */
- face->underline = FACE_UNDER_LINE;
+ face->underline = FACE_UNDERLINE_SINGLE;
face->underline_color = 0;
face->underline_defaulted_p = true;
face->underline_at_descent_line_p = false;
else if (EQ (keyword, QCstyle))
{
if (EQ (value, Qline))
- face->underline = FACE_UNDER_LINE;
+ face->underline = FACE_UNDERLINE_SINGLE;
else if (EQ (value, Qwave))
- face->underline = FACE_UNDER_WAVE;
+ face->underline = FACE_UNDERLINE_WAVE;
+ else
+ face->underline = FACE_UNDERLINE_SINGLE;
}
else if (EQ (keyword, QCposition))
{
}
-/* Map a specified color of face FACE on frame F to a tty color index.
- IDX is either LFACE_FOREGROUND_INDEX or LFACE_BACKGROUND_INDEX, and
- specifies which color to map. Set *DEFAULTED to true if mapping to the
+/* Map the specified color COLOR of face FACE on frame F to a tty
+ color index. IDX is one of LFACE_FOREGROUND_INDEX,
+ LFACE_BACKGROUND_INDEX or LFACE_UNDERLINE_INDEX, and specifies
+ which color to map. Set *DEFAULTED to true if mapping to the
default foreground/background colors. */
static void
-map_tty_color (struct frame *f, struct face *face,
- enum lface_attribute_index idx, bool *defaulted)
+map_tty_color (struct frame *f, struct face *face, Lisp_Object color,
+ enum lface_attribute_index idx, bool *defaulted)
{
- Lisp_Object frame, color, def;
- bool foreground_p = idx == LFACE_FOREGROUND_INDEX;
+ Lisp_Object frame, def;
+ bool foreground_p = idx != LFACE_BACKGROUND_INDEX;
unsigned long default_pixel =
foreground_p ? FACE_TTY_DEFAULT_FG_COLOR : FACE_TTY_DEFAULT_BG_COLOR;
unsigned long pixel = default_pixel;
foreground_p ? FACE_TTY_DEFAULT_BG_COLOR : FACE_TTY_DEFAULT_FG_COLOR;
#endif
- eassert (idx == LFACE_FOREGROUND_INDEX || idx == LFACE_BACKGROUND_INDEX);
+ eassert (idx == LFACE_FOREGROUND_INDEX
+ || idx == LFACE_BACKGROUND_INDEX
+ || idx == LFACE_UNDERLINE_INDEX);
XSETFRAME (frame, f);
- color = face->lface[idx];
if (STRINGP (color)
&& SCHARS (color)
#endif /* MSDOS */
}
- if (foreground_p)
- face->foreground = pixel;
- else
- face->background = pixel;
+ switch (idx)
+ {
+ case LFACE_FOREGROUND_INDEX:
+ face->foreground = pixel;
+ break;
+ case LFACE_UNDERLINE_INDEX:
+ face->underline_color = pixel;
+ break;
+ case LFACE_BACKGROUND_INDEX:
+ default:
+ face->background = pixel;
+ break;
+ }
}
-
/* Realize the fully-specified face with attributes ATTRS in face
cache CACHE for ASCII characters. Do it for TTY frame CACHE->f.
Value is a pointer to the newly created realized face. */
{
struct face *face;
int weight, slant;
+ Lisp_Object underline;
bool face_colors_defaulted = false;
struct frame *f = cache->f;
face->tty_bold_p = true;
if (slant != 100)
face->tty_italic_p = true;
- if (!NILP (attrs[LFACE_UNDERLINE_INDEX]))
- face->tty_underline_p = true;
if (!NILP (attrs[LFACE_INVERSE_INDEX]))
face->tty_reverse_p = true;
if (!NILP (attrs[LFACE_STRIKE_THROUGH_INDEX]))
face->tty_strike_through_p = true;
+ /* Text underline. */
+ underline = attrs[LFACE_UNDERLINE_INDEX];
+ if (NILP (underline))
+ {
+ face->underline = FACE_NO_UNDERLINE;
+ face->underline_color = 0;
+ }
+ else if (EQ (underline, Qt))
+ {
+ face->underline = FACE_UNDERLINE_SINGLE;
+ face->underline_color = 0;
+ }
+ else if (STRINGP (underline))
+ {
+ face->underline = FACE_UNDERLINE_SINGLE;
+ bool underline_color_defaulted;
+ map_tty_color (f, face, underline, LFACE_UNDERLINE_INDEX,
+ &underline_color_defaulted);
+ }
+ else if (CONSP (underline))
+ {
+ /* `(:color COLOR :style STYLE)'.
+ STYLE being one of `line', `double-line', `wave', `dots' or `dashes'. */
+ face->underline = FACE_UNDERLINE_SINGLE;
+ face->underline_color = 0;
+
+ while (CONSP (underline))
+ {
+ Lisp_Object keyword, value;
+
+ keyword = XCAR (underline);
+ underline = XCDR (underline);
+
+ if (!CONSP (underline))
+ break;
+ value = XCAR (underline);
+ underline = XCDR (underline);
+
+ if (EQ (keyword, QCcolor))
+ {
+ if (EQ (value, Qforeground_color))
+ face->underline_color = 0;
+ else if (STRINGP (value))
+ {
+ bool underline_color_defaulted;
+ map_tty_color (f, face, value, LFACE_UNDERLINE_INDEX,
+ &underline_color_defaulted);
+ }
+ }
+ else if (EQ (keyword, QCstyle))
+ {
+ if (EQ (value, Qline))
+ face->underline = FACE_UNDERLINE_SINGLE;
+ else if (EQ (value, Qdouble_line))
+ face->underline = FACE_UNDERLINE_DOUBLE_LINE;
+ else if (EQ (value, Qwave))
+ face->underline = FACE_UNDERLINE_WAVE;
+ else if (EQ (value, Qdots))
+ face->underline = FACE_UNDERLINE_DOTS;
+ else if (EQ (value, Qdashes))
+ face->underline = FACE_UNDERLINE_DASHES;
+ else
+ face->underline = FACE_UNDERLINE_SINGLE;
+ }
+ }
+ }
+
/* Map color names to color indices. */
- map_tty_color (f, face, LFACE_FOREGROUND_INDEX, &face_colors_defaulted);
- map_tty_color (f, face, LFACE_BACKGROUND_INDEX, &face_colors_defaulted);
+ map_tty_color (f, face, face->lface[LFACE_FOREGROUND_INDEX],
+ LFACE_FOREGROUND_INDEX, &face_colors_defaulted);
+ map_tty_color (f, face, face->lface[LFACE_BACKGROUND_INDEX],
+ LFACE_BACKGROUND_INDEX, &face_colors_defaulted);
/* Swap colors if face is inverse-video. If the colors are taken
from the frame colors, they are already inverted, since the
DEFSYM (QCposition, ":position");
DEFSYM (Qline, "line");
DEFSYM (Qwave, "wave");
+ DEFSYM (Qdouble_line, "double-line");
+ DEFSYM (Qdots, "dots");
+ DEFSYM (Qdashes, "dashes");
DEFSYM (Qreleased_button, "released-button");
DEFSYM (Qpressed_button, "pressed-button");
DEFSYM (Qflat_button, "flat-button");