(ansi-colors): Doc change.
[bpt/emacs.git] / lisp / ansi-color.el
CommitLineData
986b7dee 1;;; ansi-color.el --- translate ANSI into text-properties
618206ea 2
986b7dee 3;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
618206ea 4
8737bb5a
GM
5;; Author: Alex Schroeder <alex@gnu.org>
6;; Maintainer: Alex Schroeder <alex@gnu.org>
986b7dee 7;; Version: 2.4.0
618206ea
RS
8;; Keywords: comm processes
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify it
13;; under the terms of the GNU General Public License as published by the
14;; Free Software Foundation; either version 2, or (at your option) any
15;; later version.
16;;
17;; GNU Emacs is distributed in the hope that it will be useful, but
18;; WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20;; General Public License for more details.
21;;
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Commentary:
28
986b7dee
GM
29;; This file provides a function that takes a string containing Select
30;; Graphic Rendition (SGR) control sequences (formerly known as ANSI
31;; escape sequences) and tries to replace these with text-properties.
618206ea 32;;
986b7dee
GM
33;; This allows you to run ls --color=yes in shell-mode: If
34;; `ansi-color-for-shell-mode' is non-nil, the SGR control sequences are
35;; translated into text-properties, colorizing the ls output. If
36;; `ansi-color-for-shell-mode' is nil, the SGR control sequences are
37;; stripped, making the ls output legible.
618206ea 38;;
986b7dee
GM
39;; SGR control sequences are defined in section 3.8.117 of the ECMA-48
40;; standard (identical to ISO/IEC 6429), which is freely available as a
41;; PDF file <URL:http://www.ecma.ch/ecma1/STAND/ECMA-048.HTM>. The
42;; "Graphic Rendition Combination Mode (GRCM)" implemented is
43;; "cumulative mode" as defined in section 7.2.8. Cumulative mode means
44;; that whenever possible, SGR control sequences are combined (ie. blue
45;; and bold).
618206ea 46
986b7dee
GM
47;; The basic functions are:
48;;
49;; `ansi-color-apply' to colorize a string containing SGR control
50;; sequences.
51;;
52;; `ansi-color-filter-apply' to filter SGR control sequences from a
53;; string.
618206ea 54;;
986b7dee
GM
55;; `ansi-color-apply-on-region' to colorize a region containing SGR
56;; control sequences.
57;;
58;; `ansi-color-filter-region' to filter SGR control sequences from a
59;; region.
60
61;; Instead of defining lots of new faces, this package uses
62;; text-properties as described in the elisp manual
63;; *Note (elisp)Special Properties::.
618206ea 64
986b7dee 65;;; Thanks
618206ea 66
986b7dee
GM
67;; Georges Brun-Cottan <gbruncot@emc.com> for improving ansi-color.el
68;; substantially by adding the code needed to cope with arbitrary chunks
69;; of output and the filter functions.
618206ea 70;;
986b7dee 71;; Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> for pointing me to ECMA-48.
618206ea
RS
72
73\f
74
75;;; Code:
76
8737bb5a
GM
77;; Customization
78
986b7dee
GM
79(defgroup ansi-colors nil
80 "Translating SGR control sequences to text-properties.
81This translation effectively colorizes strings and regions based upon
82SGR control sequences embedded in the text. SGR (Select Graphic
83Rendition) control sequences are defined in section 3.8.117 of the
84ECMA-48 standard \(identical to ISO/IEC 6429), which is freely available
85as a PDF file <URL:http://www.ecma.ch/ecma1/STAND/ECMA-048.HTM>."
86 :version "20.7"
87 :group 'processes)
88
89(defcustom ansi-color-faces-vector
90 [default bold default italic underline bold bold-italic modeline]
91 "Faces used for SGR control sequences determining a face.
92This vector holds the faces used for SGR control sequence parameters 0
93to 7.
618206ea 94
986b7dee
GM
95Parameter Description Face used by default
96 0 default default
97 1 bold bold
98 2 faint default
99 3 italic italic
100 4 underlined underline
101 5 slowly blinking bold
102 6 rapidly blinking bold-italic
103 7 negative image modeline
618206ea 104
986b7dee
GM
105This vector is used by `ansi-color-make-color-map' to create a color
106map. This color map is stored in the variable `ansi-color-map'."
107 :type '(vector face face face face face face face face)
108 :set 'ansi-color-map-update
109 :initialize 'custom-initialize-default
110 :group 'ansi-colors)
111
112(defcustom ansi-color-names-vector
618206ea 113 ["black" "red" "green" "yellow" "blue" "magenta" "cyan" "white"]
986b7dee
GM
114 "Colors used for SGR control sequences determining a color.
115This vector holds the colors used for SGR control sequences parameters
11630 to 37 \(foreground colors) and 40 to 47 (background colors).
117
118Parameter Color
119 30 40 black
120 31 41 red
121 32 42 green
122 33 43 yellow
123 34 44 blue
124 35 45 magenta
125 36 46 cyan
126 37 47 white
127
128This vector is used by `ansi-color-make-color-map' to create a color
129map. This color map is stored in the variable `ansi-color-map'."
130 :type '(vector string string string string string string string string)
131 :set 'ansi-color-map-update
132 :initialize 'custom-initialize-default
133 :group 'ansi-colors)
134
135(defcustom ansi-color-for-shell-mode nil
136 "Determine wether font-lock or ansi-color get to fontify shell buffers.
137
138If non-nil and `global-font-lock-mode' is non-nil, ansi-color will be
139used. This adds `ansi-color-apply' to
140`comint-preoutput-filter-functions' and removes
141`ansi-color-filter-apply' for all shell-mode buffers.
142
143If non-nil and global-font-lock-mode is nil, both `ansi-color-apply' and
144`ansi-color-filter-apply' will be removed from
145`comint-preoutput-filter-functions' for all shell-mode buffers.
146
147If nil, font-lock will be used (if it is enabled). This adds
148`ansi-color-filter-apply' to `comint-preoutput-filter-functions' and
149removes `ansi-color-apply' for all shell-mode buffers."
150 :version "20.8"
151 :type 'boolean
152 :set (function (lambda (symbol value)
153 (set-default symbol value)
154 (save-excursion
155 (let ((buffers (buffer-list))
156 buffer)
157 (while buffers
158 (setq buffer (car buffers)
159 buffers (cdr buffers))
160 (set-buffer buffer)
161 (when (eq major-mode 'shell-mode)
162 (if value
163 (if global-font-lock-mode
164 (progn
165 (font-lock-mode 0)
166 (remove-hook 'comint-preoutput-filter-functions
167 'ansi-color-filter-apply)
168 (add-hook 'comint-preoutput-filter-functions
169 'ansi-color-apply))
170 (remove-hook 'comint-preoutput-filter-functions
171 'ansi-color-filter-apply)
172 (remove-hook 'comint-preoutput-filter-functions
173 'ansi-color-apply))
174 (if global-font-lock-mode
175 (font-lock-mode 1))
176 (remove-hook 'comint-preoutput-filter-functions
177 'ansi-color-apply)
178 (add-hook 'comint-preoutput-filter-functions
179 'ansi-color-filter-apply))))))))
180 :initialize 'custom-initialize-reset
181 :group 'ansi-colors)
182
183(defconst ansi-color-regexp "\033\\[\\([0-9;]*\\)m"
184 "Regexp that matches SGR control sequences.")
185
186(defconst ansi-color-parameter-regexp "\\([0-9]*\\)[m;]"
187 "Regexp that matches SGR control sequence parameters.")
188
189
190;; Main functions
191
192
193(defun ansi-color-filter-apply (s)
194 "Filter out all SGR control sequences from S.
195
196This function can be added to `comint-preoutput-filter-functions'."
197 (while (string-match ansi-color-regexp s)
198 (setq s (replace-match "" t t s)))
199 s)
200
201
202(defun ansi-color-filter-region (begin end)
203 "Filter out all SGR control sequences from region START END.
618206ea 204
986b7dee
GM
205Returns the first point it is safe to start with. Used to speedup
206further processing.
618206ea 207
986b7dee
GM
208Design to cope with arbitrary chunk of output such as the ones get by
209comint-output-filter-functions, e.g.:
618206ea 210
986b7dee
GM
211\(defvar last-context nil)
212\(make-variable-buffer-local 'last-context)
213
214\(defun filter-out-color-in-buffer (s)
215 \(setq last-context
216 \(ansi-color-filter-region
217 \(if last-context
218 last-context
219 \(if (marker-position comint-last-output-start)
220 \(marker-position comint-last-output-start)
221 1))
222 \(marker-position (process-mark (get-buffer-process (current-buffer)))) ))
223 s)
224
225\(add-hook 'comint-output-filter-functions 'filter-out-color-in-buffer)
226"
227 (let ((endm (copy-marker end)))
228 (save-excursion
229 (goto-char begin)
230 (while (re-search-forward ansi-color-regexp endm t)
231 (replace-match ""))
232 (if (re-search-forward "\033" endm t)
233 (match-beginning 0)
234 (marker-position endm)))))
618206ea 235
8737bb5a
GM
236
237(defun ansi-color-apply (string)
986b7dee 238 "Translates SGR control sequences into text-properties.
8737bb5a 239
986b7dee 240Applies SGR control sequences setting foreground and background colors
8737bb5a
GM
241to STRING and returns the result. The colors used are given in
242`ansi-color-faces-vector' and `ansi-color-names-vector'.
243
244This function can be added to `comint-preoutput-filter-functions'."
986b7dee 245 (let (face (start 0) end escape-sequence null-sequence result)
8737bb5a 246 ;; find the next escape sequence
986b7dee 247 (while (setq end (string-match ansi-color-regexp string start))
8737bb5a 248 ;; store escape sequence
986b7dee
GM
249 (setq escape-sequence (match-string 1 string)
250 null-sequence (string-equal escape-sequence ""))
8737bb5a
GM
251 ;; colorize the old block from start to end using old face
252 (if face
253 (put-text-property start end 'face face string))
986b7dee
GM
254 (setq result (concat result (substring string start end))
255 start (match-end 0))
8737bb5a 256 ;; create new face by applying all the parameters in the escape sequence
986b7dee
GM
257 (if null-sequence
258 (setq face nil)
259 (setq face (ansi-color-get-face escape-sequence))))
8737bb5a
GM
260 (concat result (substring string start))))
261
986b7dee
GM
262
263(defun ansi-color-apply-on-region (begin end &optional context)
264 "Translates SGR control sequences into text-properties.
265
266Applies SGR control sequences setting foreground and background colors
267to text in region. The colors used are given in
268`ansi-color-faces-vector' and `ansi-color-names-vector'.
269Returns a context than can be used to speedup further processing.
270Context is a (begin (start . face)) list.
271
272Design to cope with arbitrary chunk of output such as the ones get by
273comint-output-filter-functions, e.g.:
274
275\(defvar last-context nil)
276\(make-variable-buffer-local 'last-context)
277
278\(defun ansi-output-filter (s)
279 \(setq last-context
280 \(ansi-color-apply-on-region
281 \(if last-context
282 \(car last-context)
283 \(if (marker-position comint-last-output-start)
284 \(marker-position comint-last-output-start)
285 1))
286 \(process-mark (get-buffer-process (current-buffer)))
287 last-context ))
288 s)
289
290\(add-hook 'comint-output-filter-functions 'ansi-output-filter)
291"
292 (let ((endm (copy-marker end))
293 (face (if (and context (cdr context))
294 (cdr (cdr context))))
295 (face-start (if (and context (cdr context))
296 (car (cdr context))))
297 (next-safe-start begin)
298 escape-sequence
299 null-sequence
300 stop )
301 (save-excursion
302 (goto-char begin)
303 ;; find the next escape sequence
304 (while (setq stop (re-search-forward ansi-color-regexp endm t))
305 ;; store escape sequence
306 (setq escape-sequence (match-string 1))
307 (setq null-sequence (string-equal (match-string 1) ""))
308 (setq next-safe-start (match-beginning 0))
309 (if face
310 (put-text-property face-start next-safe-start 'face face)) ; colorize
311 (replace-match "") ; delete the ANSI sequence
312 (if null-sequence
313 (setq face nil)
314 (setq face-start next-safe-start)
315 (setq face (ansi-color-get-face escape-sequence))))
316 (setq next-safe-start
317 (if (re-search-forward "\033" endm t)
318 (match-beginning 0)
319 (marker-position endm))))
320 (cons next-safe-start
321 (if face
322 (cons face-start face))) ))
323
8737bb5a
GM
324;; Helper functions
325
986b7dee
GM
326(defun ansi-color-make-color-map ()
327 "Creates a vector of face definitions and returns it.
328
329The index into the vector is an ANSI code. See the documentation of
330`ansi-color-map' for an example.
331
332The face definitions are based upon the variables
333`ansi-color-faces-vector' and `ansi-color-names-vector'."
334 (let ((ansi-color-map (make-vector 50 nil))
335 (index 0))
336 ;; miscellaneous attributes
337 (mapcar
338 (function (lambda (e)
339 (aset ansi-color-map index e)
340 (setq index (1+ index)) ))
341 ansi-color-faces-vector)
342
343 ;; foreground attributes
344 (setq index 30)
345 (mapcar
346 (function (lambda (e)
347 (aset ansi-color-map index
348 (cons 'foreground-color e))
349 (setq index (1+ index)) ))
350 ansi-color-names-vector)
351
352 ;; background attributes
353 (setq index 40)
354 (mapcar
355 (function (lambda (e)
356 (aset ansi-color-map index
357 (cons 'background-color e))
358 (setq index (1+ index)) ))
359 ansi-color-names-vector)
360 ansi-color-map))
361
362(defvar ansi-color-map (ansi-color-make-color-map)
363 "A brand new color map suitable for ansi-color-get-face.
364
365The value of this variable is usually constructed by
366`ansi-color-make-color-map'. The values in the array are such that the
367numbers included in an SGR control sequences point to the correct
368foreground or background colors.
369
370Example: The sequence \033[34m specifies a blue foreground. Therefore:
371 (aref ansi-color-map 34)
372 => \(foreground-color . \"blue\")")
373
374(defun ansi-color-map-update (symbol value)
375 "Update `ansi-color-map'.
376
377Whenever the vectors used to construct `ansi-color-map' are changed,
378this function is called. Therefore this function is listed as the :set
379property of `ansi-color-faces-vector' and `ansi-color-names-vector'."
380 (set-default symbol value)
381 (setq ansi-color-map (ansi-color-make-color-map)))
382
383(defun ansi-color-get-face-1 (ansi-code)
384 "Get face definition from `ansi-color-map'.
385ANSI-CODE is used as an index into the vector."
386 (condition-case nil
387 (aref ansi-color-map ansi-code)
388 ('args-out-of-range nil)))
389
390(defun ansi-color-get-face (escape-seq)
391 "Create a new face by applying all the parameters in ESCAPE-SEQ.
392
393ESCAPE-SEQ is a SGR control sequences such as \033[34m. The parameter
39434 is used by `ansi-color-get-face-1' to return a face definition."
395 (let ((ansi-color-r "[0-9][0-9]?")
396 (i 0)
397 f)
398 (while (string-match ansi-color-r escape-seq i)
399 (setq i (match-end 0))
400 (add-to-list 'f
401 (ansi-color-get-face-1
402 (string-to-int (match-string 0 escape-seq) 10))))
403 f))
618206ea
RS
404
405(provide 'ansi-color)
406
8737bb5a 407;;; ansi-color.el ends here