Commit | Line | Data |
---|---|---|
0e3c1e3e | 1 | ;;; ansi-color.el --- translate ANSI escape sequences into faces |
618206ea | 2 | |
0d30b337 | 3 | ;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, |
114f9c96 | 4 | ;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. |
618206ea | 5 | |
8737bb5a GM |
6 | ;; Author: Alex Schroeder <alex@gnu.org> |
7 | ;; Maintainer: Alex Schroeder <alex@gnu.org> | |
b3287acf GM |
8 | ;; Version: 3.4.2 |
9 | ;; Keywords: comm processes terminals services | |
618206ea RS |
10 | |
11 | ;; This file is part of GNU Emacs. | |
12 | ||
eb3fa2cf GM |
13 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
14 | ;; it under the terms of the GNU General Public License as published by | |
15 | ;; the Free Software Foundation, either version 3 of the License, or | |
16 | ;; (at your option) any later version. | |
17 | ||
18 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | ;; GNU General Public License for more details. | |
22 | ||
618206ea | 23 | ;; You should have received a copy of the GNU General Public License |
eb3fa2cf | 24 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
618206ea RS |
25 | |
26 | ;;; Commentary: | |
27 | ||
0e3c1e3e GM |
28 | ;; This file provides a function that takes a string or a region |
29 | ;; containing Select Graphic Rendition (SGR) control sequences (formerly | |
30 | ;; known as ANSI escape sequences) and tries to translate these into | |
31 | ;; faces. | |
618206ea | 32 | ;; |
89601c7b CY |
33 | ;; This allows you to run ls --color=yes in shell-mode. It is now |
34 | ;; enabled by default; to disable it, set ansi-color-for-comint-mode | |
35 | ;; to nil. | |
0e3c1e3e GM |
36 | ;; |
37 | ;; Note that starting your shell from within Emacs might set the TERM | |
38 | ;; environment variable. The new setting might disable the output of | |
39 | ;; SGR control sequences. Using ls --color=yes forces ls to produce | |
40 | ;; these. | |
41 | ;; | |
986b7dee GM |
42 | ;; SGR control sequences are defined in section 3.8.117 of the ECMA-48 |
43 | ;; standard (identical to ISO/IEC 6429), which is freely available as a | |
44 | ;; PDF file <URL:http://www.ecma.ch/ecma1/STAND/ECMA-048.HTM>. The | |
45 | ;; "Graphic Rendition Combination Mode (GRCM)" implemented is | |
46 | ;; "cumulative mode" as defined in section 7.2.8. Cumulative mode means | |
47 | ;; that whenever possible, SGR control sequences are combined (ie. blue | |
48 | ;; and bold). | |
618206ea | 49 | |
986b7dee GM |
50 | ;; The basic functions are: |
51 | ;; | |
52 | ;; `ansi-color-apply' to colorize a string containing SGR control | |
53 | ;; sequences. | |
54 | ;; | |
55 | ;; `ansi-color-filter-apply' to filter SGR control sequences from a | |
56 | ;; string. | |
618206ea | 57 | ;; |
986b7dee GM |
58 | ;; `ansi-color-apply-on-region' to colorize a region containing SGR |
59 | ;; control sequences. | |
60 | ;; | |
61 | ;; `ansi-color-filter-region' to filter SGR control sequences from a | |
62 | ;; region. | |
63 | ||
986b7dee | 64 | ;;; Thanks |
618206ea | 65 | |
986b7dee GM |
66 | ;; Georges Brun-Cottan <gbruncot@emc.com> for improving ansi-color.el |
67 | ;; substantially by adding the code needed to cope with arbitrary chunks | |
68 | ;; of output and the filter functions. | |
618206ea | 69 | ;; |
986b7dee | 70 | ;; Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk> for pointing me to ECMA-48. |
0e3c1e3e GM |
71 | ;; |
72 | ;; Stefan Monnier <foo@acm.com> explaing obscure font-lock stuff and | |
73 | ;; code suggestions. | |
618206ea RS |
74 | |
75 | \f | |
76 | ||
77 | ;;; Code: | |
78 | ||
cd91462f JB |
79 | (defvar comint-last-output-start) |
80 | ||
8737bb5a GM |
81 | ;; Customization |
82 | ||
986b7dee | 83 | (defgroup ansi-colors nil |
0e3c1e3e | 84 | "Translating SGR control sequences to faces. |
986b7dee GM |
85 | This translation effectively colorizes strings and regions based upon |
86 | SGR control sequences embedded in the text. SGR (Select Graphic | |
87 | Rendition) control sequences are defined in section 3.8.117 of the | |
88 | ECMA-48 standard \(identical to ISO/IEC 6429), which is freely available | |
89 | as a PDF file <URL:http://www.ecma.ch/ecma1/STAND/ECMA-048.HTM>." | |
7c6c3d8e | 90 | :version "21.1" |
986b7dee GM |
91 | :group 'processes) |
92 | ||
93 | (defcustom ansi-color-faces-vector | |
94 | [default bold default italic underline bold bold-italic modeline] | |
95 | "Faces used for SGR control sequences determining a face. | |
96 | This vector holds the faces used for SGR control sequence parameters 0 | |
97 | to 7. | |
618206ea | 98 | |
986b7dee GM |
99 | Parameter Description Face used by default |
100 | 0 default default | |
101 | 1 bold bold | |
102 | 2 faint default | |
103 | 3 italic italic | |
104 | 4 underlined underline | |
105 | 5 slowly blinking bold | |
106 | 6 rapidly blinking bold-italic | |
107 | 7 negative image modeline | |
618206ea | 108 | |
0e3c1e3e GM |
109 | Note that the symbol `default' is special: It will not be combined |
110 | with the current face. | |
111 | ||
986b7dee GM |
112 | This vector is used by `ansi-color-make-color-map' to create a color |
113 | map. This color map is stored in the variable `ansi-color-map'." | |
114 | :type '(vector face face face face face face face face) | |
115 | :set 'ansi-color-map-update | |
116 | :initialize 'custom-initialize-default | |
117 | :group 'ansi-colors) | |
118 | ||
119 | (defcustom ansi-color-names-vector | |
618206ea | 120 | ["black" "red" "green" "yellow" "blue" "magenta" "cyan" "white"] |
986b7dee GM |
121 | "Colors used for SGR control sequences determining a color. |
122 | This vector holds the colors used for SGR control sequences parameters | |
123 | 30 to 37 \(foreground colors) and 40 to 47 (background colors). | |
124 | ||
125 | Parameter Color | |
126 | 30 40 black | |
127 | 31 41 red | |
128 | 32 42 green | |
129 | 33 43 yellow | |
130 | 34 44 blue | |
131 | 35 45 magenta | |
132 | 36 46 cyan | |
133 | 37 47 white | |
134 | ||
135 | This vector is used by `ansi-color-make-color-map' to create a color | |
136 | map. This color map is stored in the variable `ansi-color-map'." | |
137 | :type '(vector string string string string string string string string) | |
138 | :set 'ansi-color-map-update | |
139 | :initialize 'custom-initialize-default | |
140 | :group 'ansi-colors) | |
141 | ||
c21d4d1a | 142 | (defconst ansi-color-regexp "\033\\[\\([0-9;]*m\\)" |
986b7dee GM |
143 | "Regexp that matches SGR control sequences.") |
144 | ||
bc8d33d5 CY |
145 | (defconst ansi-color-drop-regexp |
146 | "\033\\[\\([ABCDsuK]\\|2J\\|=[0-9]+[hI]\\|[0-9;]*[Hf]\\)" | |
147 | "Regexp that matches ANSI control sequences to silently drop.") | |
148 | ||
986b7dee GM |
149 | (defconst ansi-color-parameter-regexp "\\([0-9]*\\)[m;]" |
150 | "Regexp that matches SGR control sequence parameters.") | |
151 | ||
152 | ||
0e3c1e3e | 153 | ;; Convenience functions for comint modes (eg. shell-mode) |
986b7dee GM |
154 | |
155 | ||
925f8c70 | 156 | (defcustom ansi-color-for-comint-mode t |
0e3c1e3e GM |
157 | "Determines what to do with comint output. |
158 | If nil, do nothing. | |
159 | If the symbol `filter', then filter all SGR control sequences. | |
160 | If anything else (such as t), then translate SGR control sequences | |
bc8d33d5 | 161 | into text properties. |
986b7dee | 162 | |
0e3c1e3e GM |
163 | In order for this to have any effect, `ansi-color-process-output' must |
164 | be in `comint-output-filter-functions'. | |
986b7dee | 165 | |
0e3c1e3e GM |
166 | This can be used to enable colorized ls --color=yes output |
167 | in shell buffers. You set this variable by calling one of: | |
168 | \\[ansi-color-for-comint-mode-on] | |
169 | \\[ansi-color-for-comint-mode-off] | |
170 | \\[ansi-color-for-comint-mode-filter]" | |
0e3c1e3e GM |
171 | :type '(choice (const :tag "Do nothing" nil) |
172 | (const :tag "Filter" filter) | |
173 | (const :tag "Translate" t)) | |
c2dae51b CY |
174 | :group 'ansi-colors |
175 | :version "23.2") | |
986b7dee | 176 | |
58622cc5 | 177 | ;;;###autoload |
0e3c1e3e GM |
178 | (defun ansi-color-for-comint-mode-on () |
179 | "Set `ansi-color-for-comint-mode' to t." | |
180 | (interactive) | |
181 | (setq ansi-color-for-comint-mode t)) | |
182 | ||
183 | (defun ansi-color-for-comint-mode-off () | |
184 | "Set `ansi-color-for-comint-mode' to nil." | |
185 | (interactive) | |
186 | (setq ansi-color-for-comint-mode nil)) | |
187 | ||
188 | (defun ansi-color-for-comint-mode-filter () | |
189 | "Set `ansi-color-for-comint-mode' to symbol `filter'." | |
190 | (interactive) | |
191 | (setq ansi-color-for-comint-mode 'filter)) | |
192 | ||
58622cc5 | 193 | ;;;###autoload |
1b25a579 | 194 | (defun ansi-color-process-output (ignored) |
bc8d33d5 | 195 | "Maybe translate SGR control sequences of comint output into text properties. |
0e3c1e3e GM |
196 | |
197 | Depending on variable `ansi-color-for-comint-mode' the comint output is | |
198 | either not processed, SGR control sequences are filtered using | |
199 | `ansi-color-filter-region', or SGR control sequences are translated into | |
bc8d33d5 | 200 | text properties using `ansi-color-apply-on-region'. |
0e3c1e3e GM |
201 | |
202 | The comint output is assumed to lie between the marker | |
203 | `comint-last-output-start' and the process-mark. | |
204 | ||
205 | This is a good function to put in `comint-output-filter-functions'." | |
206 | (let ((start-marker (or comint-last-output-start | |
207 | (point-min-marker))) | |
208 | (end-marker (process-mark (get-buffer-process (current-buffer))))) | |
209 | (cond ((eq ansi-color-for-comint-mode nil)) | |
210 | ((eq ansi-color-for-comint-mode 'filter) | |
211 | (ansi-color-filter-region start-marker end-marker)) | |
212 | (t | |
213 | (ansi-color-apply-on-region start-marker end-marker))))) | |
214 | ||
215 | (add-hook 'comint-output-filter-functions | |
216 | 'ansi-color-process-output) | |
217 | ||
218 | ||
b3287acf | 219 | ;; Alternative font-lock-unfontify-region-function for Emacs only |
0e3c1e3e | 220 | |
0e3c1e3e | 221 | (defun ansi-color-unfontify-region (beg end &rest xemacs-stuff) |
b3287acf GM |
222 | "Replacement function for `font-lock-default-unfontify-region'. |
223 | ||
bc8d33d5 | 224 | As text properties are implemented using extents in XEmacs, this |
b3287acf GM |
225 | function is probably not needed. In Emacs, however, things are a bit |
226 | different: When font-lock is active in a buffer, you cannot simply add | |
bc8d33d5 CY |
227 | face text properties to the buffer. Font-lock will remove the face |
228 | text property using `font-lock-unfontify-region-function'. If you want | |
0e3c1e3e GM |
229 | to insert the strings returned by `ansi-color-apply' into such buffers, |
230 | you must set `font-lock-unfontify-region-function' to | |
231 | `ansi-color-unfontify-region'. This function will not remove all face | |
bc8d33d5 | 232 | text properties unconditionally. It will keep the face text properties |
0e3c1e3e GM |
233 | if the property `ansi-color' is set. |
234 | ||
235 | The region from BEG to END is unfontified. XEMACS-STUFF is ignored. | |
236 | ||
237 | A possible way to install this would be: | |
238 | ||
239 | \(add-hook 'font-lock-mode-hook | |
240 | \(function (lambda () | |
241 | \(setq font-lock-unfontify-region-function | |
242 | 'ansi-color-unfontify-region))))" | |
05616854 RS |
243 | ;; Simplified now that font-lock-unfontify-region uses save-buffer-state. |
244 | (when (boundp 'font-lock-syntactic-keywords) | |
245 | (remove-text-properties beg end '(syntax-table nil))) | |
246 | ;; instead of just using (remove-text-properties beg end '(face | |
cf38dd42 | 247 | ;; nil)), we find regions with a non-nil face text-property, skip |
05616854 | 248 | ;; positions with the ansi-color property set, and remove the |
cf38dd42 | 249 | ;; remaining face text-properties. |
05616854 RS |
250 | (while (setq beg (text-property-not-all beg end 'face nil)) |
251 | (setq beg (or (text-property-not-all beg end 'ansi-color t) end)) | |
252 | (when (get-text-property beg 'face) | |
253 | (let ((end-face (or (text-property-any beg end 'face nil) | |
254 | end))) | |
255 | (remove-text-properties beg end-face '(face nil)) | |
256 | (setq beg end-face))))) | |
0e3c1e3e GM |
257 | |
258 | ;; Working with strings | |
259 | ||
260 | (defvar ansi-color-context nil | |
261 | "Context saved between two calls to `ansi-color-apply'. | |
262 | This is a list of the form (FACES FRAGMENT) or nil. FACES is a list of | |
263 | faces the last call to `ansi-color-apply' ended with, and FRAGMENT is a | |
264 | string starting with an escape sequence, possibly the start of a new | |
265 | escape sequence.") | |
266 | (make-variable-buffer-local 'ansi-color-context) | |
267 | ||
268 | (defun ansi-color-filter-apply (string) | |
bc8d33d5 | 269 | "Filter out all ANSI control sequences from STRING. |
0e3c1e3e GM |
270 | |
271 | Every call to this function will set and use the buffer-local variable | |
272 | `ansi-color-context' to save partial escape sequences. This information | |
273 | will be used for the next call to `ansi-color-apply'. Set | |
274 | `ansi-color-context' to nil if you don't want this. | |
618206ea | 275 | |
0e3c1e3e GM |
276 | This function can be added to `comint-preoutput-filter-functions'." |
277 | (let ((start 0) end result) | |
278 | ;; if context was saved and is a string, prepend it | |
279 | (if (cadr ansi-color-context) | |
280 | (setq string (concat (cadr ansi-color-context) string) | |
281 | ansi-color-context nil)) | |
282 | ;; find the next escape sequence | |
283 | (while (setq end (string-match ansi-color-regexp string start)) | |
284 | (setq result (concat result (substring string start end)) | |
285 | start (match-end 0))) | |
286 | ;; save context, add the remainder of the string to the result | |
287 | (let (fragment) | |
288 | (if (string-match "\033" string start) | |
289 | (let ((pos (match-beginning 0))) | |
290 | (setq fragment (substring string pos) | |
291 | result (concat result (substring string start pos)))) | |
292 | (setq result (concat result (substring string start)))) | |
293 | (if fragment | |
294 | (setq ansi-color-context (list nil fragment)) | |
295 | (setq ansi-color-context nil))) | |
296 | result)) | |
8737bb5a GM |
297 | |
298 | (defun ansi-color-apply (string) | |
bc8d33d5 CY |
299 | "Translates SGR control sequences into text properties. |
300 | Delete all other control sequences without processing them. | |
8737bb5a | 301 | |
986b7dee | 302 | Applies SGR control sequences setting foreground and background colors |
bc8d33d5 | 303 | to STRING using text properties and returns the result. The colors used |
0e3c1e3e GM |
304 | are given in `ansi-color-faces-vector' and `ansi-color-names-vector'. |
305 | See function `ansi-color-apply-sequence' for details. | |
306 | ||
307 | Every call to this function will set and use the buffer-local variable | |
308 | `ansi-color-context' to save partial escape sequences and current face. | |
309 | This information will be used for the next call to `ansi-color-apply'. | |
310 | Set `ansi-color-context' to nil if you don't want this. | |
311 | ||
312 | This function can be added to `comint-preoutput-filter-functions'. | |
313 | ||
314 | You cannot insert the strings returned into buffers using font-lock. | |
315 | See `ansi-color-unfontify-region' for a way around this." | |
316 | (let ((face (car ansi-color-context)) | |
bc8d33d5 CY |
317 | (start 0) end escape-sequence result |
318 | colorized-substring) | |
319 | ;; If context was saved and is a string, prepend it. | |
0e3c1e3e GM |
320 | (if (cadr ansi-color-context) |
321 | (setq string (concat (cadr ansi-color-context) string) | |
322 | ansi-color-context nil)) | |
bc8d33d5 | 323 | ;; Find the next escape sequence. |
986b7dee | 324 | (while (setq end (string-match ansi-color-regexp string start)) |
0e3c1e3e | 325 | (setq escape-sequence (match-string 1 string)) |
bc8d33d5 | 326 | ;; Colorize the old block from start to end using old face. |
0e3c1e3e GM |
327 | (when face |
328 | (put-text-property start end 'ansi-color t string) | |
329 | (put-text-property start end 'face face string)) | |
bc8d33d5 | 330 | (setq colorized-substring (substring string start end) |
986b7dee | 331 | start (match-end 0)) |
bc8d33d5 CY |
332 | ;; Eliminate unrecognized ANSI sequences. |
333 | (while (string-match ansi-color-drop-regexp colorized-substring) | |
334 | (setq colorized-substring | |
335 | (replace-match "" nil nil colorized-substring))) | |
336 | (push colorized-substring result) | |
337 | ;; Create new face, by applying escape sequence parameters. | |
0e3c1e3e GM |
338 | (setq face (ansi-color-apply-sequence escape-sequence face))) |
339 | ;; if the rest of the string should have a face, put it there | |
340 | (when face | |
341 | (put-text-property start (length string) 'ansi-color t string) | |
342 | (put-text-property start (length string) 'face face string)) | |
343 | ;; save context, add the remainder of the string to the result | |
344 | (let (fragment) | |
345 | (if (string-match "\033" string start) | |
346 | (let ((pos (match-beginning 0))) | |
bc8d33d5 CY |
347 | (setq fragment (substring string pos)) |
348 | (push (substring string start pos) result)) | |
349 | (push (substring string start) result)) | |
0e3c1e3e GM |
350 | (if (or face fragment) |
351 | (setq ansi-color-context (list face fragment)) | |
352 | (setq ansi-color-context nil))) | |
bc8d33d5 | 353 | (apply 'concat (nreverse result)))) |
0e3c1e3e GM |
354 | |
355 | ;; Working with regions | |
356 | ||
357 | (defvar ansi-color-context-region nil | |
358 | "Context saved between two calls to `ansi-color-apply-on-region'. | |
359 | This is a list of the form (FACES MARKER) or nil. FACES is a list of | |
360 | faces the last call to `ansi-color-apply-on-region' ended with, and | |
361 | MARKER is a buffer position within an escape sequence or the last | |
362 | position processed.") | |
363 | (make-variable-buffer-local 'ansi-color-context-region) | |
8737bb5a | 364 | |
0e3c1e3e | 365 | (defun ansi-color-filter-region (begin end) |
bc8d33d5 | 366 | "Filter out all ANSI control sequences from region BEGIN to END. |
0e3c1e3e GM |
367 | |
368 | Every call to this function will set and use the buffer-local variable | |
369 | `ansi-color-context-region' to save position. This information will be | |
370 | used for the next call to `ansi-color-apply-on-region'. Specifically, | |
371 | it will override BEGIN, the start of the region. Set | |
372 | `ansi-color-context-region' to nil if you don't want this." | |
373 | (let ((end-marker (copy-marker end)) | |
374 | (start (or (cadr ansi-color-context-region) begin))) | |
375 | (save-excursion | |
376 | (goto-char start) | |
bc8d33d5 CY |
377 | ;; Delete unrecognized escape sequences. |
378 | (while (re-search-forward ansi-color-drop-regexp end-marker t) | |
379 | (replace-match "")) | |
380 | (goto-char start) | |
381 | ;; Delete SGR escape sequences. | |
0e3c1e3e | 382 | (while (re-search-forward ansi-color-regexp end-marker t) |
0e3c1e3e | 383 | (replace-match "")) |
bc8d33d5 CY |
384 | ;; save context, add the remainder of the string to the result |
385 | (if (re-search-forward "\033" end-marker t) | |
386 | (setq ansi-color-context-region (list nil (match-beginning 0))) | |
387 | (setq ansi-color-context-region nil))))) | |
986b7dee | 388 | |
0e3c1e3e GM |
389 | (defun ansi-color-apply-on-region (begin end) |
390 | "Translates SGR control sequences into overlays or extents. | |
bc8d33d5 | 391 | Delete all other control sequences without processing them. |
986b7dee | 392 | |
bc8d33d5 CY |
393 | SGR control sequences are applied by setting foreground and |
394 | background colors to the text between BEGIN and END using | |
395 | overlays. The colors used are given in `ansi-color-faces-vector' | |
396 | and `ansi-color-names-vector'. See `ansi-color-apply-sequence' | |
397 | for details. | |
0e3c1e3e GM |
398 | |
399 | Every call to this function will set and use the buffer-local variable | |
400 | `ansi-color-context-region' to save position and current face. This | |
401 | information will be used for the next call to | |
402 | `ansi-color-apply-on-region'. Specifically, it will override BEGIN, the | |
403 | start of the region and set the face with which to start. Set | |
404 | `ansi-color-context-region' to nil if you don't want this." | |
405 | (let ((face (car ansi-color-context-region)) | |
71296446 | 406 | (start-marker (or (cadr ansi-color-context-region) |
0e3c1e3e GM |
407 | (copy-marker begin))) |
408 | (end-marker (copy-marker end)) | |
409 | escape-sequence) | |
bc8d33d5 CY |
410 | ;; First, eliminate unrecognized ANSI control sequences. |
411 | (save-excursion | |
412 | (goto-char start-marker) | |
413 | (while (re-search-forward ansi-color-drop-regexp end-marker t) | |
414 | (replace-match ""))) | |
986b7dee | 415 | (save-excursion |
0e3c1e3e | 416 | (goto-char start-marker) |
bc8d33d5 | 417 | ;; Find the next SGR sequence. |
0e3c1e3e | 418 | (while (re-search-forward ansi-color-regexp end-marker t) |
bc8d33d5 | 419 | ;; Colorize the old block from start to end using old face. |
0e3c1e3e GM |
420 | (when face |
421 | (ansi-color-set-extent-face | |
422 | (ansi-color-make-extent start-marker (match-beginning 0)) | |
423 | face)) | |
424 | ;; store escape sequence and new start position | |
425 | (setq escape-sequence (match-string 1) | |
426 | start-marker (copy-marker (match-end 0))) | |
427 | ;; delete the escape sequence | |
428 | (replace-match "") | |
429 | ;; create new face by applying all the parameters in the escape | |
430 | ;; sequence | |
431 | (setq face (ansi-color-apply-sequence escape-sequence face))) | |
432 | ;; search for the possible start of a new escape sequence | |
433 | (if (re-search-forward "\033" end-marker t) | |
434 | (progn | |
435 | ;; if the rest of the region should have a face, put it there | |
436 | (when face | |
437 | (ansi-color-set-extent-face | |
438 | (ansi-color-make-extent start-marker (point)) | |
439 | face)) | |
440 | ;; save face and point | |
441 | (setq ansi-color-context-region | |
442 | (list face (copy-marker (match-beginning 0))))) | |
443 | ;; if the rest of the region should have a face, put it there | |
444 | (if face | |
445 | (progn | |
446 | (ansi-color-set-extent-face | |
447 | (ansi-color-make-extent start-marker end-marker) | |
448 | face) | |
449 | (setq ansi-color-context-region (list face))) | |
450 | ;; reset context | |
451 | (setq ansi-color-context-region nil)))))) | |
452 | ||
453 | ;; This function helps you look for overlapping overlays. This is | |
454 | ;; usefull in comint-buffers. Overlapping overlays should not happen! | |
455 | ;; A possible cause for bugs are the markers. If you create an overlay | |
456 | ;; up to the end of the region, then that end might coincide with the | |
457 | ;; process-mark. As text is added BEFORE the process-mark, the overlay | |
458 | ;; will keep growing. Therefore, as more overlays are created later on, | |
459 | ;; there will be TWO OR MORE overlays covering the buffer at that point. | |
460 | ;; This function helps you check your buffer for these situations. | |
461 | ; (defun ansi-color-debug-overlays () | |
462 | ; (interactive) | |
463 | ; (let ((pos (point-min))) | |
464 | ; (while (< pos (point-max)) | |
465 | ; (if (<= 2 (length (overlays-at pos))) | |
466 | ; (progn | |
467 | ; (goto-char pos) | |
468 | ; (error "%d overlays at %d" (length (overlays-at pos)) pos)) | |
469 | ; (let (message-log-max) | |
470 | ; (message "Reached %d." pos))) | |
471 | ; (setq pos (next-overlay-change pos))))) | |
472 | ||
473 | ;; Emacs/XEmacs compatibility layer | |
474 | ||
475 | (defun ansi-color-make-face (property color) | |
476 | "Return a face with PROPERTY set to COLOR. | |
71296446 | 477 | PROPERTY can be either symbol `foreground' or symbol `background'. |
0e3c1e3e GM |
478 | |
479 | For Emacs, we just return the cons cell \(PROPERTY . COLOR). | |
480 | For XEmacs, we create a temporary face and return it." | |
481 | (if (featurep 'xemacs) | |
482 | (let ((face (make-face (intern (concat color "-" (symbol-name property))) | |
483 | "Temporary face created by ansi-color." | |
484 | t))) | |
485 | (set-face-property face property color) | |
486 | face) | |
487 | (cond ((eq property 'foreground) | |
488 | (cons 'foreground-color color)) | |
489 | ((eq property 'background) | |
490 | (cons 'background-color color)) | |
491 | (t | |
492 | (cons property color))))) | |
493 | ||
494 | (defun ansi-color-make-extent (from to &optional object) | |
495 | "Make an extent for the range [FROM, TO) in OBJECT. | |
496 | ||
497 | OBJECT defaults to the current buffer. XEmacs uses `make-extent', Emacs | |
498 | uses `make-overlay'. XEmacs can use a buffer or a string for OBJECT, | |
499 | Emacs requires OBJECT to be a buffer." | |
c8f0dac9 | 500 | (if (fboundp 'make-extent) |
0e3c1e3e GM |
501 | (make-extent from to object) |
502 | ;; In Emacs, the overlay might end at the process-mark in comint | |
503 | ;; buffers. In that case, new text will be inserted before the | |
504 | ;; process-mark, ie. inside the overlay (using insert-before-marks). | |
505 | ;; In order to avoid this, we use the `insert-behind-hooks' overlay | |
506 | ;; property to make sure it works. | |
507 | (let ((overlay (make-overlay from to object))) | |
508 | (overlay-put overlay 'modification-hooks '(ansi-color-freeze-overlay)) | |
509 | overlay))) | |
510 | ||
511 | (defun ansi-color-freeze-overlay (overlay is-after begin end &optional len) | |
512 | "Prevent OVERLAY from being extended. | |
513 | This function can be used for the `modification-hooks' overlay | |
514 | property." | |
515 | ;; if stuff was inserted at the end of the overlay | |
516 | (when (and is-after | |
517 | (= 0 len) | |
518 | (= end (overlay-end overlay))) | |
519 | ;; reset the end of the overlay | |
520 | (move-overlay overlay (overlay-start overlay) begin))) | |
521 | ||
522 | (defun ansi-color-set-extent-face (extent face) | |
523 | "Set the `face' property of EXTENT to FACE. | |
524 | XEmacs uses `set-extent-face', Emacs uses `overlay-put'." | |
a445370f | 525 | (if (featurep 'xemacs) |
0e3c1e3e GM |
526 | (set-extent-face extent face) |
527 | (overlay-put extent 'face face))) | |
986b7dee | 528 | |
8737bb5a GM |
529 | ;; Helper functions |
530 | ||
0e3c1e3e GM |
531 | (defun ansi-color-apply-sequence (escape-sequence faces) |
532 | "Apply ESCAPE-SEQ to FACES and return the new list of faces. | |
533 | ||
534 | ESCAPE-SEQ is an escape sequences parsed by `ansi-color-get-face'. | |
535 | ||
536 | If the new faces start with the symbol `default', then the new | |
537 | faces are returned. If the faces start with something else, | |
538 | they are appended to the front of the FACES list, and the new | |
539 | list of faces is returned. | |
540 | ||
541 | If `ansi-color-get-face' returns nil, then we either got a | |
542 | null-sequence, or we stumbled upon some garbage. In either | |
543 | case we return nil." | |
544 | (let ((new-faces (ansi-color-get-face escape-sequence))) | |
545 | (cond ((null new-faces) | |
546 | nil) | |
547 | ((eq (car new-faces) 'default) | |
548 | (cdr new-faces)) | |
549 | (t | |
7f0986e3 RS |
550 | ;; Like (append NEW-FACES FACES) |
551 | ;; but delete duplicates in FACES. | |
552 | (let ((modified-faces (copy-sequence faces))) | |
553 | (dolist (face (nreverse new-faces)) | |
554 | (setq modified-faces (delete face modified-faces)) | |
555 | (push face modified-faces)) | |
556 | modified-faces))))) | |
0e3c1e3e | 557 | |
986b7dee GM |
558 | (defun ansi-color-make-color-map () |
559 | "Creates a vector of face definitions and returns it. | |
560 | ||
561 | The index into the vector is an ANSI code. See the documentation of | |
562 | `ansi-color-map' for an example. | |
563 | ||
564 | The face definitions are based upon the variables | |
565 | `ansi-color-faces-vector' and `ansi-color-names-vector'." | |
566 | (let ((ansi-color-map (make-vector 50 nil)) | |
567 | (index 0)) | |
568 | ;; miscellaneous attributes | |
c04c01ca | 569 | (mapc |
986b7dee GM |
570 | (function (lambda (e) |
571 | (aset ansi-color-map index e) | |
572 | (setq index (1+ index)) )) | |
573 | ansi-color-faces-vector) | |
986b7dee GM |
574 | ;; foreground attributes |
575 | (setq index 30) | |
c04c01ca | 576 | (mapc |
986b7dee GM |
577 | (function (lambda (e) |
578 | (aset ansi-color-map index | |
0e3c1e3e | 579 | (ansi-color-make-face 'foreground e)) |
986b7dee GM |
580 | (setq index (1+ index)) )) |
581 | ansi-color-names-vector) | |
986b7dee GM |
582 | ;; background attributes |
583 | (setq index 40) | |
c04c01ca | 584 | (mapc |
986b7dee GM |
585 | (function (lambda (e) |
586 | (aset ansi-color-map index | |
0e3c1e3e | 587 | (ansi-color-make-face 'background e)) |
986b7dee GM |
588 | (setq index (1+ index)) )) |
589 | ansi-color-names-vector) | |
590 | ansi-color-map)) | |
591 | ||
592 | (defvar ansi-color-map (ansi-color-make-color-map) | |
0e3c1e3e | 593 | "A brand new color map suitable for `ansi-color-get-face'. |
986b7dee GM |
594 | |
595 | The value of this variable is usually constructed by | |
596 | `ansi-color-make-color-map'. The values in the array are such that the | |
597 | numbers included in an SGR control sequences point to the correct | |
598 | foreground or background colors. | |
599 | ||
600 | Example: The sequence \033[34m specifies a blue foreground. Therefore: | |
601 | (aref ansi-color-map 34) | |
602 | => \(foreground-color . \"blue\")") | |
603 | ||
604 | (defun ansi-color-map-update (symbol value) | |
605 | "Update `ansi-color-map'. | |
606 | ||
607 | Whenever the vectors used to construct `ansi-color-map' are changed, | |
608 | this function is called. Therefore this function is listed as the :set | |
609 | property of `ansi-color-faces-vector' and `ansi-color-names-vector'." | |
610 | (set-default symbol value) | |
611 | (setq ansi-color-map (ansi-color-make-color-map))) | |
612 | ||
613 | (defun ansi-color-get-face-1 (ansi-code) | |
614 | "Get face definition from `ansi-color-map'. | |
615 | ANSI-CODE is used as an index into the vector." | |
616 | (condition-case nil | |
617 | (aref ansi-color-map ansi-code) | |
74f24ba7 | 618 | (args-out-of-range nil))) |
986b7dee GM |
619 | |
620 | (defun ansi-color-get-face (escape-seq) | |
621 | "Create a new face by applying all the parameters in ESCAPE-SEQ. | |
622 | ||
0e3c1e3e GM |
623 | Should any of the parameters result in the default face (usually this is |
624 | the parameter 0), then the effect of all previous parameters is cancelled. | |
625 | ||
626 | ESCAPE-SEQ is a SGR control sequences such as \\033[34m. The parameter | |
986b7dee | 627 | 34 is used by `ansi-color-get-face-1' to return a face definition." |
c21d4d1a | 628 | (let ((i 0) |
0e3c1e3e | 629 | f val) |
c21d4d1a | 630 | (while (string-match ansi-color-parameter-regexp escape-seq i) |
0e3c1e3e GM |
631 | (setq i (match-end 0) |
632 | val (ansi-color-get-face-1 | |
c21d4d1a | 633 | (string-to-number (match-string 1 escape-seq) 10))) |
0e3c1e3e GM |
634 | (cond ((not val)) |
635 | ((eq val 'default) | |
636 | (setq f (list val))) | |
637 | (t | |
7f0986e3 RS |
638 | (unless (member val f) |
639 | (push val f))))) | |
986b7dee | 640 | f)) |
618206ea RS |
641 | |
642 | (provide 'ansi-color) | |
643 | ||
cbee283d | 644 | ;; arch-tag: 00726118-9432-44fd-b72d-d2af7591c99c |
8737bb5a | 645 | ;;; ansi-color.el ends here |