5

I am running a process from within emacs which uses ANSI color codes in its output.

I'm using start-process to create the process, and provided a custom buffer name for the process's output

(start-process "foo" "*Foo*" foo-command foo-args)

If I open *Foo* buffer, the ANSI color codes are printed in their raw format to the buffer

^[[36msome output message^[[m
^[[1;35msome output message^[[m
^[[1;34msome output message^[[m

I see in this SO answer it is possible to add colorization to a buffer; however I'm unsure as to how to do it with a buffer created using start-process

Is it possible to convert those ANSI color codes to colorised output in my *Foo* buffer?

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213

2 Answers2

3

It doesn't look like the linked answers had any solutions not involving comint-mode. You can use ansi-color-apply-on-region to colorize the output buffer, eg.

(set-process-sentinel
 (start-process "foo" "*Foo*" foo-command foo-args)
 (lambda (p _m)
   (when (eq 0 (process-exit-status p))
     (with-current-buffer (process-buffer p)
       (ansi-color-apply-on-region (point-min) (point-max))))))
Rorschach
  • 31,301
  • 5
  • 78
  • 129
  • Thanks, that's awesome, literally copy-pasted your snippet and it worked! – Steve Lorimer Jun 03 '17 at 21:56
  • 1
    Hmmm, unfortunately (and quite obviously given the mechanics of the code) the buffer will display the control codes whilst the process is executing, and only afterwards, once complete, call `ansi-color-apply-on-region`. Do you know if it's possible to apply the `ansi-color` transformations "on-the-fly"? – Steve Lorimer Jun 03 '17 at 22:11
  • @SteveLorimer I think perhaps the easiest way would be to just start the buffer in `comint-mode`. Otherwise, you can make a `process-filter` and apply the color in your filter. – Rorschach Jun 03 '17 at 22:16
3

Here's a solution that will display the colors while the process is executing (rather than after the process is complete and calling ansi-color-apply-on-region)

The key is the last line: set-process-filter.

(defun runserver ()
  (interactive)
  (setq *server-buffer* (get-buffer-create "server"))
  (with-current-buffer *server-buffer*
    (ansi-color-for-comint-mode-on)
    (comint-mode))
  (let ((default-directory "~/server/"))
    (setq *server-process*
          (start-process-shell-command
           "server" *server-buffer* "./run_server")))
  (set-process-filter *server-process* 'comint-output-filter))

A process filter function is a function that receives the standard output from the associated process. All output from that process is passed to the filter. The default filter simply outputs directly to the process buffer.

Eric Ihli
  • 1,722
  • 18
  • 30