Add support for "bright" ANSI colors in ansi-color
* lisp/ansi-color.el (ansi-bright-color-names-vector): New defcustom. (ansi-color-bold-is-bright): New defcustom. (ansi-color--find-face): Sort ANSI codes and check 'ansi-color-bold-is-bright'. (ansi-color-apply-sequence): Support bright ANSI colors. (ansi-color--fill-color-map): New function. (ansi-color-make-color-map): Add bright ANSI colors. (ansi-color-get-face-1): Add BRIGHT parameter. * test/lisp/ansi-color-tests.el (ansi-color-apply-on-region-bold-is-bright-test): New function.
This commit is contained in:
parent
f09ee98e68
commit
c8e3347ec0
3 changed files with 140 additions and 34 deletions
7
etc/NEWS
7
etc/NEWS
|
@ -375,6 +375,13 @@ emulators by using the new input-meta-mode with the special value
|
|||
This parameter, similar to 'drag-with-header-line', allows moving frames
|
||||
by dragging the tab lines of their topmost windows with the mouse.
|
||||
|
||||
---
|
||||
** 'ansi-color' now supports "bright" color codes.
|
||||
"Bright" ANSI color codes are now displayed when applying ANSI color
|
||||
filters using the color values defined in 'ansi-bright-color-names-vector'.
|
||||
In addition, bold text with regular ANSI colors can be displayed as
|
||||
"bright" if 'ansi-color-bold-is-bright' is non-nil.
|
||||
|
||||
|
||||
* Editing Changes in Emacs 28.1
|
||||
|
||||
|
|
|
@ -150,6 +150,48 @@ foreground and background colors, respectively."
|
|||
:version "24.4" ; default colors copied from `xterm-standard-colors'
|
||||
:group 'ansi-colors)
|
||||
|
||||
(defcustom ansi-bright-color-names-vector
|
||||
["gray30" "red2" "green2" "yellow2" "blue1" "magenta2" "cyan2" "white"]
|
||||
"Colors used for SGR control sequences determining a \"bright\" color.
|
||||
This vector holds the colors used for SGR control sequences parameters
|
||||
90 to 97 (bright foreground colors) and 100 to 107 (brightbackground
|
||||
colors).
|
||||
|
||||
Parameter Color
|
||||
90 100 bright black
|
||||
91 101 bright red
|
||||
92 102 bright green
|
||||
93 103 bright yellow
|
||||
94 104 bright blue
|
||||
95 105 bright magenta
|
||||
96 106 bright cyan
|
||||
97 107 bright white
|
||||
|
||||
This vector is used by `ansi-color-make-color-map' to create a color
|
||||
map. This color map is stored in the variable `ansi-color-map'.
|
||||
|
||||
Each element may also be a cons cell where the car and cdr specify the
|
||||
foreground and background colors, respectively."
|
||||
:type '(vector (choice color (cons color color))
|
||||
(choice color (cons color color))
|
||||
(choice color (cons color color))
|
||||
(choice color (cons color color))
|
||||
(choice color (cons color color))
|
||||
(choice color (cons color color))
|
||||
(choice color (cons color color))
|
||||
(choice color (cons color color)))
|
||||
:set 'ansi-color-map-update
|
||||
:initialize 'custom-initialize-default
|
||||
:version "28.1"
|
||||
:group 'ansi-colors)
|
||||
|
||||
(defcustom ansi-color-bold-is-bright nil
|
||||
"If set to non-nil, combining ANSI bold and a color produces the bright
|
||||
version of that color."
|
||||
:type 'boolean
|
||||
:version "28.1"
|
||||
:group 'ansi-colors)
|
||||
|
||||
(defconst ansi-color-control-seq-regexp
|
||||
;; See ECMA 48, section 5.4 "Control Sequences".
|
||||
"\e\\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]"
|
||||
|
@ -304,9 +346,14 @@ This function can be added to `comint-preoutput-filter-functions'."
|
|||
|
||||
(defun ansi-color--find-face (codes)
|
||||
"Return the face corresponding to CODES."
|
||||
(let (faces)
|
||||
;; Sort the codes in ascending order to guarantee that "bold" comes before
|
||||
;; any of the colors. This ensures that `ansi-color-bold-is-bright' is
|
||||
;; applied correctly.
|
||||
(let (faces bright (codes (sort (copy-sequence codes) #'<)))
|
||||
(while codes
|
||||
(let ((face (ansi-color-get-face-1 (pop codes))))
|
||||
(let ((face (ansi-color-get-face-1 (pop codes) bright)))
|
||||
(when (and ansi-color-bold-is-bright (eq face 'bold))
|
||||
(setq bright t))
|
||||
;; In the (default underline) face, say, the value of the
|
||||
;; "underline" attribute of the `default' face wins.
|
||||
(unless (eq face 'default)
|
||||
|
@ -570,11 +617,11 @@ ESCAPE-SEQUENCE is an escape sequence parsed by
|
|||
|
||||
For each new code, the following happens: if it is 1-7, add it to
|
||||
the list of codes; if it is 21-25 or 27, delete appropriate
|
||||
parameters from the list of codes; if it is 30-37 resp. 39, the
|
||||
foreground color code is replaced or added resp. deleted; if it
|
||||
is 40-47 resp. 49, the background color code is replaced or added
|
||||
resp. deleted; any other code is discarded together with the old
|
||||
codes. Finally, the so changed list of codes is returned."
|
||||
parameters from the list of codes; if it is 30-37 (or 90-97) resp. 39,
|
||||
the foreground color code is replaced or added resp. deleted; if it
|
||||
is 40-47 (or 100-107) resp. 49, the background color code is replaced
|
||||
or added resp. deleted; any other code is discarded together with the
|
||||
old codes. Finally, the so changed list of codes is returned."
|
||||
(let ((new-codes (ansi-color-parse-sequence escape-sequence)))
|
||||
(while new-codes
|
||||
(let* ((new (pop new-codes))
|
||||
|
@ -591,7 +638,7 @@ codes. Finally, the so changed list of codes is returned."
|
|||
(22 (remq 1 codes))
|
||||
(25 (remq 6 codes))
|
||||
(_ codes)))))
|
||||
((or 3 4) (let ((r (mod new 10)))
|
||||
((or 3 4 9 10) (let ((r (mod new 10)))
|
||||
(unless (= r 8)
|
||||
(let (beg)
|
||||
(while (and codes (/= q (/ (car codes) 10)))
|
||||
|
@ -603,6 +650,19 @@ codes. Finally, the so changed list of codes is returned."
|
|||
(_ nil)))))
|
||||
codes))
|
||||
|
||||
(defun ansi-color--fill-color-map (map map-index property vector get-color)
|
||||
"Fill a range of color values from VECTOR and store in MAP.
|
||||
|
||||
Start filling MAP from MAP-INDEX, and make faces for PROPERTY (`foreground'
|
||||
or `background'). GET-COLOR is a function taking an element of VECTOR and
|
||||
returning the color value to use."
|
||||
(mapc
|
||||
(lambda (e)
|
||||
(aset map map-index
|
||||
(ansi-color-make-face property (funcall get-color e)))
|
||||
(setq map-index (1+ map-index)) )
|
||||
vector))
|
||||
|
||||
(defun ansi-color-make-color-map ()
|
||||
"Creates a vector of face definitions and returns it.
|
||||
|
||||
|
@ -611,7 +671,7 @@ The index into the vector is an ANSI code. See the documentation of
|
|||
|
||||
The face definitions are based upon the variables
|
||||
`ansi-color-faces-vector' and `ansi-color-names-vector'."
|
||||
(let ((map (make-vector 50 nil))
|
||||
(let ((map (make-vector 110 nil))
|
||||
(index 0))
|
||||
;; miscellaneous attributes
|
||||
(mapc
|
||||
|
@ -620,23 +680,21 @@ The face definitions are based upon the variables
|
|||
(setq index (1+ index)) )
|
||||
ansi-color-faces-vector)
|
||||
;; foreground attributes
|
||||
(setq index 30)
|
||||
(mapc
|
||||
(lambda (e)
|
||||
(aset map index
|
||||
(ansi-color-make-face 'foreground
|
||||
(if (consp e) (car e) e)))
|
||||
(setq index (1+ index)) )
|
||||
ansi-color-names-vector)
|
||||
(ansi-color--fill-color-map
|
||||
map 30 'foreground ansi-color-names-vector
|
||||
(lambda (e) (if (consp e) (car e) e)))
|
||||
;; background attributes
|
||||
(setq index 40)
|
||||
(mapc
|
||||
(lambda (e)
|
||||
(aset map index
|
||||
(ansi-color-make-face 'background
|
||||
(if (consp e) (cdr e) e)))
|
||||
(setq index (1+ index)) )
|
||||
ansi-color-names-vector)
|
||||
(ansi-color--fill-color-map
|
||||
map 40 'background ansi-color-names-vector
|
||||
(lambda (e) (if (consp e) (cdr e) e)))
|
||||
;; bright foreground attributes
|
||||
(ansi-color--fill-color-map
|
||||
map 90 'foreground ansi-bright-color-names-vector
|
||||
(lambda (e) (if (consp e) (car e) e)))
|
||||
;; bright background attributes
|
||||
(ansi-color--fill-color-map
|
||||
map 100 'background ansi-bright-color-names-vector
|
||||
(lambda (e) (if (consp e) (cdr e) e)))
|
||||
map))
|
||||
|
||||
(defvar ansi-color-map (ansi-color-make-color-map)
|
||||
|
@ -660,9 +718,13 @@ property of `ansi-color-faces-vector' and `ansi-color-names-vector'."
|
|||
(set-default symbol value)
|
||||
(setq ansi-color-map (ansi-color-make-color-map)))
|
||||
|
||||
(defun ansi-color-get-face-1 (ansi-code)
|
||||
(defun ansi-color-get-face-1 (ansi-code &optional bright)
|
||||
"Get face definition from `ansi-color-map'.
|
||||
ANSI-CODE is used as an index into the vector."
|
||||
ANSI-CODE is used as an index into the vector. BRIGHT, if non-nil,
|
||||
requests \"bright\" ANSI colors, even if ANSI-CODE is a normal-intensity
|
||||
color."
|
||||
(when (and bright (<= 30 ansi-code 49))
|
||||
(setq ansi-code (+ ansi-code 60)))
|
||||
(condition-case nil
|
||||
(aref ansi-color-map ansi-code)
|
||||
(args-out-of-range nil)))
|
||||
|
|
|
@ -25,17 +25,54 @@
|
|||
;;; Code:
|
||||
|
||||
(require 'ansi-color)
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
|
||||
(defvar test-strings '(("\e[33mHello World\e[0m" . "Hello World")
|
||||
("\e[1m\e[3m\e[5mbold italics blink\e[0m" . "bold italics blink")))
|
||||
(defvar yellow (aref ansi-color-names-vector 3))
|
||||
(defvar bright-yellow (aref ansi-bright-color-names-vector 3))
|
||||
|
||||
(defvar test-strings
|
||||
`(("\e[33mHello World\e[0m" "Hello World"
|
||||
(foreground-color . ,yellow))
|
||||
("\e[43mHello World\e[0m" "Hello World"
|
||||
(background-color . ,yellow))
|
||||
("\e[93mHello World\e[0m" "Hello World"
|
||||
(foreground-color . ,bright-yellow))
|
||||
("\e[103mHello World\e[0m" "Hello World"
|
||||
(background-color . ,bright-yellow))
|
||||
("\e[1;33mHello World\e[0m" "Hello World"
|
||||
(bold (foreground-color . ,yellow))
|
||||
(bold (foreground-color . ,bright-yellow)))
|
||||
("\e[33;1mHello World\e[0m" "Hello World"
|
||||
(bold (foreground-color . ,yellow))
|
||||
(bold (foreground-color . ,bright-yellow)))
|
||||
("\e[1m\e[33mHello World\e[0m" "Hello World"
|
||||
(bold (foreground-color . ,yellow))
|
||||
(bold (foreground-color . ,bright-yellow)))
|
||||
("\e[33m\e[1mHello World\e[0m" "Hello World"
|
||||
(bold (foreground-color . ,yellow))
|
||||
(bold (foreground-color . ,bright-yellow)))
|
||||
("\e[1m\e[3m\e[5mbold italics blink\e[0m" "bold italics blink"
|
||||
(bold italic success))))
|
||||
|
||||
(ert-deftest ansi-color-apply-on-region-test ()
|
||||
(dolist (pair test-strings)
|
||||
(with-temp-buffer
|
||||
(insert (car pair))
|
||||
(pcase-dolist (`(,input ,text ,face) test-strings)
|
||||
(with-temp-buffer
|
||||
(insert input)
|
||||
(ansi-color-apply-on-region (point-min) (point-max))
|
||||
(should (equal (buffer-string) text))
|
||||
(should (equal (get-char-property (point-min) 'face) face))
|
||||
(should (not (equal (overlays-at (point-min)) nil))))))
|
||||
|
||||
(ert-deftest ansi-color-apply-on-region-bold-is-bright-test ()
|
||||
(pcase-dolist (`(,input ,text ,face ,bright-face) test-strings)
|
||||
(with-temp-buffer
|
||||
(let ((ansi-color-bold-is-bright t))
|
||||
(insert input)
|
||||
(ansi-color-apply-on-region (point-min) (point-max))
|
||||
(should (equal (buffer-string) (cdr pair)))
|
||||
(should (not (equal (overlays-at (point-min)) nil))))))
|
||||
(should (equal (buffer-string) text))
|
||||
(should (equal (get-char-property (point-min) 'face)
|
||||
(or bright-face face)))
|
||||
(should (not (equal (overlays-at (point-min)) nil)))))))
|
||||
|
||||
(ert-deftest ansi-color-apply-on-region-preserving-test ()
|
||||
(dolist (pair test-strings)
|
||||
|
|
Loading…
Add table
Reference in a new issue