aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoam Postavsky2017-06-15 23:23:44 -0400
committerNoam Postavsky2017-07-03 10:09:40 -0400
commit35ed01dfb3f811a997e26d843e9971eb6b81b125 (patch)
tree722d1f4750056d1c04288a0b8f3d92419a4a11fe
parenta7754a250b74c17e1f63194e601f20fdb911dd7c (diff)
downloademacs-35ed01dfb3f811a997e26d843e9971eb6b81b125.tar.gz
emacs-35ed01dfb3f811a997e26d843e9971eb6b81b125.zip
Fix and simplify ansi escape detection (Bug#21381)
* lisp/ansi-color.el (ansi-color-regexp, ansi-color-drop-regexp): Remove. (ansi-color-control-seq-regexp): New constant, matches all escape sequences. (ansi-color-filter-apply, ansi-color-apply) (ansi-color-filter-region, ansi-color-apply-on-region): Use it instead of matching color sequences separately from ignored sequences. Differentiate color sequences simply by checking the last character.
-rw-r--r--lisp/ansi-color.el115
1 files changed, 48 insertions, 67 deletions
diff --git a/lisp/ansi-color.el b/lisp/ansi-color.el
index 47437bb7c87..a1b49331754 100644
--- a/lisp/ansi-color.el
+++ b/lisp/ansi-color.el
@@ -150,17 +150,14 @@ foreground and background colors, respectively."
150 :version "24.4" ; default colors copied from `xterm-standard-colors' 150 :version "24.4" ; default colors copied from `xterm-standard-colors'
151 :group 'ansi-colors) 151 :group 'ansi-colors)
152 152
153(defconst ansi-color-regexp "\033\\[\\([0-9;]*m\\)" 153(defconst ansi-color-control-seq-regexp
154 "Regexp that matches SGR control sequences.") 154 ;; See ECMA 48, section 5.4 "Control Sequences".
155 155 "\e\\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]"
156(defconst ansi-color-drop-regexp 156 "Regexp matching an ANSI control sequence.")
157 "\033\\[\\([ABCDsuK]\\|[12][JK]\\|=[0-9]+[hI]\\|[0-9;]*[Hf]\\|\\?[0-9]+[hl]\\)"
158 "Regexp that matches ANSI control sequences to silently drop.")
159 157
160(defconst ansi-color-parameter-regexp "\\([0-9]*\\)[m;]" 158(defconst ansi-color-parameter-regexp "\\([0-9]*\\)[m;]"
161 "Regexp that matches SGR control sequence parameters.") 159 "Regexp that matches SGR control sequence parameters.")
162 160
163
164;; Convenience functions for comint modes (eg. shell-mode) 161;; Convenience functions for comint modes (eg. shell-mode)
165 162
166 163
@@ -259,22 +256,20 @@ This function can be added to `comint-preoutput-filter-functions'."
259 (setq string (concat (cadr ansi-color-context) string) 256 (setq string (concat (cadr ansi-color-context) string)
260 ansi-color-context nil)) 257 ansi-color-context nil))
261 ;; find the next escape sequence 258 ;; find the next escape sequence
262 (while (setq end (string-match ansi-color-regexp string start)) 259 (while (setq end (string-match ansi-color-control-seq-regexp string start))
263 (setq result (concat result (substring string start end)) 260 (push (substring string start end) result)
264 start (match-end 0))) 261 (setq start (match-end 0)))
265 ;; eliminate unrecognized escape sequences
266 (while (string-match ansi-color-drop-regexp string)
267 (setq string
268 (replace-match "" nil nil string)))
269 ;; save context, add the remainder of the string to the result 262 ;; save context, add the remainder of the string to the result
270 (let (fragment) 263 (let (fragment)
271 (if (string-match "\033" string start) 264 (push (substring string start
272 (let ((pos (match-beginning 0))) 265 (if (string-match "\033" string start)
273 (setq fragment (substring string pos) 266 (let ((pos (match-beginning 0)))
274 result (concat result (substring string start pos)))) 267 (setq fragment (substring string pos))
275 (setq result (concat result (substring string start)))) 268 pos)
269 nil))
270 result)
276 (setq ansi-color-context (if fragment (list nil fragment)))) 271 (setq ansi-color-context (if fragment (list nil fragment))))
277 result)) 272 (apply #'concat (nreverse result))))
278 273
279(defun ansi-color--find-face (codes) 274(defun ansi-color--find-face (codes)
280 "Return the face corresponding to CODES." 275 "Return the face corresponding to CODES."
@@ -306,35 +301,29 @@ Set `ansi-color-context' to nil if you don't want this.
306 301
307This function can be added to `comint-preoutput-filter-functions'." 302This function can be added to `comint-preoutput-filter-functions'."
308 (let ((codes (car ansi-color-context)) 303 (let ((codes (car ansi-color-context))
309 (start 0) end escape-sequence result 304 (start 0) end result)
310 colorized-substring)
311 ;; If context was saved and is a string, prepend it. 305 ;; If context was saved and is a string, prepend it.
312 (if (cadr ansi-color-context) 306 (if (cadr ansi-color-context)
313 (setq string (concat (cadr ansi-color-context) string) 307 (setq string (concat (cadr ansi-color-context) string)
314 ansi-color-context nil)) 308 ansi-color-context nil))
315 ;; Find the next escape sequence. 309 ;; Find the next escape sequence.
316 (while (setq end (string-match ansi-color-regexp string start)) 310 (while (setq end (string-match ansi-color-control-seq-regexp string start))
317 (setq escape-sequence (match-string 1 string)) 311 (let ((esc-end (match-end 0)))
318 ;; Colorize the old block from start to end using old face. 312 ;; Colorize the old block from start to end using old face.
319 (when codes 313 (when codes
320 (put-text-property start end 'font-lock-face (ansi-color--find-face codes) string)) 314 (put-text-property start end 'font-lock-face
321 (setq colorized-substring (substring string start end) 315 (ansi-color--find-face codes) string))
322 start (match-end 0)) 316 (push (substring string start end) result)
323 ;; Eliminate unrecognized ANSI sequences. 317 (setq start (match-end 0))
324 (while (string-match ansi-color-drop-regexp colorized-substring) 318 ;; If this is a color escape sequence,
325 (setq colorized-substring 319 (when (eq (aref string (1- esc-end)) ?m)
326 (replace-match "" nil nil colorized-substring))) 320 ;; create a new face from it.
327 (push colorized-substring result) 321 (setq codes (ansi-color-apply-sequence
328 ;; Create new face, by applying escape sequence parameters. 322 (substring string end esc-end) codes)))))
329 (setq codes (ansi-color-apply-sequence escape-sequence codes)))
330 ;; if the rest of the string should have a face, put it there 323 ;; if the rest of the string should have a face, put it there
331 (when codes 324 (when codes
332 (put-text-property start (length string) 325 (put-text-property start (length string)
333 'font-lock-face (ansi-color--find-face codes) string)) 326 'font-lock-face (ansi-color--find-face codes) string))
334 ;; eliminate unrecognized escape sequences
335 (while (string-match ansi-color-drop-regexp string)
336 (setq string
337 (replace-match "" nil nil string)))
338 ;; save context, add the remainder of the string to the result 327 ;; save context, add the remainder of the string to the result
339 (let (fragment) 328 (let (fragment)
340 (if (string-match "\033" string start) 329 (if (string-match "\033" string start)
@@ -367,13 +356,9 @@ it will override BEGIN, the start of the region. Set
367 (start (or (cadr ansi-color-context-region) begin))) 356 (start (or (cadr ansi-color-context-region) begin)))
368 (save-excursion 357 (save-excursion
369 (goto-char start) 358 (goto-char start)
370 ;; Delete unrecognized escape sequences. 359 ;; Delete escape sequences.
371 (while (re-search-forward ansi-color-drop-regexp end-marker t) 360 (while (re-search-forward ansi-color-control-seq-regexp end-marker t)
372 (replace-match "")) 361 (delete-region (match-beginning 0) (match-end 0)))
373 (goto-char start)
374 ;; Delete SGR escape sequences.
375 (while (re-search-forward ansi-color-regexp end-marker t)
376 (replace-match ""))
377 ;; save context, add the remainder of the string to the result 362 ;; save context, add the remainder of the string to the result
378 (if (re-search-forward "\033" end-marker t) 363 (if (re-search-forward "\033" end-marker t)
379 (setq ansi-color-context-region (list nil (match-beginning 0))) 364 (setq ansi-color-context-region (list nil (match-beginning 0)))
@@ -400,28 +385,24 @@ this."
400 (let ((codes (car ansi-color-context-region)) 385 (let ((codes (car ansi-color-context-region))
401 (start-marker (or (cadr ansi-color-context-region) 386 (start-marker (or (cadr ansi-color-context-region)
402 (copy-marker begin))) 387 (copy-marker begin)))
403 (end-marker (copy-marker end)) 388 (end-marker (copy-marker end)))
404 escape-sequence)
405 ;; First, eliminate unrecognized ANSI control sequences.
406 (save-excursion
407 (goto-char start-marker)
408 (while (re-search-forward ansi-color-drop-regexp end-marker t)
409 (replace-match "")))
410 (save-excursion 389 (save-excursion
411 (goto-char start-marker) 390 (goto-char start-marker)
412 ;; Find the next SGR sequence. 391 ;; Find the next escape sequence.
413 (while (re-search-forward ansi-color-regexp end-marker t) 392 (while (re-search-forward ansi-color-control-seq-regexp end-marker t)
414 ;; Colorize the old block from start to end using old face. 393 ;; Remove escape sequence.
415 (funcall ansi-color-apply-face-function 394 (let ((esc-seq (delete-and-extract-region
416 start-marker (match-beginning 0) 395 (match-beginning 0) (point))))
417 (ansi-color--find-face codes)) 396 ;; Colorize the old block from start to end using old face.
418 ;; store escape sequence and new start position 397 (funcall ansi-color-apply-face-function
419 (setq escape-sequence (match-string 1) 398 (prog1 (marker-position start-marker)
420 start-marker (copy-marker (match-end 0))) 399 ;; Store new start position.
421 ;; delete the escape sequence 400 (set-marker start-marker (point)))
422 (replace-match "") 401 (match-beginning 0) (ansi-color--find-face codes))
423 ;; Update the list of ansi codes. 402 ;; If this is a color sequence,
424 (setq codes (ansi-color-apply-sequence escape-sequence codes))) 403 (when (eq (aref esc-seq (1- (length esc-seq))) ?m)
404 ;; update the list of ansi codes.
405 (setq codes (ansi-color-apply-sequence esc-seq codes)))))
425 ;; search for the possible start of a new escape sequence 406 ;; search for the possible start of a new escape sequence
426 (if (re-search-forward "\033" end-marker t) 407 (if (re-search-forward "\033" end-marker t)
427 (progn 408 (progn