From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: mohkale@kisara.moe Newsgroups: gmane.emacs.bugs Subject: bug#62994: [PATCH 2/3] Add support for styled underlines on tty frames Date: Fri, 21 Apr 2023 15:34:47 +0100 Message-ID: <20230421143448.339022-3-mohkale@kisara.moe> References: <20230421143448.339022-1-mohkale@kisara.moe> Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="34641"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Mohsin Kaleem To: 62994@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Fri Apr 21 16:35:44 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pprrT-0008of-7t for geb-bug-gnu-emacs@m.gmane-mx.org; Fri, 21 Apr 2023 16:35:43 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1pprr1-0005kO-04; Fri, 21 Apr 2023 10:35:15 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1pprqr-0005dL-1C for bug-gnu-emacs@gnu.org; Fri, 21 Apr 2023 10:35:05 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1pprqp-0001NM-NK for bug-gnu-emacs@gnu.org; Fri, 21 Apr 2023 10:35:04 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1pprqp-00028n-K6 for bug-gnu-emacs@gnu.org; Fri, 21 Apr 2023 10:35:03 -0400 X-Loop: help-debbugs@gnu.org Resent-From: mohkale@kisara.moe Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 21 Apr 2023 14:35:03 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 62994 X-GNU-PR-Package: emacs Original-Received: via spool by 62994-submit@debbugs.gnu.org id=B62994.16820877028214 (code B ref 62994); Fri, 21 Apr 2023 14:35:03 +0000 Original-Received: (at 62994) by debbugs.gnu.org; 21 Apr 2023 14:35:02 +0000 Original-Received: from localhost ([127.0.0.1]:40902 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pprqn-00028A-JW for submit@debbugs.gnu.org; Fri, 21 Apr 2023 10:35:02 -0400 Original-Received: from 119.ip-51-38-65.eu ([51.38.65.119]:50928 helo=mail.kisara.moe) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1pprqk-00027L-DE for 62994@debbugs.gnu.org; Fri, 21 Apr 2023 10:34:59 -0400 Original-Received: from localhost.localdomain (unknown [146.70.132.151]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by mail.kisara.moe (Postfix) with ESMTPSA id 29B47A1048; Fri, 21 Apr 2023 16:34:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kisara.moe; s=default; t=1682087697; bh=DYJ5stR2mmjQ0R3OxuHOQBosBW2qKtAgRGPApbR9KR0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HThfDmCuKEFwwQmN4LLn/BsMraHTkpyYl2g5p5KwUh0fHwJmY7EAEWZ419m/kL47b u0m73LH0y/Pi/KEUVWz1VGYT/UEW5FBqvkyxWRV4Tv5UhgLn0P2t6azoKeTMhhi2X1 MhRHC3bCXxwHHjhiODF3iJUJOs18woNzQT76PrjI1QgV9YqkIRe44w/R6xbkCAdwa7 Zt+t7G6APw1YSUkXzGQQuRe2EhheckGVit4tTb5zb/eITjDvybkGab037vxZv5I88h 8Hp6hSi5VJK94LEUcQdTZuNRFvpAxXC7dQKSeFRsVUILRMQ50gs/fDRErgzDdQPzZN VrdECm2GMXDmg== X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230421143448.339022-1-mohkale@kisara.moe> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:260393 Archived-At: From: Mohsin Kaleem * src/dispextern.h (face): Convert tty_underline_p from bool to a face_underline_type enumeration. Add a flag to check whether styled underlines are available. * src/termchar.c (tty_display_info): Add an entry for the escape sequence to set the underline style on terminal frames. * src/term.c (init_tty, tty_capable_p, turn_on_face): Read and save the underline style escape sequence from the Smulx termcap (alternatively if the Su flag is set use a default sequence). Allow checking for support of styled underlines in the current terminal frame. Output the necessary escape sequences to activate a styled underline on turn_on_face; this is currently only used for the new special underline styles, a default straight underline will still use the "us" termcap. * src/xfaces.c (tty_supports_face_attributes_p, realize_tty_face): Assert whether styled underlines are supported by the current terminal on display-supports-face-attributes-p checks. Populate the correct underline style in the face spec when realizing a face. --- etc/NEWS | 16 +++++++++++++ src/dispextern.h | 3 ++- src/term.c | 35 ++++++++++++++++++++++++---- src/termchar.h | 4 ++++ src/xfaces.c | 60 ++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 62d2fdcd3a4..9f34927dfad 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1916,6 +1916,22 @@ This command switches to the "*scratch*" buffer. If "*scratch*" doesn't exist, the command creates it first. You can use this command if you inadvertently delete the "*scratch*" buffer. +--- +** Support for 'styled-underline' face attributes on TTY frames +If your terminals termcap or terminfo database entry has the 'Su' or +'Smulx' capability defined, Emacs will now emit the prescribed escape +sequence necessary to render faces with styled underlines on TTY +frames. + +Styled underlines are any underlines containing a non-default +underline style. The available underline styles for TTY frames are +'double', 'wave', 'dotted', and 'dashed'. + +The 'Smulx' capability should define the actual sequence needed to +render styled underlines. If ommitted, but the 'Su' flag is defined, +then a default sequence will be used. It's recommended to use 'Smulx' +instead of 'Su', with priority being given to 'Smulx'. + ** Debugging --- diff --git a/src/dispextern.h b/src/dispextern.h index 1dc84e32efc..6ea6f6170e4 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1773,7 +1773,7 @@ #define FONT_TOO_HIGH(ft) \ string meaning the default color of the TTY. */ bool_bf tty_bold_p : 1; bool_bf tty_italic_p : 1; - bool_bf tty_underline_p : 1; + ENUM_BF (face_underline_type) tty_underline : 3; bool_bf tty_reverse_p : 1; bool_bf tty_strike_through_p : 1; @@ -3365,6 +3365,7 @@ #define TTY_CAP_BOLD 0x04 #define TTY_CAP_DIM 0x08 #define TTY_CAP_ITALIC 0x10 #define TTY_CAP_STRIKE_THROUGH 0x20 +#define TTY_CAP_UNDERLINE_STYLED 0x32 & TTY_CAP_UNDERLINE /*********************************************************************** diff --git a/src/term.c b/src/term.c index 53ba2a231e4..0f0393780eb 100644 --- a/src/term.c +++ b/src/term.c @@ -1948,8 +1948,17 @@ turn_on_face (struct frame *f, int face_id) 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->tty_underline && MAY_USE_WITH_COLORS_P (tty, NC_UNDERLINE)) { + if (face->tty_underline == FACE_UNDER_LINE || + !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->tty_underline, 0, 0, 0); + OUTPUT (tty, p); + xfree (p); + } + } if (face->tty_strike_through_p && MAY_USE_WITH_COLORS_P (tty, NC_STRIKE_THROUGH)) @@ -1995,7 +2004,7 @@ turn_off_face (struct frame *f, int face_id) if (face->tty_bold_p || face->tty_italic_p || face->tty_reverse_p - || face->tty_underline_p + || face->tty_underline || face->tty_strike_through_p) { OUTPUT1_IF (tty, tty->TS_exit_attribute_mode); @@ -2007,7 +2016,7 @@ 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) + if (face->tty_underline) OUTPUT_IF (tty, tty->TS_exit_underline_mode); } @@ -2036,6 +2045,9 @@ #define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \ 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, @@ -4250,6 +4262,21 @@ init_tty (const char *name, const char *terminal_type, bool must_succeed) 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")) + tty->TF_set_underline_style = "\x1b[4:%p1%dm"; + #else /* DOS_NT */ #ifdef WINDOWSNT { diff --git a/src/termchar.h b/src/termchar.h index 5c47679a994..319c2319fba 100644 --- a/src/termchar.h +++ b/src/termchar.h @@ -171,6 +171,10 @@ #define EMACS_TERMCHAR_H non-blank position. Must clear before writing _. */ int TF_teleray; /* termcap xt flag: many weird consequences. For t1061. */ + const char *TF_set_underline_style; /* termcap Smulx entry: Switches the underline + style based on the parameter. Param should + be one of: 0 (none), 1 (straight), 2 (double), + 3 (wave), 4 (dotted), or 5 (dashed). */ int RPov; /* # chars to start a TS_repeat */ diff --git a/src/xfaces.c b/src/xfaces.c index cfbb89d2ae2..2c6c554d01d 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -5408,8 +5408,18 @@ tty_supports_face_attributes_p (struct frame *f, { 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 */ + else if (EQ (CAR_SAFE (val), QCstyle)) + { + if (!(EQ (CAR_SAFE (CDR_SAFE (val)), Qline) || + EQ (CAR_SAFE (CDR_SAFE (val)), Qdouble) || + EQ (CAR_SAFE (CDR_SAFE (val)), Qwave) || + EQ (CAR_SAFE (CDR_SAFE (val)), Qdotted) || + EQ (CAR_SAFE (CDR_SAFE (val)), Qdashed))) { + return false; /* 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 @@ -6335,6 +6345,8 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] face->underline = FACE_UNDER_LINE; else if (EQ (value, Qwave)) face->underline = FACE_UNDER_WAVE; + else + face->underline = FACE_UNDER_LINE; } else if (EQ (keyword, QCposition)) { @@ -6469,6 +6481,7 @@ realize_tty_face (struct face_cache *cache, { struct face *face; int weight, slant; + Lisp_Object underline; bool face_colors_defaulted = false; struct frame *f = cache->f; @@ -6488,13 +6501,52 @@ realize_tty_face (struct face_cache *cache, 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->tty_underline = FACE_NO_UNDERLINE; + } else if (EQ (underline, Qt)) { + face->tty_underline = FACE_UNDER_LINE; + } else if (STRINGP (underline)) { + face->tty_underline = FACE_UNDER_LINE; + } else if (CONSP (underline)) { + /* `(:style STYLE)'. + STYLE being one of `line', `double', `wave', `dotted' or `dashed'. */ + face->tty_underline = FACE_UNDER_LINE; + + 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, QCstyle)) { + if (EQ (value, Qline)) + face->tty_underline = FACE_UNDER_LINE; + else if (EQ (value, Qdouble)) + face->tty_underline = FACE_DOUBLE_UNDER_LINE; + else if (EQ (value, Qwave)) + face->tty_underline = FACE_UNDER_WAVE; + else if (EQ (value, Qdotted)) + face->tty_underline = FACE_DOTTED_UNDER_LINE; + else if (EQ (value, Qdashed)) + face->tty_underline = FACE_DASHED_UNDER_LINE; + else + face->tty_underline = FACE_UNDER_LINE; + } + } + } + /* 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); -- 2.40.0