Package: emacs;
Reported by: miha <at> kamnitnik.top
Date: Sat, 25 Sep 2021 22:30:02 UTC
Severity: wishlist
Tags: patch
Found in version 27.2
Fixed in version 29.1
Done: Lars Ingebrigtsen <larsi <at> gnus.org>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: <miha <at> kamnitnik.top> To: Jim Porter <jporterbugs <at> gmail.com>, 50806 <at> debbugs.gnu.org Cc: Lars Ingebrigtsen <larsi <at> gnus.org> Subject: bug#50806: 27.2; [PATCH] Optimize ansi-color.el Date: Sun, 03 Oct 2021 21:59:25 +0200
[Message part 1 (text/plain, inline)]
>> Two less important side notes: >> >> 1) This patch additionally makes it very straight forward to add support >> for ANSI color codes 38 and 48 allowing 256-colors and 24bit >> full-color. I plan to submit such a patch later (for both ansi-color >> and term-mode). > > Glad to hear it! I was planning on doing this for Emacs 29, but if > you've already got something in mind for this, feel free to work on > it. Another thing that might be worth looking at would be improving > term.el's support for "basic" ANSI escapes; I think it only does bold, > underline, and inverse. Also, the inverse implementation seems a bit > over-complicated when it could just use the :inverse-video face > attribute instead. > Ok, thanks. I have actually already prepared patches for all these features: full-color in ansi-color.el and term.el and also "basic" ANSI escapes 1-8 for term.el that you mentioned. I guess there's no harm in sending them right now. >> 2) Two vector variables, that were recently added by Jim, were merged >> into one. Adding him as CC. > > I see you posted an updated patch that doesn't merge these vectors. I > don't have an opinion here, although if we do merge them, it would > probably be nice to get that into Emacs 28; other packages might > conceivably want to let-bind those[1]. Indeed, if we wanted to merge them we'd have to do it in Emacs 28. That's why I think its best to simply leave them un-merged. Thanks and best regards.
[0002-Add-support-for-256-color-and-24bit-ANSI-colors-in-a.patch (text/x-patch, inline)]
From cc7c1a4888b6e4dfda3a370ce357d0029b6448cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miha=20Rihtar=C5=A1i=C4=8D?= <miha <at> kamnitnik.top> Date: Sat, 2 Oct 2021 23:13:21 +0200 Subject: [PATCH 2/4] Add support for 256-color and 24bit ANSI colors in ansi-color * lisp/ansi-color.el (ansi-color--code-as-hex): New function to convert from 256-color and 24-bit ANSI codes. (ansi-color--face-vec-face): Add support for ANSI color codes greater than 16 (ansi-color--update-face-vec): Add support for ANSI codes 38 and 48 which can specify 256-color and 24bit ANSI colors. * test/lisp/ansi-color-tests.el (ansi-color-tests--strings): Add tests for ANSI codes 38 and 34 --- etc/NEWS | 7 ++++ lisp/ansi-color.el | 70 ++++++++++++++++++++++++++++------- test/lisp/ansi-color-tests.el | 12 +++++- 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 8c22230daf..e862b77563 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -65,6 +65,13 @@ binding in the menu. ** subr-x *** New macro 'with-memoization' provides a very primitive form of memoization +** ansi-color.el + +--- +*** Support for ANSI 256-color and 24-bit colors. +256-color and 24-bit color codes are now handled by ANSI color +filters and displayed with the specified color. + * New Modes and Packages in Emacs 29.1 diff --git a/lisp/ansi-color.el b/lisp/ansi-color.el index 7b46754d83..8d394f353b 100644 --- a/lisp/ansi-color.el +++ b/lisp/ansi-color.el @@ -594,22 +594,24 @@ ansi-color--face-vec-face (when-let ((fg (car colors))) (push `(:foreground - ,(face-foreground - (aref (if (or bright (>= fg 8)) - ansi-color-bright-colors-vector - ansi-color-normal-colors-vector) - (mod fg 8)) - nil 'default)) + ,(or (ansi-color--code-as-hex fg) + (face-foreground + (aref (if (or bright (>= fg 8)) + ansi-color-bright-colors-vector + ansi-color-normal-colors-vector) + (mod fg 8)) + nil 'default))) faces)) (when-let ((bg (cadr colors))) (push `(:background - ,(face-background - (aref (if (or bright (>= bg 8)) - ansi-color-bright-colors-vector - ansi-color-normal-colors-vector) - (mod bg 8)) - nil 'default)) + ,(or (ansi-color--code-as-hex bg) + (face-background + (aref (if (or bright (>= bg 8)) + ansi-color-bright-colors-vector + ansi-color-normal-colors-vector) + (mod bg 8)) + nil 'default))) faces)) (let ((i 8)) @@ -622,6 +624,32 @@ ansi-color--face-vec-face faces (car faces)))) +(defun ansi-color--code-as-hex (color) + "Convert COLOR to hexadecimal string representation. +COLOR is an ANSI color code. If it is between 16 and 255 +inclusive, it corresponds to a color from an 8-bit color cube. +If it is greater or equal than 256, it is subtracted by 256 to +directly specify a 24-bit color. + +Return a hexadecimal string, specifying the color, or nil, if +COLOR is less than 16." + (cond + ((< color 16) nil) + ((>= color 256) (format "#%06X" (- color 256))) + ((>= color 232) ;; Grayscale + (format "#%06X" (* #x010101 (+ 8 (* 10 (- color 232)))))) + (t ;; 6x6x6 color cube + (setq color (- color 16)) + (let ((res 0) + (frac (* 6 6))) + (while (<= 1 frac) ; Repeat 3 times + (setq res (* res #x000100)) + (let ((color-num (mod (/ color frac) 6))) + (unless (zerop color-num) + (setq res (+ res #x37 (* #x28 color-num))))) + (setq frac (/ frac 6))) + (format "#%06X" res))))) + ;; Working with regions (defvar-local ansi-color-context-region nil @@ -907,7 +935,23 @@ ansi-color--update-face-vec (let ((r (mod new 10)) (cell (if (memq q '(3 9)) colors (cdr colors)))) (pcase r - (8 (setq do-clear t)) + (8 + (pcase (funcall iterator) + (5 (setq new (setcar cell (funcall iterator))) + (setq do-clear (or (null new) (>= new 256)))) + (2 + (let ((red (funcall iterator)) + (green (funcall iterator)) + (blue (funcall iterator))) + (if (and red green blue + (progn + (setq new (+ (* #x010000 red) + (* #x000100 green) + (* #x000001 blue))) + (<= new #xFFFFFF))) + (setcar cell (+ 256 new)) + (setq do-clear t)))) + (_ (setq do-clear t)))) (9 (setcar cell nil)) (_ (setcar cell (+ (if (memq q '(3 4)) 0 8) r)))))) (_ (setq do-clear t))) diff --git a/test/lisp/ansi-color-tests.el b/test/lisp/ansi-color-tests.el index 953fdff893..16a1ba4a89 100644 --- a/test/lisp/ansi-color-tests.el +++ b/test/lisp/ansi-color-tests.el @@ -27,7 +27,8 @@ (defvar ansi-color-tests--strings (let ((bright-yellow (face-foreground 'ansi-color-bright-yellow nil 'default)) - (yellow (face-foreground 'ansi-color-yellow nil 'default))) + (yellow (face-foreground 'ansi-color-yellow nil 'default)) + (custom-color "#87FFFF")) `(("Hello World" "Hello World") ("\e[33mHello World\e[0m" "Hello World" (:foreground ,yellow)) @@ -51,7 +52,14 @@ ansi-color-tests--strings (ansi-color-bold (:foreground ,bright-yellow))) ("\e[1m\e[3m\e[5mbold italics blink\e[0m" "bold italics blink" (ansi-color-bold ansi-color-italic ansi-color-slow-blink)) - ("\e[10munrecognized\e[0m" "unrecognized")))) + ("\e[10munrecognized\e[0m" "unrecognized") + ("\e[38;5;3;1mHello World\e[0m" "Hello World" + (ansi-color-bold (:foreground ,yellow)) + (ansi-color-bold (:foreground ,bright-yellow))) + ("\e[48;5;123;1mHello World\e[0m" "Hello World" + (ansi-color-bold (:background ,custom-color))) + ("\e[48;2;135;255;255;1mHello World\e[0m" "Hello World" + (ansi-color-bold (:background ,custom-color)))))) (ert-deftest ansi-color-apply-on-region-test () (pcase-dolist (`(,input ,text ,face) ansi-color-tests--strings) -- 2.33.0
[0003-Add-support-for-256-color-and-24bit-ANSI-colors-in-t.patch (text/x-patch, inline)]
From ad667c79926f28c5e82654c9f99dc23f41e9375e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miha=20Rihtar=C5=A1i=C4=8D?= <miha <at> kamnitnik.top> Date: Sat, 25 Sep 2021 23:28:08 +0200 Subject: [PATCH 3/4] Add support for 256-color and 24bit ANSI colors in term-mode (term-ansi-face-already-done): Make obsolete (term--maybe-brighten-color): Remove (term--color-as-hex): New function (term-handle-colors-array): Make obsolete in favour of the new function 'term--handle-colors-list'. (term--handle-colors-list): New function, that can also handle ANSI codes 38 and 48. (term-handle-ansi-escape): Use it * test/lisp/term-tests.el (ansi-test-strings): Add tests for 256-color and 24bit ANSI colors --- etc/NEWS | 7 ++ etc/e/README | 18 +-- etc/e/eterm-color | Bin 1179 -> 1275 bytes etc/e/eterm-color.ti | 15 ++- etc/e/eterm-direct | Bin 0 -> 1354 bytes lisp/term.el | 249 +++++++++++++++++++--------------------- test/lisp/term-tests.el | 16 ++- 7 files changed, 163 insertions(+), 142 deletions(-) create mode 100644 etc/e/eterm-direct diff --git a/etc/NEWS b/etc/NEWS index e862b77563..e22eac5e75 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -72,6 +72,13 @@ binding in the menu. 256-color and 24-bit color codes are now handled by ANSI color filters and displayed with the specified color. +** term-mode + +--- +*** Support for ANSI 256-color and 24-bit colors. +256-color and 24-bit color codes are now displayed with the specified +color. + * New Modes and Packages in Emacs 29.1 diff --git a/etc/e/README b/etc/e/README index dd2c8d64e2..1293292a87 100644 --- a/etc/e/README +++ b/etc/e/README @@ -1,12 +1,12 @@ -eterm-color.ti is a terminfo source file. eterm-color is a compiled -version produced by the terminfo compiler (tic). The compiled files -are binary, and depend on the version of tic, but they seem to be -system-independent and backwardly compatible. So there should be no -need to recompile the distributed binary version. If it is -necessary, use: +eterm-color.ti is a terminfo source file. eterm-color and +eterm-direct are compiled versions produced by the terminfo compiler +(tic). The compiled files are binary, and depend on the version of +tic, but they seem to be system-independent and backwardly compatible. +So there should be no need to recompile the distributed binary +version. If it is necessary, use: tic -o ../ ./eterm-color.ti -The compiled file is used by lisp/term.el, so if it is moved term.el -needs to be changed. terminfo requires it to be stored in an 'e' -subdirectory (the first character of the file name). +The compiled files are used by lisp/term.el, so if they are moved, +term.el needs to be changed. terminfo requires them to be stored in +an 'e' subdirectory (the first character of the file name). diff --git a/etc/e/eterm-color b/etc/e/eterm-color index bd3f5003ae620db49b89a2c1387b0ba1c836f4f1..99603ba5613b822d9916df63b7c1fcc6833a038d 100644 GIT binary patch delta 160 zcmbQu`J0nliqV~c9|$uUS5D+EWMN?ZU%#>80uy8A=0IjW#u|Io0z=hmi&|A1)e>V6 tJ4H1WEM#Z~7PExO>w;vAEv!wgA*!r%8Kk3Ck+qv((QasfqTd8XKLBEMDcJx3 delta 64 zcmey(Ih&JPiqV~c9|$uUJtuM(vT!gsFl=nNz{F^^IgnY8QKrC9wc6OAR#jUyC6_ <at> u MS{2Aw*HDLW0nn2UQ~&?~ diff --git a/etc/e/eterm-color.ti b/etc/e/eterm-color.ti index a6ef814990..61c29e6dcc 100644 --- a/etc/e/eterm-color.ti +++ b/etc/e/eterm-color.ti @@ -9,10 +9,10 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96, # Any change to this file should be done at the same time with a # corresponding change to the TERMCAP environment variable in term.el. # Comments in term.el specify where each of these capabilities is implemented. - colors#8, + colors#256, cols#80, lines#24, - pairs#64, + pairs#32767, am, mir, msgr, @@ -65,8 +65,8 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96, rmul=\E[24m, rs1=\Ec, sc=\E7, - setab=\E[%p1%{40}%+%dm, - setaf=\E[%p1%{30}%+%dm, + setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, + setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, sgr0=\E[m, smir=\E[4h, smul=\E[4m, @@ -76,3 +76,10 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96, # smcup=\E[?47h, # rmcup=\E[?47l, # rs2 may need to be added + +eterm-direct|Emacs term.el with direct-color indexing term-protocol-version 0.96, + use=eterm-color, + colors#0x1000000, + pairs#0x10000, + setab=\E[%?%p1%{8}%<%t4%p1%d%e48;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%d%;m, + setaf=\E[%?%p1%{8}%<%t3%p1%d%e38;2;%p1%{65536}%/%d;%p1%{256}%/%{255}%&%d;%p1%{255}%&%d%;m, diff --git a/etc/e/eterm-direct b/etc/e/eterm-direct new file mode 100644 index 0000000000000000000000000000000000000000..35983ec8aded7b0c6b818df47abe57b9440934cb GIT binary patch literal 1354 zcmcgoJ!lkB5T18LqCpW0LD(QG_$&e!z5Tm8HbJ8aM9q<y#^P+k?P?b9Zja4kLgJ}~ z*jU)uq_DBEu&}jFYZXXqYilb6!urkJo~H&hA>!MenQy-Nd-Kj0?$Bv`k=j;a8YZn` z5G7$FeLT}zYOI*djE7BgHA<JwUZmKFn{i <at> B?I2u>+7Be9*h%6vMxgj8Oje?}ZC)9# zdPGWolB3iDY=(0#w~YUGkSa~GjHp0Es6R`iWJ;fl<Wd>P7jF`J3Nk}C#plko94*pa zpnJ4L_l0>VI;ND?^Nhhgo`HFuvoBy@?#meDX4xxxjrb<y4ZWpzdG7l^*7WK>&_~*$ zPsrS%&-4ZM>u*)xa(@?g5ARS=y~<;`{rMgT#luIaJ?M=8n|Jb%8=X<3QgPvsb^mg! zG1XPWbc&3+j&!G_17CM69V8%TjruK^+Yq+D#Aj)QGw3+<4agK^0aAmMT2Rh1RE1Ib zhjJK6unAyEz!Gwfo`SKTkTHK9paf92*qa9M*mK##q<Nks7v*sRYJI?^!d&Zvxjx`N z65`7WK%WK~6*9`aN{vn+;P9jpFN|gJ62T&%*M_pIzEkC^>#JP7QR(Ulo!Zh#hjzuc keBnLUwY{#sEboXs%M}mS?dnSdw&!VoUrQ%%=^UZucQ(5!9smFU literal 0 HcmV?d00001 diff --git a/lisp/term.el b/lisp/term.el index e76eb77647..771b73238f 100644 --- a/lisp/term.el +++ b/lisp/term.el @@ -303,6 +303,7 @@ term-protocol-version (require 'ange-ftp) (require 'cl-lib)) (require 'comint) ; Password regexp. +(require 'ansi-color) (require 'ehelp) (require 'ring) (require 'shell) @@ -717,6 +718,9 @@ term-ansi-current-underline (defvar term-ansi-current-reverse nil) (defvar term-ansi-current-invisible nil) +(make-obsolete-variable 'term-ansi-face-already-done + "it doesn't have any effect." "28.1") + ;;; Faces (defvar ansi-term-color-vector [term @@ -1039,10 +1043,6 @@ term-ansi-reset (setq term-ansi-current-reverse nil) (setq term-ansi-current-color 0) (setq term-ansi-current-invisible nil) - ;; Stefan thought this should be t, but could not remember why. - ;; Setting it to t seems to cause bug#11785. Setting it to nil - ;; again to see if there are other consequences... - (setq term-ansi-face-already-done nil) (setq term-ansi-current-bg-color 0)) (define-derived-mode term-mode fundamental-mode "Term" @@ -1584,7 +1584,8 @@ term-termcap-format :so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:md=\\E[1m:mr=\\E[7m:me=\\E[m\ :UP=\\E[%%dA:DO=\\E[%%dB:LE=\\E[%%dD:RI=\\E[%%dC\ :kl=\\EOD:kd=\\EOB:kr=\\EOC:ku=\\EOA:kN=\\E[6~:kP=\\E[5~:@7=\\E[4~:kh=\\E[1~\ -:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#8:pa#64:AB=\\E[4%%dm:AF=\\E[3%%dm:cr=^M\ +:mk=\\E[8m:cb=\\E[1K:op=\\E[39;49m:Co#256:pa#32767\ +:AB=\\E[48;5;%%dm:AF=\\E[38;5;%%dm:cr=^M\ :bl=^G:do=^J:le=^H:ta=^I:se=\\E[27m:ue=\\E[24m\ :kb=^?:kD=^[[3~:sc=\\E7:rc=\\E8:r1=\\Ec:" ;; : -undefine ic @@ -3285,133 +3286,125 @@ term-reset-terminal (setq term-current-row 0) (setq term-current-column 1) (term--reset-scroll-region) - (setq term-insert-mode nil) - ;; FIXME: No idea why this is here, it looks wrong. --Stef - (setq term-ansi-face-already-done nil)) - -(defun term--maybe-brighten-color (color bold) - "Possibly convert COLOR to its bright variant. -COLOR is an index into `ansi-term-color-vector'. If BOLD and -`ansi-color-bold-is-bright' are non-nil and COLOR is a regular color, -return the bright version of COLOR; otherwise, return COLOR." - (if (and ansi-color-bold-is-bright bold (<= 1 color 8)) - (+ color 8) - color)) + (setq term-insert-mode nil)) + +(defun term--color-as-hex (for-foreground) + "Return the current ANSI color as a hexadecimal color string. +Use the current background color if FOR-FOREGROUND is nil, +otherwise use the current foreground color." + (let ((color (if for-foreground term-ansi-current-color + term-ansi-current-bg-color))) + (or (ansi-color--code-as-hex (1- color)) + (progn + (and ansi-color-bold-is-bright term-ansi-current-bold + (<= 1 color 8) + (setq color (+ color 8))) + (if for-foreground + (face-foreground (elt ansi-term-color-vector color) + nil 'default) + (face-background (elt ansi-term-color-vector color) + nil 'default)))))) ;; New function to deal with ansi colorized output, as you can see you can ;; have any bold/underline/fg/bg/reverse combination. -mm (defun term-handle-colors-array (parameter) - (cond - - ;; Bold (terminfo: bold) - ((eq parameter 1) - (setq term-ansi-current-bold t)) - - ;; Underline - ((eq parameter 4) - (setq term-ansi-current-underline t)) - - ;; Blink (unsupported by Emacs), will be translated to bold. - ;; This may change in the future though. - ((eq parameter 5) - (setq term-ansi-current-bold t)) - - ;; Reverse (terminfo: smso) - ((eq parameter 7) - (setq term-ansi-current-reverse t)) - - ;; Invisible - ((eq parameter 8) - (setq term-ansi-current-invisible t)) - - ;; Reset underline (terminfo: rmul) - ((eq parameter 24) - (setq term-ansi-current-underline nil)) - - ;; Reset reverse (terminfo: rmso) - ((eq parameter 27) - (setq term-ansi-current-reverse nil)) - - ;; Foreground - ((and (>= parameter 30) (<= parameter 37)) - (setq term-ansi-current-color (- parameter 29))) - - ;; Bright foreground - ((and (>= parameter 90) (<= parameter 97)) - (setq term-ansi-current-color (- parameter 81))) - - ;; Reset foreground - ((eq parameter 39) - (setq term-ansi-current-color 0)) - - ;; Background - ((and (>= parameter 40) (<= parameter 47)) - (setq term-ansi-current-bg-color (- parameter 39))) - - ;; Bright foreground - ((and (>= parameter 100) (<= parameter 107)) - (setq term-ansi-current-bg-color (- parameter 91))) - - ;; Reset background - ((eq parameter 49) - (setq term-ansi-current-bg-color 0)) - - ;; 0 (Reset) or unknown (reset anyway) - (t - (term-ansi-reset))) - - ;; (message "Debug: U-%d R-%d B-%d I-%d D-%d F-%d B-%d" - ;; term-ansi-current-underline - ;; term-ansi-current-reverse - ;; term-ansi-current-bold - ;; term-ansi-current-invisible - ;; term-ansi-face-already-done - ;; term-ansi-current-color - ;; term-ansi-current-bg-color) - - (unless term-ansi-face-already-done - (let ((current-color (term--maybe-brighten-color - term-ansi-current-color - term-ansi-current-bold)) - (current-bg-color (term--maybe-brighten-color - term-ansi-current-bg-color - term-ansi-current-bold))) - (if term-ansi-current-invisible - (let ((color - (if term-ansi-current-reverse - (face-foreground - (elt ansi-term-color-vector current-color) - nil 'default) - (face-background - (elt ansi-term-color-vector current-bg-color) - nil 'default)))) - (setq term-current-face - (list :background color - :foreground color)) - ) ;; No need to bother with anything else if it's invisible. - (setq term-current-face - (list :foreground - (face-foreground - (elt ansi-term-color-vector current-color) - nil 'default) - :background - (face-background - (elt ansi-term-color-vector current-bg-color) - nil 'default) - :inverse-video term-ansi-current-reverse)) - - (when term-ansi-current-bold - (setq term-current-face - `(,term-current-face :inherit term-bold))) - - (when term-ansi-current-underline - (setq term-current-face - `(,term-current-face :inherit term-underline)))))) - - ;; (message "Debug %S" term-current-face) - ;; FIXME: shouldn't we set term-ansi-face-already-done to t here? --Stef - (setq term-ansi-face-already-done nil)) + (declare (obsolete term--handle-colors-list "28.1")) + (term--handle-colors-list (list parameter))) + +(defun term--handle-colors-list (parameters) + (while parameters + (pcase (pop parameters) + (1 (setq term-ansi-current-bold t)) ; (terminfo: bold) + (4 (setq term-ansi-current-underline t)) ; (terminfo: smul) + (5 (setq term-ansi-current-bold t)) ; (terminfo: bold) + (7 (setq term-ansi-current-reverse t)) ; (terminfo: smso, rev) + (8 (setq term-ansi-current-invisible t)) ; (terminfo: invis) + (24 (setq term-ansi-current-underline nil)) ; (terminfo: rmul) + (27 (setq term-ansi-current-reverse nil)) ; (terminfo: rmso) + + ;; Foreground (terminfo: setaf) + ((and param (guard (<= 30 param 37))) + (setq term-ansi-current-color (- param 29))) + + ;; Bright foreground (terminfo: setaf) + ((and param (guard (<= 90 param 97))) + (setq term-ansi-current-color (- param 81))) + + ;; Extended foreground (terminfo: setaf) + (38 + (pcase (pop parameters) + ;; 256 color + (5 (if (setq term-ansi-current-color (pop parameters)) + (cl-incf term-ansi-current-color) + (term-ansi-reset))) + ;; Full 24-bit color + (2 (cl-loop with color = (1+ 256) ; Base + for i from 16 downto 0 by 8 + if (pop parameters) + do (setq color (+ color (ash it i))) + else return (term-ansi-reset) + finally + (if (> color (+ 1 256 #xFFFFFF)) + (term-ansi-reset) + (setq term-ansi-current-color color)))) + (_ (term-ansi-reset)))) + + ;; Reset foreground (terminfo: op) + (39 (setq term-ansi-current-color 0)) + + ;; Background (terminfo: setab) + ((and param (guard (<= 40 param 47))) + (setq term-ansi-current-bg-color (- param 39))) + + ;; Bright background (terminfo: setab) + ((and param (guard (<= 100 param 107))) + (setq term-ansi-current-bg-color (- param 91))) + + ;; Extended background (terminfo: setab) + (48 + (pcase (pop parameters) + ;; 256 color + (5 (if (setq term-ansi-current-bg-color (pop parameters)) + (cl-incf term-ansi-current-bg-color) + (term-ansi-reset))) + ;; Full 24-bit color + (2 (cl-loop with color = (1+ 256) ; Base + for i from 16 downto 0 by 8 + if (pop parameters) + do (setq color (+ color (ash it i))) + else return (term-ansi-reset) + finally + (if (> color (+ 1 256 #xFFFFFF)) + (term-ansi-reset) + (setq term-ansi-current-bg-color color)))) + (_ (term-ansi-reset)))) + + ;; Reset background (terminfo: op) + (49 (setq term-ansi-current-bg-color 0)) + + ;; 0 (Reset) (terminfo: sgr0) or unknown (reset anyway) + (_ (term-ansi-reset)))) + + (let (fg bg) + (if term-ansi-current-invisible + (setq bg (term--color-as-hex term-ansi-current-reverse) + fg bg) + (setq fg (term--color-as-hex t) + bg (term--color-as-hex nil))) + (setq term-current-face + `( :foreground ,fg + :background ,bg + ,@(unless term-ansi-current-invisible + (list :inverse-video term-ansi-current-reverse))))) + + (when term-ansi-current-bold + (setq term-current-face + `(,term-current-face :inherit term-bold))) + + (when term-ansi-current-underline + (setq term-current-face + `(,term-current-face :inherit term-underline)))) ;; Handle a character assuming (eq terminal-state 2) - @@ -3499,7 +3492,7 @@ term-handle-ansi-escape ;; \E[m - Set/reset modes, set bg/fg ;;(terminfo: smso,rmso,smul,rmul,rev,bold,sgr0,invis,op,setab,setaf) ((eq char ?m) - (mapc #'term-handle-colors-array params)) + (term--handle-colors-list params)) ;; \E[6n - Report cursor position (terminfo: u7) ((eq char ?n) diff --git a/test/lisp/term-tests.el b/test/lisp/term-tests.el index 96b6d73488..b8adc62c9d 100644 --- a/test/lisp/term-tests.el +++ b/test/lisp/term-tests.el @@ -42,6 +42,9 @@ bright-yellow-bg-props `( :foreground "unspecified-fg" :background ,(face-background 'term-color-bright-yellow nil 'default) :inverse-video nil)) +(defvar custom-color-fg-props + `( :foreground "#87FFFF" + :background "unspecified-bg" :inverse-video nil)) (defvar ansi-test-strings `(("\e[33mHello World\e[0m" @@ -71,7 +74,18 @@ ansi-test-strings ,(propertize "Hello World" 'font-lock-face `(,yellow-fg-props :inherit term-bold)) ,(propertize "Hello World" 'font-lock-face - `(,bright-yellow-fg-props :inherit term-bold))))) + `(,bright-yellow-fg-props :inherit term-bold))) + ("\e[38;5;3;1mHello World\e[0m" + ,(propertize "Hello World" 'font-lock-face + `(,yellow-fg-props :inherit term-bold)) + ,(propertize "Hello World" 'font-lock-face + `(,bright-yellow-fg-props :inherit term-bold))) + ("\e[38;5;123;1mHello World\e[0m" + ,(propertize "Hello World" 'font-lock-face + `(,custom-color-fg-props :inherit term-bold))) + ("\e[38;2;135;255;255;1mHello World\e[0m" + ,(propertize "Hello World" 'font-lock-face + `(,custom-color-fg-props :inherit term-bold))))) (defun term-test-screen-from-input (width height input &optional return-var) (with-temp-buffer -- 2.33.0
[0004-In-term-mode-handle-ANSI-codes-specifying-italic-and.patch (text/x-patch, inline)]
From d1b256c98b658231cc4bbec83c7e3c2a44601dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miha=20Rihtar=C5=A1i=C4=8D?= <miha <at> kamnitnik.top> Date: Mon, 27 Sep 2021 15:15:57 +0200 Subject: [PATCH 4/4] In term-mode, handle ANSI codes, specifying italic and other modes * etc/e/eterm-color.ti: Add new capabilities * lisp/term.el: New faces and variables to support new ANSI modes. (term-termcap-format): Add new capabilities (term-emulate-terminal): When saving cursor, additionally save the new variables. (term--handle-colors-list): Handle ANSI codes, specifying italic other modes. * test/lisp/term-tests.el (ansi-test-strings): Adjust tests. --- etc/NEWS | 8 +-- etc/e/eterm-color | Bin 1275 -> 1296 bytes etc/e/eterm-color.ti | 4 ++ etc/e/eterm-direct | Bin 1354 -> 1375 bytes lisp/term.el | 105 ++++++++++++++++++++++++++++++---------- test/lisp/term-tests.el | 32 ++++++------ 6 files changed, 104 insertions(+), 45 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index e22eac5e75..4b6a25c1e7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -75,9 +75,11 @@ filters and displayed with the specified color. ** term-mode --- -*** Support for ANSI 256-color and 24-bit colors. -256-color and 24-bit color codes are now displayed with the specified -color. +*** Support for ANSI 256-color and 24-bit colors, italic and other fonts. +Term-mode can now display 256-color and 24-bit color codes. It can +also handle ANSI codes for faint, italic and blinking text, displaying +it with new 'ansi-term-faint/italic/slow-blinking/fast-blinking' +faces. * New Modes and Packages in Emacs 29.1 diff --git a/etc/e/eterm-color b/etc/e/eterm-color index 99603ba5613b822d9916df63b7c1fcc6833a038d..bf44fa0f36de0f6681fa3172db13a83c414aa42a 100644 GIT binary patch delta 286 zcmey(If08?iqV~c9|$uU_f6zp>EX)|#PA;o!Wm*15`nBVhHQocut+JGtYoNTXaTc8 zs$ifCDAETNodBe#GE6pPl#!UpFb~LC48+SB)-Y^@D%i>}c_O2d%}$0x45t~c00r+d zJY#qdq<=saz)WRigs <at> nEG&>^~BM+3%&p7!aqZN}Nh&nl0fRUX^j1g$09+xzu8d!-o zBhY#&F%zhIn0X-D5~RtC*`Bd(av*a6w`neebhIIeFq*uG`3}1=m}xw <at> ilq?%rk#|p delta 241 zcmbQh^_!DhiqV~c9|$uUS5D+!>GA)+FT;N <at> 2x15avSJt#8PdQa*<doCp <at> g9dssf <at> 8 zL^c3LTA-qBK)Rb <at> vLU04L_fn6AZI2J&t+J|upFvjHN)hIj7m1^8FnxnWH<#Byv%Ti z;VF=Q2UP$w_dAsT3rPQEU|?iogvhWmPQJ)!#l#MxPEHnJWM|@G1RANwCCDfPR-y=! Ysbbb*%$yv^9KdKec <at> 6WO$&*=X0X>z1egFUf diff --git a/etc/e/eterm-color.ti b/etc/e/eterm-color.ti index 61c29e6dcc..eeb9b0b6e6 100644 --- a/etc/e/eterm-color.ti +++ b/etc/e/eterm-color.ti @@ -18,6 +18,7 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96, msgr, xenl, bel=^G, + blink=\E[5m, bold=\E[1m, clear=\E[H\E[J, cr=\r, @@ -31,6 +32,7 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96, cup=\E[%i%p1%d;%p2%dH, cuu1=\E[A, cuu=\E[%p1%dA, + dim=\E[2m, dch1=\E[P, dch=\E[%p1%dP, dl1=\E[M, @@ -60,6 +62,7 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96, rc=\E8, rev=\E[7m, ri=\EM, + ritm=\E[23m, rmir=\E[4l, rmso=\E[27m, rmul=\E[24m, @@ -68,6 +71,7 @@ eterm-color|Emacs term.el terminal emulator term-protocol-version 0.96, setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, sgr0=\E[m, + sitm=\E[3m, smir=\E[4h, smul=\E[4m, smso=\E[7m, diff --git a/etc/e/eterm-direct b/etc/e/eterm-direct index 35983ec8aded7b0c6b818df47abe57b9440934cb..c113c3713693b948ae9d52e75df5d89957fd0c77 100644 GIT binary patch delta 262 zcmX <at> bb)Sn{jwz6V9|$uUpHAey=;6x{#PA;o!Wm*15`nBVhHQocut+JGtYoNTXaTc8 zs$ifCDAETNodBe#GE8igk(kLa56E5&#LF4hFl>a%Z)KQ#kWtBcC&M9z(+pRDf_E97 zF}w%TKcEU=hB7ijSS&!Aoso-?2g>K4{E^X`Q4mO8WE2CE`kc~?YG65SAWxdn1V{=q oS^`OLW_!j-lPj46xJ`2zq <at> xW%gwf<v%y-z0!A#@Hi&$0w0G2X_$p8QV delta 232 zcmcc5b&88yjwz6V9|$uUFHGdV=<)x*FT;N <at> 2x15avSJt#8PdQa*<doCp <at> g9dssf <at> 8 zL^c3LTA-qBK)Rb <at> Vxx>iKf <at> FtdnORiWmv?p94fz>Ve&ynCF}JJI~Wc!oB|47X1K%f z6iB~=Du5aL9m <at> X&r2jH7FfuVhWLPJEWVB{v2a*>Vd4Qxory!#YSWXeht7g_>tesrR R9KdKe`3m!$$-7yW000mDghK!T diff --git a/lisp/term.el b/lisp/term.el index 771b73238f..ce086c379b 100644 --- a/lisp/term.el +++ b/lisp/term.el @@ -711,10 +711,14 @@ term-ansi-at-save-user (defvar term-ansi-at-save-pwd nil) (defvar term-ansi-at-save-anon nil) (defvar term-ansi-current-bold nil) +(defvar term-ansi-current-faint nil) +(defvar term-ansi-current-italic nil) +(defvar term-ansi-current-underline nil) +(defvar term-ansi-current-slow-blink nil) +(defvar term-ansi-current-fast-blink nil) (defvar term-ansi-current-color 0) (defvar term-ansi-face-already-done nil) (defvar term-ansi-current-bg-color 0) -(defvar term-ansi-current-underline nil) (defvar term-ansi-current-reverse nil) (defvar term-ansi-current-invisible nil) @@ -769,12 +773,36 @@ term-bold :group 'term :version "28.1") +(defface term-faint + '((t :inherit ansi-color-faint)) + "Default face to use for faint text." + :group 'term + :version "28.1") + +(defface term-italic + '((t :inherit ansi-color-italic)) + "Default face to use for italic text." + :group 'term + :version "28.1") + (defface term-underline '((t :inherit ansi-color-underline)) "Default face to use for underlined text." :group 'term :version "28.1") +(defface term-slow-blink + '((t :inherit ansi-color-slow-blink)) + "Default face to use for slowly blinking text." + :group 'term + :version "28.1") + +(defface term-fast-blink + '((t :inherit ansi-color-fast-blink)) + "Default face to use for rapidly blinking text." + :group 'term + :version "28.1") + (defface term-color-black '((t :inherit ansi-color-black)) "Face used to render black color code." @@ -1038,8 +1066,12 @@ term-display-table (defun term-ansi-reset () (setq term-current-face 'term) - (setq term-ansi-current-underline nil) (setq term-ansi-current-bold nil) + (setq term-ansi-current-faint nil) + (setq term-ansi-current-italic nil) + (setq term-ansi-current-underline nil) + (setq term-ansi-current-slow-blink nil) + (setq term-ansi-current-fast-blink nil) (setq term-ansi-current-reverse nil) (setq term-ansi-current-color 0) (setq term-ansi-current-invisible nil) @@ -1581,6 +1613,7 @@ term-termcap-format :nd=\\E[C:up=\\E[A:ce=\\E[K:ho=\\E[H:pt\ :al=\\E[L:dl=\\E[M:DL=\\E[%%dM:AL=\\E[%%dL:cs=\\E[%%i%%d;%%dr:sf=^J\ :dc=\\E[P:DC=\\E[%%dP:IC=\\E[%%d@:im=\\E[4h:ei=\\E[4l:mi:\ +:mb=\\E[5m:mh=\\E[2m:ZR=\\E[23m:ZH=\\E[3m\ :so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:md=\\E[1m:mr=\\E[7m:me=\\E[m\ :UP=\\E[%%dA:DO=\\E[%%dB:LE=\\E[%%dD:RI=\\E[%%dC\ :kl=\\EOD:kd=\\EOB:kr=\\EOC:ku=\\EOA:kN=\\E[6~:kP=\\E[5~:@7=\\E[4~:kh=\\E[1~\ @@ -3105,30 +3138,34 @@ term-emulate-terminal (term-horizontal-column) term-ansi-current-bg-color term-ansi-current-bold + term-ansi-current-faint + term-ansi-current-italic + term-ansi-current-underline + term-ansi-current-slow-blink + term-ansi-current-fast-blink term-ansi-current-color term-ansi-current-invisible term-ansi-current-reverse - term-ansi-current-underline term-current-face))) (?8 ;; Restore cursor (terminfo: rc, [ctlseqs] ;; "DECRC"). (when term-saved-cursor (term-goto (nth 0 term-saved-cursor) (nth 1 term-saved-cursor)) - (setq term-ansi-current-bg-color - (nth 2 term-saved-cursor) - term-ansi-current-bold - (nth 3 term-saved-cursor) - term-ansi-current-color - (nth 4 term-saved-cursor) - term-ansi-current-invisible - (nth 5 term-saved-cursor) - term-ansi-current-reverse - (nth 6 term-saved-cursor) - term-ansi-current-underline - (nth 7 term-saved-cursor) - term-current-face - (nth 8 term-saved-cursor)))) + (pcase-setq + `( ,_ ,_ + ,term-ansi-current-bg-color + ,term-ansi-current-bold + ,term-ansi-current-faint + ,term-ansi-current-italic + ,term-ansi-current-underline + ,term-ansi-current-slow-blink + ,term-ansi-current-fast-blink + ,term-ansi-current-color + ,term-ansi-current-invisible + ,term-ansi-current-reverse + ,term-current-face) + term-saved-cursor))) (?c ;; \Ec - Reset (terminfo: rs1, [ctlseqs] "RIS"). ;; This is used by the "clear" program. (term-reset-terminal)) @@ -3316,11 +3353,20 @@ term--handle-colors-list (while parameters (pcase (pop parameters) (1 (setq term-ansi-current-bold t)) ; (terminfo: bold) + (2 (setq term-ansi-current-faint t)) ; (terminfo: dim) + (3 (setq term-ansi-current-italic t)) ; (terminfo: sitm) (4 (setq term-ansi-current-underline t)) ; (terminfo: smul) - (5 (setq term-ansi-current-bold t)) ; (terminfo: bold) + (5 (setq term-ansi-current-slow-blink t)) ; (terminfo: blink) + (6 (setq term-ansi-current-fast-blink t)) (7 (setq term-ansi-current-reverse t)) ; (terminfo: smso, rev) (8 (setq term-ansi-current-invisible t)) ; (terminfo: invis) + (21 (setq term-ansi-current-bold nil)) + (22 (setq term-ansi-current-bold nil) + (setq term-ansi-current-faint nil)) + (23 (setq term-ansi-current-italic nil)) ; (terminfo: ritm) (24 (setq term-ansi-current-underline nil)) ; (terminfo: rmul) + (25 (setq term-ansi-current-slow-blink nil) + (setq term-ansi-current-fast-blink nil)) (27 (setq term-ansi-current-reverse nil)) ; (terminfo: rmso) ;; Foreground (terminfo: setaf) @@ -3398,13 +3444,20 @@ term--handle-colors-list ,@(unless term-ansi-current-invisible (list :inverse-video term-ansi-current-reverse))))) - (when term-ansi-current-bold - (setq term-current-face - `(,term-current-face :inherit term-bold))) - - (when term-ansi-current-underline - (setq term-current-face - `(,term-current-face :inherit term-underline)))) + (setq term-current-face + `(,term-current-face + ,@(when term-ansi-current-bold + '(term-bold)) + ,@(when term-ansi-current-faint + '(term-faint)) + ,@(when term-ansi-current-italic + '(term-italic)) + ,@(when term-ansi-current-underline + '(term-underline)) + ,@(when term-ansi-current-slow-blink + '(term-slow-blink)) + ,@(when term-ansi-current-fast-blink + '(term-fast-blink))))) ;; Handle a character assuming (eq terminal-state 2) - @@ -3490,7 +3543,7 @@ term-handle-ansi-escape ;; Modified to allow ansi coloring -mm ;; \E[m - Set/reset modes, set bg/fg - ;;(terminfo: smso,rmso,smul,rmul,rev,bold,sgr0,invis,op,setab,setaf) + ;;(terminfo: smso,rmso,smul,rmul,rev,bold,dim,sitm,ritm,blink,sgr0,invis,op,setab,setaf) ((eq char ?m) (term--handle-colors-list params)) diff --git a/test/lisp/term-tests.el b/test/lisp/term-tests.el index b8adc62c9d..73d39cf3b6 100644 --- a/test/lisp/term-tests.el +++ b/test/lisp/term-tests.el @@ -48,44 +48,44 @@ custom-color-fg-props (defvar ansi-test-strings `(("\e[33mHello World\e[0m" - ,(propertize "Hello World" 'font-lock-face yellow-fg-props)) + ,(propertize "Hello World" 'font-lock-face `(,yellow-fg-props))) ("\e[43mHello World\e[0m" - ,(propertize "Hello World" 'font-lock-face yellow-bg-props)) + ,(propertize "Hello World" 'font-lock-face `(,yellow-bg-props))) ("\e[93mHello World\e[0m" - ,(propertize "Hello World" 'font-lock-face bright-yellow-fg-props)) + ,(propertize "Hello World" 'font-lock-face `(,bright-yellow-fg-props))) ("\e[103mHello World\e[0m" - ,(propertize "Hello World" 'font-lock-face bright-yellow-bg-props)) + ,(propertize "Hello World" 'font-lock-face `(,bright-yellow-bg-props))) ("\e[1;33mHello World\e[0m" ,(propertize "Hello World" 'font-lock-face - `(,yellow-fg-props :inherit term-bold)) + `(,yellow-fg-props term-bold)) ,(propertize "Hello World" 'font-lock-face - `(,bright-yellow-fg-props :inherit term-bold))) + `(,bright-yellow-fg-props term-bold))) ("\e[33;1mHello World\e[0m" ,(propertize "Hello World" 'font-lock-face - `(,yellow-fg-props :inherit term-bold)) + `(,yellow-fg-props term-bold)) ,(propertize "Hello World" 'font-lock-face - `(,bright-yellow-fg-props :inherit term-bold))) + `(,bright-yellow-fg-props term-bold))) ("\e[1m\e[33mHello World\e[0m" ,(propertize "Hello World" 'font-lock-face - `(,yellow-fg-props :inherit term-bold)) + `(,yellow-fg-props term-bold)) ,(propertize "Hello World" 'font-lock-face - `(,bright-yellow-fg-props :inherit term-bold))) + `(,bright-yellow-fg-props term-bold))) ("\e[33m\e[1mHello World\e[0m" ,(propertize "Hello World" 'font-lock-face - `(,yellow-fg-props :inherit term-bold)) + `(,yellow-fg-props term-bold)) ,(propertize "Hello World" 'font-lock-face - `(,bright-yellow-fg-props :inherit term-bold))) + `(,bright-yellow-fg-props term-bold))) ("\e[38;5;3;1mHello World\e[0m" ,(propertize "Hello World" 'font-lock-face - `(,yellow-fg-props :inherit term-bold)) + `(,yellow-fg-props term-bold)) ,(propertize "Hello World" 'font-lock-face - `(,bright-yellow-fg-props :inherit term-bold))) + `(,bright-yellow-fg-props term-bold))) ("\e[38;5;123;1mHello World\e[0m" ,(propertize "Hello World" 'font-lock-face - `(,custom-color-fg-props :inherit term-bold))) + `(,custom-color-fg-props term-bold))) ("\e[38;2;135;255;255;1mHello World\e[0m" ,(propertize "Hello World" 'font-lock-face - `(,custom-color-fg-props :inherit term-bold))))) + `(,custom-color-fg-props term-bold))))) (defun term-test-screen-from-input (width height input &optional return-var) (with-temp-buffer -- 2.33.0
[signature.asc (application/pgp-signature, inline)]
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.