26

It is annoying to see the compilation window appear when it is successful. How to remove that automatically?

I want to see it though if it is not successful.

5 Answers 5

12

years ago on the #emacs IRC channel I got this bit of code I've been using forever. The value "2 sec" sets the amount of time the successful compilation window stays visible.

; from enberg on #emacs
(add-hook 'compilation-finish-functions
  (lambda (buf str)
    (if (null (string-match ".*exited abnormally.*" str))
        ;;no errors, make the compilation window go away in a few seconds
        (progn
          (run-at-time
           "2 sec" nil 'delete-windows-on
           (get-buffer-create "*compilation*"))
          (message "No Compilation Errors!")))))
1
  • Thanks, this is still very useful.
    – drgibbon
    Jul 28, 2022 at 18:29
15

Looking quickly at the code (in library compile.el), you should be able to just kill or hide the displayed buffer by using a function on hook compilation-finish-functions. To do that, use something like this:

 (add-hook 'compilation-finish-functions (lambda (buf strg) (kill-buffer buf))

If you don't want to kill the buffer, then use something like this:

 (add-hook 'compilation-finish-functions
           (lambda (buf strg)
             (let ((win  (get-buffer-window buf 'visible)))
               (when win (delete-window win)))))

In general, you can imagine that for something like this there is probably a hook already provided, so you can easily attach code at such a significant place in the processing. A little browsing of the code or using M-x apropos will typically quickly let you know. The names of hooks typically end in -hook or -functions.

3

I have this snippet in my .emacs.d:

    (defcustom compilation-auto-quit-window-delay 1
      "Time in seconds before auto closing the window."
      :group 'compilation
      :type 'number)  

    (defun compilation-auto-quit-window-finish-function (buffer status)
      "Quit the *compilation* window if it went well."
      (let ((window (get-buffer-window buffer)))
        (when (and (equal status "finished\n")
                   (compilation-went-super-p))
          (run-with-timer
              (or compilation-auto-quit-window-delay 0) nil
            (lambda nil
              (when (and (window-live-p window)
                         (eq (window-buffer window)
                             buffer)
                         (not (eq (selected-window)
                                  window)))
                (save-selected-window
                  (quit-window nil window))))))))

    (define-minor-mode compilation-auto-quit-window
      "Automatically close the *compilation* window if it went well."
      :global t
      (cond (compilation-auto-quit-window
             (add-hook 'compilation-finish-functions
                       'compilation-auto-quit-window-finish-function))
            (t
             (remove-hook 'compilation-finish-functions
                          'compilation-auto-quit-window-finish-function))))

    (defun compilation-went-super-p (&optional buffer)
      "Return t, if no gotoable output appeared."
      (with-current-buffer (or buffer (current-buffer))
        (save-excursion
          (goto-char (point-min))
          (let (;; (compilation-skip-threshold 1)
                )
            (not (ignore-errors
                   (compilation-next-error 1)
                   t))))))
3

This thread talks about how to autohide the compilation buffer when compilation succeeds and keep showing the buffer when there are errors or warnings. The use case may be relevant to many users.

The credit goes to the original author, jpkotta. Here is his answer:

I use the following for compilation. It keeps the compilation buffer if there are warnings or errors, and buries it otherwise (after 1 second).

(defun bury-compile-buffer-if-successful (buffer string)
  "Bury a compilation buffer if succeeded without warnings "
  (if (and
       (string-match "compilation" (buffer-name buffer))
       (string-match "finished" string)
       (not
        (with-current-buffer buffer
          (search-forward "warning" nil t))))
      (run-with-timer 1 nil
                      (lambda (buf)
                        (bury-buffer buf)
                        (switch-to-prev-buffer (get-buffer-window buf) 'kill))
                      buffer)))
(add-hook 'compilation-finish-functions 'bury-compile-buffer-if-successful)
3
1

I've tweaked above answers with better logic and tested it, working perfectly:

  1. Add Hooks to functions:
  (add-hook 'compilation-start-hook 'compilation-started)
  (add-hook 'compilation-finish-functions 'hide-compile-buffer-if-successful)
  1. Auto Hide Compile Buffer Delay Customizable Variable (via M-x customize-variable RET auto-hide-compile-buffer-delay):
  (defcustom auto-hide-compile-buffer-delay 0
    "Time in seconds before auto hiding compile buffer."
    :group 'compilation
    :type 'number
  )
  1. Get time taken in compilation and use compilation-num-* for warnings and errors count in compilation buffer:
  (defun hide-compile-buffer-if-successful (buffer string)
    (setq compilation-total-time (time-subtract nil compilation-start-time))
    (setq time-str (concat " (Time: " (format-time-string "%s.%3N" compilation-total-time) "s)"))

    (if
      (with-current-buffer buffer
        (setq warnings (eval compilation-num-warnings-found))
        (setq warnings-str (concat " (Warnings: " (number-to-string warnings) ")"))
        (setq errors (eval compilation-num-errors-found))

        (if (eq errors 0) nil t)
      )

      ;;If Errors then
      (message (concat "Compiled with Errors" warnings-str time-str))

      ;;If Compiled Successfully or with Warnings then
      (progn
        (bury-buffer buffer)
        (run-with-timer auto-hide-compile-buffer-delay nil 'delete-window (get-buffer-window buffer 'visible))
        (message (concat "Compiled Successfully" warnings-str time-str))
      )
    )
  )

  (make-variable-buffer-local 'compilation-start-time)

  (defun compilation-started (proc) 
    (setq compilation-start-time (current-time))
  )

Demo

6
  • I like this answer, but I found that it didn't work for link errors, only compile errors. I think that's actually a problem with emacs' compilation system; it's not a 'real' error because you can't jump to in. In previous compilation handling systems I've written I've actually searched backwards through the buffer looking for link errors. I'll probably modify this similarly at some point. Oct 6, 2022 at 3:53
  • Actually, here's a quick hack that will account for the issue regardless (and could actually replace the entire error count section). ``` (when (s-contains? "abnormal" string) (setq errors (+ errors 1))) ``` It does require that you're using the string manipulation library, s, but any string match there will work. Oct 6, 2022 at 4:12
  • Why use a manipulation library, when you can use this: (with-temp-buffer (insert string) (goto-char (point-min)) (looking-at "abnormal")). Also, looking-at can be replaced with search-forward or re-search-forward. Or, in one line you can use: (string-match-p (regexp-quote "abnormal") string)
    – nitin
    Nov 29, 2022 at 12:04
  • Because, frankly, the s library is far superior. (s-contains?) is a more human readable syntax, and it hews a little more closely to some of the Common Lisp syntax that I've read. Certainly elisp can do it natively, but there are many ways in which it's a clumsy, obtuse, hard-to-read language. Dec 1, 2022 at 2:02
  • Well, if you ever got time to look at how s.el defines s-contains? you'll find out its just a wrapper around string-match-p and I prefer learning native functions first and then jump onto libraries or end up making my own wrappers. Also, when bug occurs in code, one assumes the libraries are not the culprit. So, using s-contains? knowing it uses string-match-p is what I prefer rather than using s-contains? without knowing what native function it is using, this way I can program my functions as well as learn native functions better-ly.
    – nitin
    Dec 1, 2022 at 4:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.