Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Don't display *compilation* buffer in Emacs until the process exits with error or warning

I am looking for a way to have the Emacs compilation buffer triggered by M-x compile, M-x recompile or some compile on save script only appear when the compilation exits either with an error or a warning.

Note that I am not looking for a way to close the compile buffer if there are no errors or warnings as described in [1]. No I want the buffer to never appear until the compilation is fully finished and only appear if there is an error or warning to display.

The reasons are simple: The flickering compile buffer is disturbing and rearranges the position of the code on the screen. This becomes more annoying if you have compile on save turned on.

The compile buffer contains many different types of compile processes from make to pdflatex so it would be great if the function which determines whether the buffer should be displayed works across the board.

[1] emacs compile buffer auto close?

like image 942
Rovanion Avatar asked Jul 15 '13 16:07

Rovanion


People also ask

How do I run a compiled program in Emacs?

To run make or another compilation command, type M-x compile . This reads a shell command line using the minibuffer, and then executes the command by running a shell as a subprocess (or inferior process) of Emacs.

Does Emacs have a compiler?

Emacs can run compilers for languages such as C and Fortran, feeding the compilation log into an Emacs buffer. It can also parse the error messages and show you where the errors occurred.

What is compilation mode?

Compilation mode turns each error message in the buffer into a hyperlink; you can move point to it and type RET, or click on it with the mouse (see Mouse References), to visit the locus of the error message in a separate window. The locus is the specific position in a file where that error occurred.

Can you run code in Emacs?

To execute a file of Emacs Lisp code, use M-x load-file . This command reads a file name using the minibuffer and then executes the contents of that file as Lisp code. It is not necessary to visit the file first; in any case, this command reads the file as found on disk, not text in an Emacs buffer.


4 Answers

Looks like you can achieve what you want through temporarily disabling display-buffer across compilation-start.

This is a combination of what sds said and something posted on the comments @ here

The comment there had a nasty problem with point jumping in the original source buffer that I appear to have worked out by also blocking set-window-point and goto-char. It feels like a dirty hack, but is working so far. YMMV!

(defun brian-compile-finish (buffer outstr)
  (unless (string-match "finished" outstr)
    (switch-to-buffer-other-window buffer))
  t)

(setq compilation-finish-functions 'brian-compile-finish)

(require 'cl)

(defadvice compilation-start
  (around inhibit-display
      (command &optional mode name-function highlight-regexp)) 
  (if (not (string-match "^\\(find\\|grep\\)" command))
      (flet ((display-buffer)
         (set-window-point)
         (goto-char)) 
    (fset 'display-buffer 'ignore)
    (fset 'goto-char 'ignore)
    (fset 'set-window-point 'ignore)
    (save-window-excursion 
      ad-do-it))
    ad-do-it))

(ad-activate 'compilation-start)

Now you should see that all compile buffers will only be shown if outstr doesn't return a successful finish status OR the invoked command started with "find" or "grep."

like image 74
assem Avatar answered Sep 28 '22 07:09

assem


I edited @assem's answer to use cl-letf instead of flet.

(defun brian-compile-finish (buffer outstr)
  (unless (string-match "finished" outstr)
    (switch-to-buffer-other-window buffer))
  t)

(setq compilation-finish-functions 'brian-compile-finish)

(defadvice compilation-start
  (around inhibit-display
      (command &optional mode name-function highlight-regexp))
  (if (not (string-match "^\\(find\\|grep\\)" command))
      (cl-letf ((display-buffer   #'ignore)
                (set-window-point #'ignoreco)
                (goto-char        #'ignore))
        (save-window-excursion
          ad-do-it))
    ad-do-it))

(ad-activate 'compilation-start)

(provide 'only-display-compile-on-error)
like image 22
Rovanion Avatar answered Sep 29 '22 07:09

Rovanion


The function compilation-start calls display-buffer on the compilation buffer. This should give you all the control you need.

I.e., you need to customize one of the action variables (display-buffer-overriding-action et al) so that it will handle compilation buffers specially buy displaying it in a separate frame and not displaying the frame itself.

Then you need to customize your compilation-filter-hook so that, whenever a warning or an error is inserted into the compilation buffer, the compilation buffer is displayed visibly (e.g., by popping up the aforementioned separate frame). Don't forget to bind your action variable to nil there!

like image 40
sds Avatar answered Sep 29 '22 07:09

sds


assems answer has been overtaken by events, somewhat.

Emacs core, in their wisdom have decided to deprecate flet. The suggested alternative is cl-flet. However, as discussed in this post, this seems to be lexically scoped rather than dynamically scoped. We explicitly want dynamic scoping.

Should `flet` be replaced with `cl-flet` or `cl-letf` ?

This page suggests replace flet to noflet, a third-party library.

This appears to only support the definition of functions and their bodies. So the flet in assem's answer becomes

(noflet ((display-buffer ()) ....

like image 38
Att Righ Avatar answered Oct 02 '22 07:10

Att Righ