4

When executing the command shell-command, the output shown in the associated buffer is not colorized.

This is particularly annoying when calling a testing framework (outputting yellow/green/red...) from within emacs.

How can I configure, or extend, emacs in order to have shell-command allowing colorized output in the shell and preserving the colors while representing that output?

Thanks!

ps. I'm using the Bash shell, on a UN*X system.

mgodinho
  • 155
  • 2
  • 6

4 Answers4

3

This is probably what you want :

(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
Chmouel Boudjnah
  • 2,541
  • 3
  • 24
  • 28
  • 1
    had tried that hook before, in combination with _(autoload 'ansi-color-for-comint-mode-on "ansi-color" nil t)_, but it seems to only affect the **shell-mode** and not a simple **shell-command**. – mgodinho Jan 20 '11 at 07:14
  • @mgodinho: Well, the accepted answer is not doing a shell-command is opening a shell-mode (with a renamed buffer) and without this add-hook the accepted answer is not producing any color. at least for me. – Pablo Marin-Garcia Apr 28 '11 at 13:17
3

You can implement your own shell-execute, something like

(defun my-shell-execute(cmd)
   (interactive "sShell command: ")
   (shell (get-buffer-create "my-shell-buf"))
   (process-send-string (get-buffer-process "my-shell-buf") (concat cmd "\n")))
Oleg Pavliv
  • 20,462
  • 7
  • 59
  • 75
  • nice hack, i did implement it with a little tweak: _(concat "reset\n" cmd "\nexit 0 &> /dev/null\n")_ – mgodinho Jan 20 '11 at 08:00
  • Very cool, and @mgodinho hack prevents triggering the shell init prompt at each subsequent invocation. My Emacs looks like an IDE now :) – yPhil Sep 20 '15 at 10:45
1

This adds an advice to run ansi-color-apply-on-region on the minibuffer after shell-command finishes:

(require 'ansi-color)

(defun ansi-color-apply-on-buffer ()
    (ansi-color-apply-on-region (point-min) (point-max)))

(defun ansi-color-apply-on-minibuffer ()
  (let ((bufs (remove-if-not
               (lambda (x) (string-starts-with (buffer-name x) " *Echo Area"))
               (buffer-list))))
    (dolist (buf bufs)
      (with-current-buffer buf
        (ansi-color-apply-on-buffer)))))

(defun ansi-color-apply-on-minibuffer-advice (proc &rest rest)
  (ansi-color-apply-on-minibuffer))

(advice-add 'shell-command :after #'ansi-color-apply-on-minibuffer-advice)
;; (advice-remove 'shell-command #'ansi-color-apply-on-minibuffer-advice)

It does not rely on shell-mode or comint. I accompany it with something like the following to get nice test output (a green smiley with the count of successful doctests.

(defun add-test-function (cmd)
  (interactive "sCommand to run: ")
  (setq my-testall-test-function cmd)
  (defun my-testall ()
    (interactive)
    (shell-command my-testall-test-function))
  (local-set-key [f9] 'my-testall))
Arne Babenhauserheide
  • 2,423
  • 29
  • 23
0

This solution is inspired by @ArneBabenhauserheide's but uses xterm-color instead of ansi-color. It also colorizes the *Shell Command Output* buffer as well as the mini

(defun xterm-color-colorize-shell-command-output ()
  "Colorize `shell-command' output."
  (let ((bufs
         (seq-remove
          (lambda (x)
            (not (or (string-prefix-p " *Echo Area" (buffer-name x))
                     (string-prefix-p "*Shell Command" (buffer-name x)))))
          (buffer-list))))
    (dolist (buf bufs)
      (with-current-buffer buf
        (xterm-color-colorize-buffer)))))

(defun xterm-color-colorize-shell-command-output-advice (proc &rest rest)
  (xterm-color-colorize-shell-command-output))

(advice-add 'shell-command :after #'xterm-color-colorize-shell-command-output-advice)
;; (advice-remove 'shell-command #'xterm-color-colorize-shell-command-output-advice)

Chris
  • 2,166
  • 1
  • 24
  • 37