unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#45230: 27.1; Fix support for wavy underlines on terminal mode
@ 2020-12-13 22:29 Víctor Cuadrado Juan
  2020-12-14 15:29 ` Eli Zaretskii
  2022-12-23  1:36 ` bug#45230: /bug#45231: [PATCH] Support underline colors and styles in terminal Adam Schwalm
  0 siblings, 2 replies; 4+ messages in thread
From: Víctor Cuadrado Juan @ 2020-12-13 22:29 UTC (permalink / raw)
  To: 45230

[-- Attachment #1: Type: text/plain, Size: 15559 bytes --]


Support for (:underline (:style wave) when on terminal move is missing.
See src/xfaces.c, and the line:

    return false;               /* ttys can't use wave underlines */

Since ~3 years, support for curly underscores and colored underscores is
present in several terminal emulators. At least:
- Kitty: https://github.com/kovidgoyal/kitty/blob/master/protocol-extensions.asciidoc
- VTE
- iTerm2: https://gitlab.com/gnachman/iterm2/-/issues/6382

Example of implementations from other editors, such as Vim and Neovim
among others:
- https://github.com/vim/vim/issues/1306
- https://github.com/vim/vim/pull/2405
- https://github.com/neovim/neovim/issues/7479


In GNU Emacs 27.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.23, cairo version 1.16.0)
 of 2020-11-08, modified by Debian built on x86-ubc-01
System Description: Debian GNU/Linux bullseye/sid

Recent messages:
Loading /home/vic/.emacs.d/.local/cache/recentf...done
Starting new Ispell process aspell with english dictionary...done
Note: standard-indent, tab-width, evil-shift-width adjusted to 4
Session restored. Welcome back.
Wrote /home/vic/.doom.d/config.el
"config.el" 143L, 5373C written

Configured using:
 'configure --build x86_64-linux-gnu --prefix=/usr
 --sharedstatedir=/var/lib --libexecdir=/usr/lib
 --localstatedir=/var/lib --infodir=/usr/share/info
 --mandir=/usr/share/man --enable-libsystemd --with-pop=yes
 --enable-locallisppath=/etc/emacs:/usr/local/share/emacs/27.1/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/27.1/site-lisp:/usr/share/emacs/site-lisp
 --with-sound=alsa --without-gconf --with-mailutils --build
 x86_64-linux-gnu --prefix=/usr --sharedstatedir=/var/lib
 --libexecdir=/usr/lib --localstatedir=/var/lib
 --infodir=/usr/share/info --mandir=/usr/share/man --enable-libsystemd
 --with-pop=yes
 --enable-locallisppath=/etc/emacs:/usr/local/share/emacs/27.1/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/27.1/site-lisp:/usr/share/emacs/site-lisp
 --with-sound=alsa --without-gconf --with-mailutils --with-cairo
 --with-x=yes --with-x-toolkit=gtk3 --with-toolkit-scroll-bars
 'CFLAGS=-g -O2 -fdebug-prefix-map=/build/emacs-6jKC2B/emacs-27.1+1=.
 -fstack-protector-strong -Wformat -Werror=format-security -Wall'
 'CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2' LDFLAGS=-Wl,-z,relro'

Configured features:
XPM JPEG TIFF GIF PNG RSVG CAIRO SOUND GPM DBUS GSETTINGS GLIB NOTIFY
INOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE HARFBUZZ M17N_FLT LIBOTF
ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 XDBE XIM MODULES THREADS LIBSYSTEMD
JSON PDUMPER LCMS2 GMP

Important settings:
  value of $LC_MONETARY: en_DK.UTF-8
  value of $LC_NUMERIC: en_DK.UTF-8
  value of $LC_TIME: en_DK.UTF-8
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: @im=ibus
  locale-coding-system: utf-8

Major mode: Elisp

Minor modes in effect:
  evil-traces-mode: t
  git-gutter-mode: t
  whitespace-mode: t
  global-evil-surround-mode: t
  evil-surround-mode: t
  eros-mode: t
  highlight-quoted-mode: t
  rainbow-delimiters-mode: t
  display-fill-column-indicator-mode: t
  vi-tilde-fringe-mode: t
  highlight-numbers-mode: t
  display-line-numbers-mode: t
  flyspell-lazy-mode: t
  flycheck-popup-tip-mode: t
  save-place-mode: t
  global-so-long-mode: t
  which-key-mode: t
  better-jumper-mode: t
  better-jumper-local-mode: t
  global-company-mode: t
  company-mode: t
  ivy-rich-mode: t
  ivy-mode: t
  evil-goggles-mode: t
  evil-escape-mode: t
  evil-snipe-override-mode: t
  evil-snipe-mode: t
  evil-snipe-override-local-mode: t
  evil-snipe-local-mode: t
  gcmh-mode: t
  global-hl-line-mode: t
  hl-line-mode: t
  winner-mode: t
  show-paren-mode: t
  smartparens-global-mode: t
  smartparens-mode: t
  ws-butler-global-mode: t
  ws-butler-mode: t
  global-undo-fu-session-mode: t
  undo-fu-session-mode: t
  undo-fu-mode: t
  global-flycheck-mode: t
  flycheck-mode: t
  solaire-global-mode: t
  solaire-mode: t
  projectile-mode: t
  xterm-mouse-mode: t
  xclip-mode: t
  hl-todo-mode: t
  outline-minor-mode: t
  yas-minor-mode: t
  savehist-mode: t
  recentf-mode: t
  doom-modeline-mode: t
  global-git-commit-mode: t
  async-bytecomp-package-mode: t
  persp-mode: t
  flyspell-mode: t
  shell-dirtrack-mode: t
  evil-mode: t
  evil-local-mode: t
  +popup-mode: t
  general-override-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  window-divider-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  size-indication-mode: t
  column-number-mode: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
/usr/share/emacs/site-lisp/llvm-11/llvm-mode hides /usr/share/emacs/site-lisp/llvm-6.0/llvm-mode
/usr/share/emacs/site-lisp/llvm-11/tablegen-mode hides /usr/share/emacs/site-lisp/llvm-6.0/tablegen-mode
/usr/share/emacs/site-lisp/llvm-11/emacs hides /usr/share/emacs/site-lisp/llvm-6.0/emacs
/usr/share/emacs/site-lisp/llvm-11/llvm-mode hides /usr/share/emacs/site-lisp/llvm-7/llvm-mode
/usr/share/emacs/site-lisp/llvm-11/tablegen-mode hides /usr/share/emacs/site-lisp/llvm-7/tablegen-mode
/usr/share/emacs/site-lisp/llvm-11/emacs hides /usr/share/emacs/site-lisp/llvm-7/emacs
/usr/share/emacs/site-lisp/llvm-11/llvm-mode hides /usr/share/emacs/site-lisp/llvm-8/llvm-mode
/usr/share/emacs/site-lisp/llvm-11/tablegen-mode hides /usr/share/emacs/site-lisp/llvm-8/tablegen-mode
/usr/share/emacs/site-lisp/llvm-11/emacs hides /usr/share/emacs/site-lisp/llvm-8/emacs
/usr/share/emacs/site-lisp/llvm-11/llvm-mode hides /usr/share/emacs/site-lisp/llvm-9/llvm-mode
/usr/share/emacs/site-lisp/llvm-11/tablegen-mode hides /usr/share/emacs/site-lisp/llvm-9/tablegen-mode
/usr/share/emacs/site-lisp/llvm-11/emacs hides /usr/share/emacs/site-lisp/llvm-9/emacs
/usr/share/emacs/site-lisp/elpa/debian-el-37/debian-autoloads hides /usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/debian-autoloads
/usr/share/emacs/site-lisp/elpa/debian-el-37/debian-el-autoloads hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/debian-el-autoloads
/usr/share/emacs/site-lisp/elpa/debian-el-37/apt-sources hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/apt-sources
/usr/share/emacs/site-lisp/elpa/debian-el-37/debian-el hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/debian-el
/usr/share/emacs/site-lisp/elpa/debian-el-37/debian-bug hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/debian-bug
/usr/share/emacs/site-lisp/elpa/debian-el-37/debian-el-pkg hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/debian-el-pkg
/usr/share/emacs/site-lisp/elpa/debian-el-37/deb-view hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/deb-view
/usr/share/emacs/site-lisp/elpa/debian-el-37/apt-utils hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/apt-utils
/usr/share/emacs/site-lisp/elpa/debian-el-37/gnus-BTS hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/gnus-BTS
/usr/share/emacs/site-lisp/elpa/debian-el-37/preseed hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/preseed
/usr/share/emacs/site-lisp/elpa/debian-el-37/debian-autoloads hides /usr/share/emacs/site-lisp/elpa-src/debian-el-37/debian-autoloads
/usr/share/emacs/site-lisp/elpa/devscripts-40/devscripts-pkg hides /usr/share/emacs/site-lisp/elpa-src/devscripts-40/devscripts-pkg
/usr/share/emacs/site-lisp/elpa/devscripts-40/devscripts-autoloads hides /usr/share/emacs/site-lisp/elpa-src/devscripts-40/devscripts-autoloads
/usr/share/emacs/site-lisp/elpa/devscripts-40/pbuilder-mode hides /usr/share/emacs/site-lisp/elpa-src/devscripts-40/pbuilder-mode
/usr/share/emacs/site-lisp/elpa/devscripts-40/devscripts hides /usr/share/emacs/site-lisp/elpa-src/devscripts-40/devscripts
/usr/share/emacs/site-lisp/elpa/devscripts-40/pbuilder-log-view-mode hides /usr/share/emacs/site-lisp/elpa-src/devscripts-40/pbuilder-log-view-mode
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/debian-copyright hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/debian-copyright
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/readme-debian hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/readme-debian
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/dpkg-dev-el hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/dpkg-dev-el
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/debian-control-mode hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/debian-control-mode
/usr/share/emacs/site-lisp/elpa/debian-el-37/debian-autoloads hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/debian-autoloads
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/dpkg-dev-el-autoloads hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/dpkg-dev-el-autoloads
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/debian-bts-control hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/debian-bts-control
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/dpkg-dev-el-pkg hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/dpkg-dev-el-pkg
/usr/share/emacs/site-lisp/elpa/dpkg-dev-el-37.0/debian-changelog-mode hides /usr/share/emacs/site-lisp/elpa-src/dpkg-dev-el-37.0/debian-changelog-mode
/usr/share/emacs/site-lisp/latex-cjk-thai/thai-word hides /usr/share/emacs/27.1/lisp/language/thai-word

Features:
(shadow sort mail-extr emacsbug sendmail amx cursor-sensor evil-traces
evil-ex lsp-mode lsp-protocol spinner network-stream
smartparens-markdown markdown-mode edit-indirect inline ht ewoc
dash-functional bindat flycheck-golangci-lint evil-collection-go-mode
go-mode find-file ffap etags fileloop flycheck-cask git-gutter
evil-collection-vc-git vc-git jka-compr auto-minor-mode disp-table
whitespace evil-embrace evil-surround embrace expand-region
text-mode-expansions the-org-mode-expansions er-basic-expansions
expand-region-core expand-region-custom eros highlight-quoted
rainbow-delimiters display-fill-column-indicator vi-tilde-fringe
highlight-numbers parent-mode display-line-numbers flyspell-lazy
flycheck-popup-tip evil-collection-popup popup ispell flyspell
face-remap saveplace so-long evil-collection-which-key which-key
better-jumper company-capf company evil-collection-ivy ivy-avy avy
ivy-rich counsel xdg ivy-xref evil-collection-xref xref project swiper
ivy delsel ivy-faces ivy-overlay colir evil-goggles pulse
evil-easymotion evil-escape evil-snipe gcmh hl-line winner paren
smartparens-config smartparens-text smartparens ws-butler
undo-fu-session undo-fu evil-collection-flycheck flycheck
doom-themes-ext-org doom-themes-ext-treemacs solaire-mode
doom-molokai-theme doom-themes doom-themes-base projectile ibuf-ext
evil-collection-ibuffer ibuffer ibuffer-loaddefs xt-mouse xclip
evil-terminal-cursor-changer color term/tmux term/xterm xterm
org-capture org-agenda org-refile evil-collection-magit-todos
magit-todos pcre2el rxt re-builder hl-todo evil-collection-grep grep
evil-collection-compile compile orgit smartparens-org org-yt org-element
avl-tree generator org ob ob-tangle ob-ref ob-lob ob-table ob-exp
org-macro org-footnote org-src ob-comint org-pcomplete org-list
org-faces org-entities evil-collection-outline noutline outline
org-version ob-emacs-lisp ob-core ob-eval org-table ol org-keys
org-compat org-macs org-loaddefs find-func evil-collection-calendar
cal-menu calendar cal-loaddefs github-review ghub-graphql treepy gsexp
ghub url-http url-gw nsm url-auth url url-proxy url-privacy url-expand
url-methods url-history url-cookie url-domsuf url-util mailcap let-alist
gnutls deferred a evil-collection-magit magit-autoloads magit-submodule
magit-obsolete magit-popup magit-blame magit-stash magit-reflog
magit-bisect magit-push magit-pull magit-fetch magit-clone magit-remote
magit-commit magit-sequence magit-notes magit-worktree magit-tag
magit-merge magit-branch magit-reset magit-files magit-refs magit-status
magit magit-repos magit-apply magit-wip magit-log which-func
evil-collection-imenu imenu magit-diff smerge-mode diff
evil-collection-diff-mode diff-mode magit-core magit-autorevert
autorevert filenotify magit-margin magit-transient magit-process
magit-mode lv core-packages package browse-url url-handlers url-parse
auth-source json map url-vars doom-snippets doom-snippets-lib yasnippet
evil-collection-elisp-mode elisp-mode help-mode savehist recentf
tree-widget dtrt-indent doom-modeline doom-modeline-segments
doom-modeline-env doom-modeline-core shrink-path f s all-the-icons
all-the-icons-faces data-material data-weathericons data-octicons
data-fileicons data-faicons data-alltheicons memoize git-commit
with-editor transient async-bytecomp async server magit-git
magit-section eieio eieio-core eieio-loaddefs magit-utils crm
evil-collection-log-edit log-edit message rmc puny evil-collection-dired
dired dired-loaddefs format-spec rfc822 mml mml-sec password-cache
evil-collection-epa evil-collection-custom cus-edit cus-start cus-load
wid-edit evil-collection-comint evil-collection annalist epa epg
epg-config gnus-util rmail rmail-loaddefs text-property-search time-date
mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 mm-util
ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils mailheader
pcvs-util add-log dash persp-mode evil evil-integration evil-maps
evil-commands reveal evil-jumps evil-command-window evil-types
evil-search shell pcomplete comint ansi-color evil-macros evil-repeat
evil-states evil-core advice evil-common windmove thingatpt rect
evil-digraphs evil-vars ring derived core-editor core-projects core-ui
edmacro kmacro easy-mmode core-keybinds pp general cl-extra easymenu seq
byte-opt cl-seq use-package-core bytecomp byte-compile cconv
core-modules rx cl core core-lib pcase cl-macs gv cl-loaddefs cl-lib
subr-x tooltip eldoc electric uniquify ediff-hook vc-hooks
lisp-float-type mwheel term/x-win x-win term/common-win x-dnd tool-bar
dnd fontset image regexp-opt fringe tabulated-list replace newcomment
text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow
isearch timer select scroll-bar mouse jit-lock font-lock syntax facemenu
font-core term/tty-colors frame minibuffer cl-generic cham georgian
utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean
japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european
ethiopic indian cyrillic chinese composite charscript charprop
case-table epa-hook jka-cmpr-hook simple abbrev obarray cl-preloaded
nadvice loaddefs button faces cus-face macroexp files text-properties
overlay sha1 md5 base64 format env code-pages mule custom widget
hashtable-print-readable backquote threads dbusbind inotify lcms2
dynamic-setting system-font-setting font-render-setting cairo
move-toolbar gtk x-toolkit x multi-tty make-network-process emacs)

Memory information:
((conses 16 635613 661479)
 (symbols 48 47597 48)
 (strings 32 155317 57250)
 (string-bytes 1 4780813)
 (vectors 16 78376)
 (vector-slots 8 1499396 183442)
 (floats 8 1014 2781)
 (intervals 56 1418 482)
 (buffers 1000 18))

-- 
Víctor Cuadrado Juan           me@viccuad.me

PGP key ID: 4096R: 0xA2591E231E251F36
Key fingerprint: E3C5 114C 0C5B 4C49 BA03  0991 A259 1E23 1E25 1F36
My signed E-Mails are trustworthy.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* bug#45230: 27.1; Fix support for wavy underlines on terminal mode
  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 ` bug#45230: /bug#45231: [PATCH] Support underline colors and styles in terminal Adam Schwalm
  1 sibling, 0 replies; 4+ messages in thread
From: Eli Zaretskii @ 2020-12-14 15:29 UTC (permalink / raw)
  To: Víctor Cuadrado Juan; +Cc: 45230

> From: Víctor Cuadrado Juan <me@viccuad.me>
> Date: Sun, 13 Dec 2020 23:29:15 +0100
> 
> Support for (:underline (:style wave) when on terminal move is missing.
> See src/xfaces.c, and the line:
> 
>     return false;               /* ttys can't use wave underlines */
> 
> Since ~3 years, support for curly underscores and colored underscores is
> present in several terminal emulators. At least:
> - Kitty: https://github.com/kovidgoyal/kitty/blob/master/protocol-extensions.asciidoc
> - VTE
> - iTerm2: https://gitlab.com/gnachman/iterm2/-/issues/6382

Patches to support this in Emacs are welcome (although it's a pity
that these features aren't based on terminfo capabilities, AFAICT).





^ permalink raw reply	[flat|nested] 4+ messages in thread

* 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

* bug#45230: /bug#45231: [PATCH] Support underline colors and styles in terminal
  2022-12-23  1:36 ` bug#45230: /bug#45231: [PATCH] Support underline colors and styles in terminal Adam Schwalm
@ 2022-12-24  7:47   ` Eli Zaretskii
  0 siblings, 0 replies; 4+ messages in thread
From: Eli Zaretskii @ 2022-12-24  7:47 UTC (permalink / raw)
  To: Adam Schwalm; +Cc: 45230

> From: Adam Schwalm <adamschwalm@gmail.com>
> Date: Thu, 22 Dec 2022 19:36:35 -0600
> 
> 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).

I didn't see in the patches any code that would enable this feature in
the MS-Windows build of Emacs; did I miss something?

> 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.

If terminfo doesn't define these capabilities, how will we make sure
the terminal actually supports them?  Should we perhaps test the name
of the terminal?  I don't think I like just trusting the users on doing
TRT when they enable the feature by hand.

> 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, these are definitely features we'd like to have, so please do
start you legal paperwork rolling (I can send you the form if you
want/need that), so that we could accept the changes.





^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-12-24  7:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` bug#45230: /bug#45231: [PATCH] Support underline colors and styles in terminal Adam Schwalm
2022-12-24  7:47   ` Eli Zaretskii

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).