Subject: bug#28892: 24.5; Allow multiple compilations to append to an existing compilation buffer

From: Ludovic Brenta <[email-masked]>
Date: Wed, 18 Oct 2017 17:24:02 +0100

Severity: wishlist

There are use cases for compilation-mode that would benefit from an
"append" feature.  For example, M-x grep places results in a *grep*
compilation buffer and it would be nice to be able to start a new grep
command that appends to the same buffer.

We use this for cross-references emitted by gnatfind (part of the GNU 
Ada
compiler suite) in a buffer named *gnatfind*.  We would like to be able 
to
call gnatfind with a prefix argument to append new references to this
buffer, without moving point in the *gnatfind* buffer.

Currently, compilation-start unconditionally empties the compilation
buffer before doing anything.

I have a crude workaround consisting in starting the new gnatfind
compilation in a new temporary buffer (created with
generate-new-buffer-name), waiting for the compilation to finish, and
finally, in a compilation-finished-functions hook, appending the 
contents
of the temporary buffer to the *gnatfind* buffer.  This has drawbacks:

* compilation-start raises the new *gnatfind*<2> buffer before starting
   the compilation, disrupting any browsing the user was doing in
   *gnatfind*;

* the new contents are added to *gnatfind* only after the compilation
   finishes

So I think some adjustments to compilation-start (i.e. a new argument)
would be necessary for a full solution.

For the record here is my current workaround:

(defun ada-gnat-xref-all (identifier file line col local-only append)
   "For `ada-xref-all-function'."
   (let* ((arg (ada-gnat-xref-common-args identifier file line col)))
     (setq arg (cons "-r" arg))
     (when local-only (setq arg (append arg (list file))))

     (with-current-buffer (gnat-run-buffer); for default-directory
       (let* ((compilation-buffer-name "*gnatfind*")
              (compilation-error "reference")
              (command-and-args (mapconcat (lambda (a) (or a ""))
                                           (cons 
(ada-gnat-xref-common-cmd) arg)
                                           " "))
              (gnatfind-buffer (get-buffer-create 
compilation-buffer-name))
              (saved-compilation-finish-functions 
compilation-finish-functions))
	;; compilation-environment is buffer-local; don't set in 'let'
	(setq compilation-environment (ada-prj-get 'proc_env))

	;; WORKAROUND: the 'compilation' API doesn't let us specify "append", 
so we use this.
         (add-hook 'compilation-finish-functions
                   (lambda (compilation-finished-buffer 
compilation-result)
                     (if append
                         (with-current-buffer gnatfind-buffer
                           (let ((inhibit-read-only t)
                                 (prev-pos (point)))
                             (goto-char (point-max))
                             (insert "\n")
                             (insert-buffer-substring 
compilation-finished-buffer)
                             (goto-char prev-pos)
                             (kill-buffer compilation-finished-buffer)))
                       ;; else
                       (progn
                         (kill-buffer gnatfind-buffer)
                         (with-current-buffer 
compilation-finished-buffer
                           (rename-buffer compilation-buffer-name))))
                     (setq compilation-finish-functions
                        saved-compilation-finish-functions)))

         ;; Now start the compilation in a new temporary buffer.
         (compilation-start command-and-args
                            'compilation-mode
                            (lambda (_name)
                              ;; If the result starts with a space, the 
buffer
                              ;; is hidden but no fontification occurs 
in it, so we
                              ;; return a name for a visible buffer.
                              (generate-new-buffer-name 
compilation-buffer-name)))))))

-- 
Ludovic Brenta.