diff options
| author | Noam Postavsky | 2017-06-15 23:23:44 -0400 |
|---|---|---|
| committer | Noam Postavsky | 2017-07-03 10:09:40 -0400 |
| commit | 35ed01dfb3f811a997e26d843e9971eb6b81b125 (patch) | |
| tree | 722d1f4750056d1c04288a0b8f3d92419a4a11fe | |
| parent | a7754a250b74c17e1f63194e601f20fdb911dd7c (diff) | |
| download | emacs-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.el | 115 |
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 | ||
| 307 | This function can be added to `comint-preoutput-filter-functions'." | 302 | This 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 |