* bug#45230: /bug#45231: [PATCH] Support underline colors and styles in terminal
2020-12-13 22:29 bug#45230: 27.1; Fix support for wavy underlines on terminal mode Víctor Cuadrado Juan
2020-12-14 15:29 ` Eli Zaretskii
@ 2022-12-23 1:36 ` Adam Schwalm
2022-12-24 7:47 ` Eli Zaretskii
1 sibling, 1 reply; 4+ messages in thread
From: Adam Schwalm @ 2022-12-23 1:36 UTC (permalink / raw)
To: 45230
[-- Attachment #1: Type: text/plain, Size: 2510 bytes --]
Many modern terminal emulators support control sequences that enable underlines
with colors other than the text foreground color and styles like the
'wave' used in GUI
mode Emacs. These two patches add support for using these control sequences
in terminal mode Emacs. The first enables support for terminals which
report support
for these features in their terminfo, the second adds two functions
which can be used
to override terminfo and explicitly enable the feature. The latter is
unfortunately probably
necessary, as there is no official way to announce support in terminfo
yet (though there
is an unofficial standard being followed by some terminals).
I have tested these patches on the following terminal emulators on GNU/Linux:
- Alacritty
- Kitty
- Wezterm
- gnome-terminal (vte)
And on Windows, I tested with mintty (though I have very little
experience with Windows
terminal emulators).
For alacritty, kitty and wezterm, the 'style' feature works without
any action from the user.
The 'Smulx' entry is present in their terminfo, which emacs detects.
Unfortunately, while
some terminals like wezterm do announce support for underline colors
via 'Setulc',
they do not announce support for the 'ol' feature used to reset the
underline color back
to default (which I think is necessary when turning off a face).
Therefore, I had to use
the new functions to force enable colors. After doing this, underline
colors worked in
the terminals listed above.
I will be working in the next few weeks to update the terminfo for
some of these terminal
emulators to reflect these capabilities, but this will presumably take
a long time to
actually land in the main ncurses terminfo.src. With that said, I do
think there is enough
of a general consensus on the terminfo names that should be used (from tmux and
existing usage in some terminals), that such additions will hopefully
be uncontroversial.
For the second patch, 'default' control sequences I've chosen (if the
user explicitly requests
underline color/styles be enabled on a terminal that does not declare
support for those
features) is supported by the terminals listed above as well as tmux.
Please note that I have not signed the copyright assignment, but if
these patches seem worth
merging in some form, I will complete that (and update
NEWS/manuals/etc). There are
some areas that I suspect I am doing things wrong as I don't have much prior
experience with emacs internals, so please let me know and I'll update things.
Thanks,
Adam Schwalm
[-- Attachment #2: 0001-Support-underline-colors-and-styles-in-non-gui-mode.patch --]
[-- Type: text/x-patch, Size: 17847 bytes --]
From 1ebf2a80073010e2388f78c1bd6b48803557365f Mon Sep 17 00:00:00 2001
From: Adam Schwalm <adamschwalm@gmail.com>
Date: Mon, 19 Dec 2022 18:56:59 -0600
Subject: [PATCH 1/2] Support underline colors and styles in non-gui mode
Many terminal emulators now support informal escape sequences
to allow setting color and style of underlines. Underline color is
typically controlled by a sequence intended to mirror the CSI 38/48
codes for foreground/background colors:
CSI 58 : 2 :: R : G : B m -> set color to specified true color RGB
CSI 58 : 5 : I m -> set color to palette index I (0-255)
CSI 59 m -> restore underline color to default
Underline style is controlled via a set of extensions to CSI 4:
CSI 4 : 0 m -> No underline
CSI 4 : 1 m -> Single underline
CSI 4 : 2 m -> Double underline
CSI 4 : 3 m -> Curly underline
CSI 4 : 4 m -> Dotted underline
CSI 4 : 5 m -> Dashed underline
The informal terminfo identifiers for these features are:
Smulx -> Underline style sequence
Setulc -> Underline color set sequence
ol -> Underline color reset sequence
This patch allows emacs to recognize these features of a terminal
emulator and use them to support setting 'wave' underline style
and colors when running in a tty.
(Bug#45230)
(Bug#45231)
---
src/term.c | 87 +++++++++++++++++-
src/termchar.h | 3 +
src/xfaces.c | 235 ++++++++++++++++++++++++++++---------------------
3 files changed, 222 insertions(+), 103 deletions(-)
diff --git a/src/term.c b/src/term.c
index f8104e0304..306c57338b 100644
--- a/src/term.c
+++ b/src/term.c
@@ -115,6 +115,32 @@ #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } whil
NC_PROTECT = 1 << 7
};
+
+enum tty_underline_type
+{
+ TTY_NO_UNDERLINE = 0,
+ TTY_UNDER_LINE,
+ TTY_DOUBLE_UNDER_LINE,
+ TTY_CURLY_UNDER_LINE,
+ TTY_DOTTED_UNDER_LINE,
+ TTY_DASHED_UNDER_LINE
+};
+
+static int tty_map_underline_style (enum face_underline_type underline)
+{
+ switch (underline)
+ {
+ case FACE_NO_UNDERLINE:
+ return TTY_NO_UNDERLINE;
+ case FACE_UNDER_LINE:
+ return TTY_UNDER_LINE;
+ case FACE_UNDER_WAVE:
+ return TTY_CURLY_UNDER_LINE;
+ default:
+ return TTY_UNDER_LINE;
+ }
+}
+
/* internal state */
/* The largest frame width in any call to calculate_costs. */
@@ -1923,6 +1949,7 @@ turn_on_face (struct frame *f, int face_id)
struct face *face = FACE_FROM_ID (f, face_id);
unsigned long fg = face->foreground;
unsigned long bg = face->background;
+ unsigned long uc = face->underline_color;
struct tty_display_info *tty = FRAME_TTY (f);
/* Use reverse video if the face specifies that.
@@ -1949,7 +1976,24 @@ turn_on_face (struct frame *f, int face_id)
}
if (face->tty_underline_p && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE))
- OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
+ {
+ OUTPUT1_IF (tty, tty->TS_enter_underline_mode);
+
+ if (face_tty_specified_color (uc) && tty->TS_set_underline_color)
+ {
+ char *p = tparam (tty->TS_set_underline_color, NULL, 0, uc, 0, 0, 0);
+ OUTPUT (tty, p);
+ xfree (p);
+ }
+
+ if (face->underline != FACE_UNDER_LINE && tty->TS_set_underline_style)
+ {
+ char *p = tparam (tty->TS_set_underline_style, NULL, 0,
+ tty_map_underline_style (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))
@@ -1986,6 +2030,7 @@ turn_off_face (struct frame *f, int face_id)
{
struct face *face = FACE_FROM_ID (f, face_id);
struct tty_display_info *tty = FRAME_TTY (f);
+ unsigned long uc = face->underline_color;
if (tty->TS_exit_attribute_mode)
{
@@ -2008,7 +2053,20 @@ turn_off_face (struct frame *f, int face_id)
/* If we don't have "me" we can only have those appearances
that have exit sequences defined. */
if (face->tty_underline_p)
- OUTPUT_IF (tty, tty->TS_exit_underline_mode);
+ {
+ OUTPUT_IF (tty, tty->TS_exit_underline_mode);
+
+ if (face_tty_specified_color (uc))
+ OUTPUT_IF (tty, tty->TS_reset_underline_color);
+
+ if (face->underline != FACE_UNDER_LINE && tty->TS_set_underline_style)
+ {
+ char *p = tparam (tty->TS_set_underline_style, NULL, 0,
+ tty_map_underline_style (face->underline), 0, 0, 0);
+ OUTPUT (tty, p);
+ xfree (p);
+ }
+ }
}
/* Switch back to default colors. */
@@ -4156,6 +4214,31 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed)
tty->TS_enter_underline_mode = tgetstr ("us", address);
tty->TS_exit_underline_mode = tgetstr ("ue", address);
+#ifdef TERMINFO
+ {
+ /* Underline color and style support. These are unofficial
+ identifiers, which are used here due to as a de-facto standard
+ introduced by tmux. */
+ tty->TS_set_underline_style = tigetstr ("Smulx");
+ tty->TS_set_underline_color = tigetstr ("Setulc");
+ tty->TS_reset_underline_color = tigetstr ("ol");
+
+ if (tty->TS_set_underline_style == (char *) (intptr_t) -1)
+ tty->TS_set_underline_style = NULL;
+
+ /* If either color or reset is not available, disable underline
+ coloring. */
+ if (tty->TS_reset_underline_color == NULL ||
+ tty->TS_reset_underline_color == (char *) (intptr_t) -1 ||
+ tty->TS_set_underline_color == NULL ||
+ tty->TS_set_underline_color == (char *) (intptr_t) -1)
+ {
+ tty->TS_set_underline_color = NULL;
+ tty->TS_reset_underline_color = NULL;
+ }
+ }
+#endif
+
tty->TS_enter_bold_mode = tgetstr ("md", address);
tty->TS_enter_italic_mode = tgetstr ("ZH", address);
tty->TS_enter_dim_mode = tgetstr ("mh", address);
diff --git a/src/termchar.h b/src/termchar.h
index 0f17246411..33800e41c0 100644
--- a/src/termchar.h
+++ b/src/termchar.h
@@ -143,6 +143,9 @@ #define EMACS_TERMCHAR_H
const char *TS_enter_underline_mode; /* "ue" -- end underlining. */
const char *TS_enter_strike_through_mode; /* "smxx" -- turn on strike-through
mode. */
+ const char* TS_set_underline_style; /* "Smulx" */
+ const char* TS_set_underline_color; /* "Setulc" */
+ const char* TS_reset_underline_color; /* "ol" */
/* "as"/"ae" -- start/end alternate character set. Not really
supported, yet. */
diff --git a/src/xfaces.c b/src/xfaces.c
index be4a7ca71c..44285cea09 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -373,6 +373,10 @@ #define CLEAR_FONT_TABLE_NFONTS 10
Lisp_Object [LFACE_VECTOR_SIZE]);
static struct face *realize_tty_face (struct face_cache *,
Lisp_Object [LFACE_VECTOR_SIZE]);
+static void realize_underline_attrs (struct face* face,
+ struct face_cache *cache,
+ Lisp_Object attrs [LFACE_VECTOR_SIZE],
+ bool tty);
static bool realize_basic_faces (struct frame *);
static bool realize_default_face (struct frame *);
static void realize_named_face (struct frame *, Lisp_Object, int);
@@ -383,6 +387,9 @@ #define CLEAR_FONT_TABLE_NFONTS 10
bool, struct named_merge_point *,
enum lface_attribute_index);
static int color_distance (Emacs_Color *x, Emacs_Color *y);
+static unsigned long map_tty_color (struct frame *f, struct face *face,
+ enum lface_attribute_index idx, bool *defaulted,
+ Lisp_Object color);
#ifdef HAVE_WINDOW_SYSTEM
static void set_font_frame_param (Lisp_Object, Lisp_Object);
@@ -6032,6 +6039,111 @@ font_maybe_unset_attribute (Lisp_Object font_object,
}
}
+void
+realize_underline_attrs (struct face* face,
+ struct face_cache *cache,
+ Lisp_Object attrs[LFACE_VECTOR_SIZE],
+ bool tty)
+{
+ struct frame *f = cache->f;
+ unsigned long default_color = tty ? FACE_TTY_DEFAULT_COLOR : 0;
+ Lisp_Object underline = attrs[LFACE_UNDERLINE_INDEX];
+ bool defaulted = false;
+ if (EQ (underline, Qt))
+ {
+ /* Use default color (same as foreground color). */
+ face->underline = FACE_UNDER_LINE;
+ face->underline_defaulted_p = true;
+ face->underline_color = default_color;
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
+ }
+ else if (STRINGP (underline))
+ {
+ /* Use specified color. */
+ face->underline = FACE_UNDER_LINE;
+
+ if (tty)
+ face->underline_color = map_tty_color (f, face, LFACE_UNDERLINE_INDEX,
+ &defaulted,
+ face->lface[LFACE_UNDERLINE_INDEX]);
+ else
+ face->underline_color
+ = load_color (f, face, underline,
+ LFACE_UNDERLINE_INDEX);
+ face->underline_defaulted_p = defaulted;
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
+ }
+ else if (NILP (underline))
+ {
+ face->underline = FACE_NO_UNDERLINE;
+ face->underline_defaulted_p = false;
+ face->underline_color = default_color;
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
+ }
+ else if (CONSP (underline))
+ {
+ /* `(:color COLOR :style STYLE)'.
+ STYLE being one of `line' or `wave'. */
+ face->underline = FACE_UNDER_LINE;
+ face->underline_color = default_color;
+ face->underline_defaulted_p = true;
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
+
+ /* FIXME? This is also not robust about checking the precise form.
+ See comments in Finternal_set_lisp_face_attribute. */
+ 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_defaulted_p = true;
+ face->underline_color = default_color;
+ }
+ else if (STRINGP (value))
+ {
+ if (tty)
+ face->underline_color = map_tty_color (f, face, LFACE_UNDERLINE_INDEX,
+ &defaulted,
+ value);
+ else
+ face->underline_color = load_color (f, face, value,
+ LFACE_UNDERLINE_INDEX);
+ face->underline_defaulted_p = defaulted;
+ }
+ }
+ else if (EQ (keyword, QCstyle))
+ {
+ if (EQ (value, Qline))
+ face->underline = FACE_UNDER_LINE;
+ else if (EQ (value, Qwave))
+ face->underline = FACE_UNDER_WAVE;
+ }
+ else if (EQ (keyword, QCposition) && !tty)
+ {
+ face->underline_at_descent_line_p = !NILP (value);
+
+ if (FIXNATP (value))
+ face->underline_pixels_above_descent_line = XFIXNAT (value);
+ }
+ }
+ }
+}
+
/* Realize the fully-specified face with attributes ATTRS in face
cache CACHE for ASCII characters. Do it for GUI frame CACHE->f.
If the new face doesn't share font with the default face, a
@@ -6046,7 +6158,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
#ifdef HAVE_WINDOW_SYSTEM
struct face *default_face;
struct frame *f;
- Lisp_Object stipple, underline, overline, strike_through, box;
+ Lisp_Object stipple, overline, strike_through, box;
eassert (FRAME_WINDOW_P (cache->f));
@@ -6244,90 +6356,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
}
/* Text underline, overline, strike-through. */
-
- underline = attrs[LFACE_UNDERLINE_INDEX];
- if (EQ (underline, Qt))
- {
- /* Use default color (same as foreground color). */
- face->underline = FACE_UNDER_LINE;
- face->underline_defaulted_p = true;
- face->underline_color = 0;
- face->underline_at_descent_line_p = false;
- face->underline_pixels_above_descent_line = 0;
- }
- else if (STRINGP (underline))
- {
- /* Use specified color. */
- face->underline = FACE_UNDER_LINE;
- face->underline_defaulted_p = false;
- face->underline_color
- = load_color (f, face, underline,
- LFACE_UNDERLINE_INDEX);
- face->underline_at_descent_line_p = false;
- face->underline_pixels_above_descent_line = 0;
- }
- else if (NILP (underline))
- {
- face->underline = FACE_NO_UNDERLINE;
- face->underline_defaulted_p = false;
- face->underline_color = 0;
- face->underline_at_descent_line_p = false;
- face->underline_pixels_above_descent_line = 0;
- }
- else if (CONSP (underline))
- {
- /* `(:color COLOR :style STYLE)'.
- STYLE being one of `line' or `wave'. */
- face->underline = FACE_UNDER_LINE;
- face->underline_color = 0;
- face->underline_defaulted_p = true;
- face->underline_at_descent_line_p = false;
- face->underline_pixels_above_descent_line = 0;
-
- /* FIXME? This is also not robust about checking the precise form.
- See comments in Finternal_set_lisp_face_attribute. */
- 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_defaulted_p = true;
- face->underline_color = 0;
- }
- else if (STRINGP (value))
- {
- face->underline_defaulted_p = false;
- face->underline_color = load_color (f, face, value,
- LFACE_UNDERLINE_INDEX);
- }
- }
- else if (EQ (keyword, QCstyle))
- {
- if (EQ (value, Qline))
- face->underline = FACE_UNDER_LINE;
- else if (EQ (value, Qwave))
- face->underline = FACE_UNDER_WAVE;
- }
- else if (EQ (keyword, QCposition))
- {
- face->underline_at_descent_line_p = !NILP (value);
-
- if (FIXNATP (value))
- face->underline_pixels_above_descent_line = XFIXNAT (value);
- }
- }
- }
+ realize_underline_attrs(face, cache, attrs, false);
overline = attrs[LFACE_OVERLINE_INDEX];
if (STRINGP (overline))
@@ -6373,24 +6402,26 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
specifies which color to map. Set *DEFAULTED to true if mapping to the
default foreground/background colors. */
-static void
+static unsigned long
map_tty_color (struct frame *f, struct face *face,
- enum lface_attribute_index idx, bool *defaulted)
+ enum lface_attribute_index idx, bool *defaulted,
+ Lisp_Object color)
{
- 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;
#ifdef MSDOS
unsigned long default_other_pixel =
- foreground_p ? FACE_TTY_DEFAULT_BG_COLOR : FACE_TTY_DEFAULT_FG_COLOR;
+ foreground_p ? FACE_TTY_DEFAULT_BG_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)
@@ -6419,7 +6450,7 @@ map_tty_color (struct frame *f, struct face *face,
pixel = FRAME_FOREGROUND_PIXEL (f);
else
pixel = FRAME_BACKGROUND_PIXEL (f);
- face->lface[idx] = tty_color_name (f, pixel);
+ XSETSTRING (color, tty_color_name (f, pixel));
*defaulted = true;
}
else if (pixel == default_other_pixel)
@@ -6428,20 +6459,16 @@ map_tty_color (struct frame *f, struct face *face,
pixel = FRAME_BACKGROUND_PIXEL (f);
else
pixel = FRAME_FOREGROUND_PIXEL (f);
- face->lface[idx] = tty_color_name (f, pixel);
+ XSETSTRING (color, tty_color_name (f, pixel));
*defaulted = true;
}
}
#endif /* MSDOS */
}
- if (foreground_p)
- face->foreground = pixel;
- else
- face->background = pixel;
+ return pixel;
}
-
/* 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. */
@@ -6478,9 +6505,15 @@ realize_tty_face (struct face_cache *cache,
if (!NILP (attrs[LFACE_STRIKE_THROUGH_INDEX]))
face->tty_strike_through_p = true;
+ realize_underline_attrs (face, cache, attrs, true);
+
/* 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);
+ face->foreground = map_tty_color (f, face, LFACE_FOREGROUND_INDEX,
+ &face_colors_defaulted,
+ face->lface[LFACE_FOREGROUND_INDEX]);
+ face->background = map_tty_color (f, face, LFACE_BACKGROUND_INDEX,
+ &face_colors_defaulted,
+ face->lface[LFACE_BACKGROUND_INDEX]);
/* Swap colors if face is inverse-video. If the colors are taken
from the frame colors, they are already inverted, since the
--
2.39.0
[-- Attachment #3: 0002-Allow-user-enabled-tty-underline-style-color.patch --]
[-- Type: text/x-patch, Size: 3983 bytes --]
From d232c0b209ee447ec8b40be4aacb59d339d92277 Mon Sep 17 00:00:00 2001
From: Adam Schwalm <adamschwalm@gmail.com>
Date: Mon, 19 Dec 2022 18:57:11 -0600
Subject: [PATCH 2/2] Allow user-enabled tty underline style/color
Users can now explicitly enable underline style or color support,
even if their terminal's does not seem to support it. The control
squence used when a user enables the underline color/style feature
this way is the most widely supported sequence currently. For
underline style, CSI 4 : <n> m is used and for underline color, CSI
58 : 2 :: <r> : <g> : <b> m is used (if the terminal supports 'true'
color. Otherwise, the color pallete version is used: 58 : 5 : <n> m).
---
src/term.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/src/term.c b/src/term.c
index 306c57338b..ffc5ca6fe0 100644
--- a/src/term.c
+++ b/src/term.c
@@ -115,6 +115,10 @@ #define OUTPUT1_IF(tty, a) do { if (a) emacs_tputs ((tty), a, 1, cmputc); } whil
NC_PROTECT = 1 << 7
};
+static bool term_is_24bit (struct tty_display_info *tty)
+{
+ return tty->TN_max_colors == 16777216;
+}
enum tty_underline_type
{
@@ -2280,6 +2284,56 @@ DEFUN ("controlling-tty-p", Fcontrolling_tty_p, Scontrolling_tty_p, 0, 1, 0,
return (t && !strcmp (t->display_info.tty->name, DEV_TTY) ? Qt : Qnil);
}
+DEFUN ("tty-allow-underline-color", Ftty_allow_underline_color,
+ Stty_allow_underline_color, 0, 1, 0,
+ doc: /* Declare that the tty used by TERMINAL supports underline colors.
+This is used to override the terminfo data, for certain terminals that
+support underline with colors that differ from the foreground or background
+colors, but do not specify that support in a standard way. This function has
+no effect if used on a non-tty terminal.
+
+TERMINAL can be a terminal object, a frame or nil (meaning the
+selected frame's terminal). This function always returns nil if
+TERMINAL does not refer to a text terminal. */)
+ (Lisp_Object terminal)
+{
+ struct terminal *t = decode_live_terminal (terminal);
+
+ if (t->type == output_termcap)
+ {
+ if (!t->display_info.tty->TS_set_underline_color)
+ {
+ if (term_is_24bit (t->display_info.tty))
+ t->display_info.tty->TS_set_underline_color = "\033[58:2::%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%d%;m";
+ else
+ t->display_info.tty->TS_set_underline_color = "\033[58:5:%dm";
+ }
+
+ if (!t->display_info.tty->TS_set_underline_color)
+ t->display_info.tty->TS_reset_underline_color = "\033[59m";
+ }
+ return Qnil;
+}
+
+DEFUN ("tty-allow-underline-style", Ftty_allow_underline_style,
+ Stty_allow_underline_style, 0, 1, 0,
+ doc: /* Declare that the tty used by TERMINAL supports underline styles.
+This is used to override the terminfo data, for certain terminals that
+support underline styles such as 'waves', but do not specify that support
+in a standard way. This function has no effect if used on a non-tty terminal.
+
+TERMINAL can be a terminal object, a frame or nil (meaning the
+selected frame's terminal). This function always returns nil if
+TERMINAL does not refer to a text terminal. */)
+ (Lisp_Object terminal)
+{
+ struct terminal *t = decode_live_terminal (terminal);
+
+ if (t->type == output_termcap && !t->display_info.tty->TS_set_underline_style)
+ t->display_info.tty->TS_set_underline_style = "\033[4:%p1%dm";
+ return Qnil;
+}
+
DEFUN ("tty-no-underline", Ftty_no_underline, Stty_no_underline, 0, 1, 0,
doc: /* Declare that the tty used by TERMINAL does not handle underlining.
This is used to override the terminfo data, for certain terminals that
@@ -4671,6 +4725,8 @@ syms_of_term (void)
defsubr (&Stty_display_color_p);
defsubr (&Stty_display_color_cells);
+ defsubr (&Stty_allow_underline_color);
+ defsubr (&Stty_allow_underline_style);
defsubr (&Stty_no_underline);
defsubr (&Stty_type);
defsubr (&Scontrolling_tty_p);
--
2.39.0
^ permalink raw reply related [flat|nested] 4+ messages in thread