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.

Husain
  • 485
  • 8
  • 12

5 Answers5

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.

Drew
  • 75,699
  • 9
  • 109
  • 225
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!")))))
shapr
  • 370
  • 2
  • 7
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)
Swarnendu Biswas
  • 1,378
  • 1
  • 11
  • 24
  • 2
    Please [do not post an answer that consists of just a link](http://meta.stackexchange.com/questions/225370/your-answer-is-in-another-castle-when-is-an-answer-not-an-answer). Include the essential parts of the answer in your post, so that your post answers the question. Provide the link as a source and for further information. For more information, please read our [guidelines on writing answers](http://emacs.stackexchange.com/help/how-to-answer). – Gilles 'SO- stop being evil' Feb 19 '15 at 22:12
  • Updated my answer. – Swarnendu Biswas Feb 21 '15 at 00:06
  • Note that [it is ok to quote someone else's answer from Stack Exchange](http://creativecommons.org/licenses/by-sa/3.0/), but you must provide [proper attribution](http://blog.stackoverflow.com/2009/06/attribution-required/), including the author's name. – Gilles 'SO- stop being evil' Feb 21 '15 at 00:30
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))))))
politza
  • 3,316
  • 14
  • 16
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

nitin
  • 21
  • 2
  • 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. – RealityMonster Oct 06 '22 at 03: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. – RealityMonster Oct 06 '22 at 04: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 '22 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. – RealityMonster Dec 01 '22 at 02:02
  • Well, if you ever got time to look at how [s.el defines s-contains?](https://github.com/magnars/s.el/blob/master/s.el#L320) 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 01 '22 at 04:54
  • About human-readable syntax, clumsy, hard-to-read, hard-to-remember native proteins and vitamins are healthier than eating loads of syntactic sugaries :P – nitin Dec 01 '22 at 05:07