Skip to content

Instantly share code, notes, and snippets.

@akorobov
Last active March 20, 2018 10:16
Show Gist options
  • Save akorobov/2c9f5796c661304b4d8aa64c89d2cd00 to your computer and use it in GitHub Desktop.
Save akorobov/2c9f5796c661304b4d8aa64c89d2cd00 to your computer and use it in GitHub Desktop.
Patch for emacs 25.2 (rc2) to enable 24-bit colors in terminal
diff --git a/doc/misc/efaq.texi b/doc/misc/efaq.texi
index f7a47f8..e9cfe7a 100644
--- a/doc/misc/efaq.texi
+++ b/doc/misc/efaq.texi
@@ -1491,6 +1491,39 @@ exhibits all the colors Emacs knows about on the current display.
Syntax highlighting is on by default since version 22.1.
+Emacs 26.1 and later support direct color mode in terminals. If Emacs
+finds Terminfo capabilities @samp{setb24} and @samp{setf24}, 24-bit
+direct color mode is used. The capability strings are expected to
+take one 24-bit pixel value as argument and transform the pixel to a
+string that can be used to send 24-bit colors to the terminal.
+
+There aren't yet any standard terminal type definitions that would
+support the capabilities, but Emacs can be invoked with a custom
+definition as shown below.
+
+@example
+$ cat terminfo-24bit.src
+
+# Use colon separators.
+xterm-24bit|xterm with 24-bit direct color mode,
+ use=xterm-256color,
+ setb24=\E[48:2:%p1%@{65536@}%/%d:%p1%@{256@}%/%@{255@}%&%d:%p1%@{255@}%&%dm,
+ setf24=\E[38:2:%p1%@{65536@}%/%d:%p1%@{256@}%/%@{255@}%&%d:%p1%@{255@}%&%dm,
+# Use semicolon separators.
+xterm-24bits|xterm with 24-bit direct color mode,
+ use=xterm-256color,
+ setb24=\E[48;2;%p1%@{65536@}%/%d;%p1%@{256@}%/%@{255@}%&%d;%p1%@{255@}%&%dm,
+ setf24=\E[38;2;%p1%@{65536@}%/%d;%p1%@{256@}%/%@{255@}%&%d;%p1%@{255@}%&%dm,
+
+$ tic -x -o ~/.terminfo terminfo-24bit.src
+
+$ TERM=xterm-24bit emacs -nw
+@end example
+
+Currently there's no standard way to determine whether a terminal
+supports direct color mode. If such standard arises later on, support
+for @samp{setb24} and @samp{setf24} may be removed.
+
@node Debugging a customization file
@section How do I debug a @file{.emacs} file?
@cindex Debugging @file{.emacs} file
diff --git a/lisp/term/tty-colors.el b/lisp/term/tty-colors.el
index 237aa19..f9262ae 100644
--- a/lisp/term/tty-colors.el
+++ b/lisp/term/tty-colors.el
@@ -824,6 +824,15 @@ A canonicalized color name is all-lower case, with any blanks removed."
(replace-regexp-in-string " +" "" (downcase color))
color)))
+(defun tty-color-24bit (rgb)
+ "Return pixel value on 24-bit terminals. Return nil if RGB is
+nil or not on 24-bit terminal."
+ (when (and rgb (= (display-color-cells) 16777216))
+ (let ((r (lsh (car rgb) -8))
+ (g (lsh (cadr rgb) -8))
+ (b (lsh (nth 2 rgb) -8)))
+ (logior (lsh r 16) (lsh g 8) b))))
+
(defun tty-color-define (name index &optional rgb frame)
"Specify a tty color by its NAME, terminal INDEX and RGB values.
NAME is a string, INDEX is typically a small integer used to send to
@@ -840,7 +849,10 @@ If FRAME is not specified or is nil, it defaults to the selected frame."
(and rgb (or (not (listp rgb)) (/= (length rgb) 3))))
(error "Invalid specification for tty color \"%s\"" name))
(tty-modify-color-alist
- (append (list (tty-color-canonicalize name) index) rgb) frame))
+ (append (list (tty-color-canonicalize name)
+ (or (tty-color-24bit rgb) index))
+ rgb)
+ frame))
(defun tty-color-clear (&optional _frame)
"Clear the list of supported tty colors for frame FRAME.
@@ -1013,7 +1025,10 @@ might need to be approximated if it is not supported directly."
(let ((color (tty-color-canonicalize color)))
(or (assoc color (tty-color-alist frame))
(let ((rgb (tty-color-standard-values color)))
- (and rgb (tty-color-approximate rgb frame)))))))
+ (and rgb
+ (let ((pixel (tty-color-24bit rgb)))
+ (or (and pixel (cons color (cons pixel rgb)))
+ (tty-color-approximate rgb frame)))))))))
(defun tty-color-gray-shades (&optional display)
"Return the number of gray colors supported by DISPLAY's terminal.
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index 447f536..311638b 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -917,6 +917,14 @@ versions of xterm."
;; are more colors to support, compute them now.
(when (> ncolors 0)
(cond
+ ((= ncolors 16777200) ; 24-bit xterm
+ ;; all named tty colors
+ (let ((idx (length xterm-standard-colors)))
+ (mapc (lambda (color)
+ (unless (assoc (car color) xterm-standard-colors)
+ (tty-color-define (car color) idx (cdr color))
+ (setq idx (1+ idx))))
+ color-name-rgb-alist)))
((= ncolors 240) ; 256-color xterm
;; 216 non-gray colors first
(let ((r 0) (g 0) (b 0))
diff --git a/src/term.c b/src/term.c
index 5554a00..3ec89bc 100644
--- a/src/term.c
+++ b/src/term.c
@@ -4131,6 +4131,20 @@ use the Bourne shell command 'TERM=...; export TERM' (C-shell:\n\
tty->TN_max_colors = tgetnum ("Co");
tty->TN_max_pairs = tgetnum ("pa");
+#ifdef TERMINFO
+ /* Non-standard support for 24-bit colors. */
+ {
+ const char* fg = tigetstr ("setf24");
+ const char* bg = tigetstr ("setb24");
+ if (fg && bg && fg != (char *)-1 && bg != (char *)-1)
+ {
+ tty->TS_set_foreground = fg;
+ tty->TS_set_background = bg;
+ tty->TN_max_colors = 16777216;
+ }
+ }
+#endif
+
tty->TN_no_color_video = tgetnum ("NC");
if (tty->TN_no_color_video == -1)
tty->TN_no_color_video = 0;
diff --git a/src/tparam.h b/src/tparam.h
index 15664d6..02136b6 100644
--- a/src/tparam.h
+++ b/src/tparam.h
@@ -36,4 +36,8 @@ extern char PC;
extern char *BC;
extern char *UP;
+#ifdef TERMINFO
+char *tigetstr(const char *);
+#endif
+
#endif /* EMACS_TPARAM_H */
# Replace semicolons with colons in setb24 and setf24 on terminals
# that use ITU-T separators (iTerm2). A 24-bit integer (p1) is given
# as a parameter to the control functions which calculate rgb
# component values with following formulas:
# r = p1 / 65536, g = (p1 / 256) & 255, b = p1 & 255
xterm-24bits|xterm with 16777216 colors,
use=xterm-256color,
setb24=\033[48;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%dm,
setf24=\033[38;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%dm,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment