comparison lisp/ansi-color.el @ 26092:8080bafbae4b

Complete rewrite.
author Gerd Moellmann <gerd@gnu.org>
date Tue, 19 Oct 1999 11:17:23 +0000
parents 38f98813a83d
children 5ebcf240e1c6
comparison
equal deleted inserted replaced
26091:db9c6f10ec76 26092:8080bafbae4b
1 ;;; ansi-color.el -- translate ANSI into text-properties 1 ;;; ansi-color.el -- translate ANSI into text-properties
2 2
3 ;; Copyright (C) 1999 Free Software Foundation, Inc. 3 ;; Copyright (C) 1999 Free Software Foundation, Inc.
4 4
5 ;; Author: Alex Schroeder <alex@gnu.ch> 5 ;; Author: Alex Schroeder <alex@gnu.org>
6 ;; Maintainer: Alex Schroeder <alex@gnu.ch> 6 ;; Maintainer: Alex Schroeder <alex@gnu.org>
7 ;; Version: 1.2.0 7 ;; Version: 2.1.1
8 ;; Keywords: comm processes 8 ;; Keywords: comm processes
9 9
10 ;; This file is part of GNU Emacs. 10 ;; This file is part of GNU Emacs.
11 11
12 ;; GNU Emacs is free software; you can redistribute it and/or modify it 12 ;; GNU Emacs is free software; you can redistribute it and/or modify it
34 ;; 34 ;;
35 ;; I was unable to extract this functionality from term.el for another 35 ;; I was unable to extract this functionality from term.el for another
36 ;; program I wanted to extend (the MUSH client TinyTalk.el), so I had to 36 ;; program I wanted to extend (the MUSH client TinyTalk.el), so I had to
37 ;; rewrite this. 37 ;; rewrite this.
38 38
39 ;; In order to install this with TinyMush.el, add the following to your
40 ;; .emacs file:
41 ;;
42 ;; (setq tinymud-filter-line-hook 'my-tinymud-add-ansi-text-properties)
43 ;; (autoload 'ansi-color-to-text-properties "ansi-color"
44 ;; "Translates ANSI color control sequences into text-properties." t)
45 ;; (defun my-tinymud-add-ansi-text-properties (conn line)
46 ;; "Call `ansi-color-to-text-properties' for LINE.
47 ;; Ignores CONN and returns nil, so that `tinymud-filter-line' continues to
48 ;; process triggers and everything else."
49 ;; (ansi-color-to-text-properties line)
50 ;; nil)
51
52 ;; If the ANSI sequences assume that you have a black background, you'll
53 ;; have to display the stuff in a frame with a black background. You
54 ;; can create such a frame like this (it still looks ugly!):
55 ;;
56 ;; (defun my-black-frame ()
57 ;; "Create a frame with black background."
58 ;; (interactive)
59 ;; (make-frame '((foreground-color . "white")
60 ;; (background-color . "black"))))
61
62 ;;; Testing: 39 ;;; Testing:
63 40
64 ;; If you want to test the setup, evaluate the following fragment in a 41 ;; If you want to test the setup, evaluate the following fragment in a
65 ;; buffer without font-lock-mode. This doesn't work in buffers that 42 ;; buffer without font-lock-mode. This doesn't work in buffers that
66 ;; have font-lock-mode! 43 ;; have font-lock-mode!
67 ;; 44 ;;
68 ;; (progn 45 ;; (insert (ansi-color-apply "\033[1mbold\033[0m and \033[34mblue\033[0m, \033[1m\033[34mbold and blue\033[0m!!"))
69 ;; (setq line "bold and blue, bold and blue!!") 46
70 ;; (ansi-color-to-text-properties line) 47 ;; Usage with TinyMush.el:
71 ;; (insert line)) 48
49 ;; In order to install this with TinyMush.el, add the following to your
50 ;; .emacs file:
72 ;; 51 ;;
73 ;; Other test strings: (m-eating-bug) "mold should be mold" 52 ;; (setq tinymud-filter-line-hook 'my-ansi-color-filter)
53 ;; (autoload 'ansi-color-apply "ansi-color"
54 ;; "Translates ANSI color control sequences into text-properties." t)
55 ;; (defun my-ansi-color-filter (conn line)
56 ;; "Call `ansi-color-apply' and then processes things like `filter-line'."
57 ;; (setq line (ansi-color-apply line))
58 ;; (if (not (get-value conn 'trigger-disable))
59 ;; (progn
60 ;; (check-triggers conn line
61 ;; (get-value conn 'triggers))
62 ;; (check-triggers conn line
63 ;; (get-value (get-value conn 'world) 'triggers))
64 ;; (check-triggers conn line
65 ;; tinymud-global-triggers)))
66 ;; (display-line conn line)
67 ;; t)
74 68
75 ;;; Bugs: 69 ;; Usage with shell-mode:
76 70
77 ;; 1. Only supports the ANSI sequences that the MUSH I'm on uses (the 71 ;; In order to enjoy the marvels of "ls --color=tty" you will have to
78 ;; MUSH is Elendor, see http://www.elendor.net). To see the list of 72 ;; enter shell-mode using M-x shell, possibly disable font-lock-mode
79 ;; codes supported I did a `help ansi()'. Based on this information, 73 ;; using M-: (font-lock-mode 0), and add ansi-color-apply to
80 ;; I used TinyTalk.el (without ANSI color support), gave myself the 74 ;; comint-preoutput-filter-functions using M-: (add-hook
81 ;; ANSI color flags using `@set me=ANSI' and `@set me=COLOR', and 75 ;; 'comint-preoutput-filter-functions 'ansi-color-apply).
82 ;; noted the ANSI escape sequences produced by the MUSH using `think
83 ;; ansi(r,red)' for example.
84 ;;
85 ;; 2. The code is spaghetti-code, I hate it.
86 ;;
87 ;; 3. If a squence of chars looks like the start of an ANSI sequence,
88 ;; the chars will be set invisible. If the squence of chars turns
89 ;; out not to be an ANSI sequence, this is not undone. Here is a
90 ;; teststring: "Is '[3' visible as ^[[3?" This could be solved by
91 ;; using `state': it shows most of the time how many characters have
92 ;; been set invisible.
93 76
94 77
95 78
96 ;;; Code: 79 ;;; Code:
97 80
81 ;; Customization
82
98 (defvar ansi-color-faces-vector 83 (defvar ansi-color-faces-vector
99 [default bold default default underline bold default modeline] 84 [default bold default default underline bold default modeline]
100 "Faces used for ANSI control sequences determining a face. 85 "Faces used for ANSI control sequences determining a face.
101 86
102 Those are sequences like this one: , where 1 could be one of the 87 Those are sequences like this one: \033[1m, where 1 could be one of the
103 following numbers: 0 (default), 1 (hilight, rendered as bold), 4 88 following numbers: 0 (default), 1 (hilight, rendered as bold), 4
104 (underline), 5 (flashing, rendered as bold), 7 (inverse, rendered the 89 (underline), 5 (flashing, rendered as bold), 7 (inverse, rendered the
105 same as the modeline)") 90 same as the modeline)")
106 91
107 (defvar ansi-color-names-vector 92 (defvar ansi-color-names-vector
108 ["black" "red" "green" "yellow" "blue" "magenta" "cyan" "white"] 93 ["black" "red" "green" "yellow" "blue" "magenta" "cyan" "white"]
109 "Array of colors. 94 "Array of colors.
110 95
111 Used for sequences like this one: , where 1 could be an index to a 96 Used for sequences like this one: \033[31m, where 1 could be an index to a
112 foreground color (red, in this case), or , where 1 could be an 97 foreground color (red, in this case), or \033[41m, where 1 could be an
113 index to a background color. 98 index to a background color.
114 99
115 The default colors are: black, red, green, yellow, blue, magenta, 100 The default colors are: black, red, green, yellow, blue, magenta,
116 cyan, and white. 101 cyan, and white.
117 102
118 On a light background, I prefer: black, red, dark green, orange, blue, 103 On a light background, I prefer: black, red, dark green, orange, blue,
119 magenta, turquoise, snow4") 104 magenta, turquoise, snow4")
120 105
121 ;; The main function 106 ;; Main function
122 107
123 (defun ansi-color-to-text-properties (str) 108 (defun ansi-color-apply (string)
124 "Translates ANSI color control sequences into text-properties. 109 "Translates ANSI color control sequences into text-properties.
125 110
126 The ANSI control sequences are made invisible. The text-properties are 111 Applies ANSI control sequences setting foreground and background colors
127 added to the string given in the parameter STR." 112 to STRING and returns the result. The colors used are given in
128 ;; ANSI code for highlighting, example: boringINTERESTINGboring 113 `ansi-color-faces-vector' and `ansi-color-names-vector'.
129 ;; state: start with 0, "" -> 1, "[" -> 2, "[013457]" -> 3,
130 ;; "[013457]" -> 4, "m" -> back to 0!
131 ;; param: stored when state is 3 (in the above example: 1)
132 (let ((str-length (length str))
133 (face '(default))
134 (i 0) (char) (state 0) (param1) (param2))
135 (while (< i str-length)
136 (setq char (aref str i))
137 (cond
138 ;; When writing normal chars (state 0) and happening upon an ANSI sequence.
139 ((and (= state 0) (= char ?))
140 (setq state 1)); saw escape
141 ((and (= state 1) (= char ?\[)); seen escape
142 (setq state 2
143 param1 nil
144 param2 nil)); saw [, prepare for param1 and param2!
145 ((and (or (= state 2) (= state 3)); reading first or second digit
146 (string-match "[01234567]" (substring str i (1+ i))))
147 (if (= state 2); reading first digit
148 ;;  (hilight)
149 (setq param1 (string-to-number (substring str i (1+ i)))
150 state 3); prepare to read a second digit or quit.
151 ;; if reading second digit
152 ;; such as  (green foreground)
153 (setq param2 (string-to-number (substring str i (1+ i)))
154 state 4))); read second digit, prepare to quit
155 ((and (or (= state 3) (= state 4)) (= char ?m)); reading last char: m
156 (setq state 5); state 5: m will be last invisible char. Now
157 ;; reset face according to param1 and param2.
158 (if (null param2); only param1 set: no color changes!
159 ;; : default face
160 (if (= param1 0)
161 (setq face '(default))
162 ;; : hilight, : inverse, : underline, etc.
163 (add-to-list 'face (aref ansi-color-faces-vector param1)))
164 ;; If param2 is set, we are changing back- or foreground color.
165 (if (= param1 3); first digit told us to change foreground
166 ;; : red foreground
167 (add-to-list 'face (cons 'foreground-color
168 (aref ansi-color-names-vector param2)))
169 ;; : green background
170 (add-to-list 'face (cons 'background-color
171 (aref ansi-color-names-vector param2))))))
172 (t (setq state 0))); all other cases, state is 0.
173 114
174 ;; Set text-property for every char. 115 This function can be added to `comint-preoutput-filter-functions'."
175 (if (> state 0); if reading ANSI codes, state > 0: make them 116 (let ((face)
176 ; invisible. 117 (start 0) (end) (escape)
177 (put-text-property i (1+ i) 'invisible t str) 118 (result)
178 ;; if reading normal chars, state is 0, put them in the 119 (params))
179 ;; current face. 120 ;; find the next escape sequence
180 (put-text-property i (1+ i) 'face face str)) 121 (while (setq end (string-match "\033\\[\\([01347][01234567]?;\\)*[01347][01234567]?m" string start))
122 ;; store escape sequence
123 (setq escape (match-string 0 string))
124 ;; colorize the old block from start to end using old face
125 (if face
126 (put-text-property start end 'face face string))
127 (setq result (concat result (substring string start end)))
128 ;; create new face by applying all the parameters in the escape sequence
129 (let ((i 0))
130 (while (setq i (string-match "[01347][01234567]?[;m]" escape i))
131 (setq face (ansi-color-make-face face
132 (aref escape i)
133 (aref escape (1+ i))))
134 (setq i (match-end 0))))
135 (setq start (+ end (length escape))))
136 (concat result (substring string start))))
181 137
182 ;; Debug: (message "%c: %d" char state) 138 ;; Helper functions
183 139
184 ;; If we just finished reading an ANSI sequence (state 5), reset 140 (defun ansi-color-make-face (face param1 param2)
185 ;; state (state 0). 141 "Return a face based on FACE and characters PARAM1 and PARAM2.
186 (if (> state 4) (setq state 0)) 142
187 ;; Next char 143 The face can be used in a call to `add-text-properties'. The PARAM1 and
188 (setq i (1+ i))))) 144 PARAM2 characters are the two numeric characters in ANSI control
145 sequences between ?[ and ?m. Unless the ANSI control sequence specifies
146 a return to default face using PARAM1 ?0 and PARAM2 ?m (ie. \"\033[0m\"), the
147 properties specified by PARAM1 and PARAM2 are added to face."
148 (cond ((= param1 ?0)
149 nil)
150 ((= param2 ?m)
151 (add-to-list 'face (aref ansi-color-faces-vector
152 (string-to-number (char-to-string param1)))))
153 ((= param1 ?3)
154 (add-to-list 'face (cons 'foreground-color
155 (aref ansi-color-names-vector
156 (string-to-number (char-to-string param2))))))
157 ((= param1 ?4)
158 (add-to-list 'face (cons 'background-color
159 (aref ansi-color-names-vector
160 (string-to-number (char-to-string param2))))))
161 (t (add-to-list 'face (aref ansi-color-faces-vector
162 (string-to-number (char-to-string param1)))))))
189 163
190 (provide 'ansi-color) 164 (provide 'ansi-color)
191 165
192 ;;; ansi-colors.el ends here 166 ;;; ansi-color.el ends here
193
194