[comp.emacs] Extension of compile.el to handle source in many directories

lupton@uhccux.uhcc.hawaii.edu (Robert Lupton) (02/02/90)

When you have source scattered down a directory hierarchy next-error
will only find the errors in the directory that you ran compile in. 
Here is a patch to compile.el that provides a search path. 

The only new function is compilation-make-dir-list which prompts you for
the path to use (the variable compilation-dir-list with default value
"."). If you don't specify a path (i.e. just hit <CR>) it'll create a
path consisting of all the subdirectories (and sub-subdirectories and so
on) of your current directory. 

			Robert
			
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*** /usr/local/emacs.18.51/emacs/lisp/compile.el	Sun Dec  6 01:27:59 1987
--- compile.el	Fri Dec 15 11:46:07 1989
***************
*** 17,22
  ;; can know your rights and responsibilities.  It should be in a
  ;; file named COPYING.  Among other things, the copyright notice
  ;; and this notice must be preserved on all copies.
  
  (provide 'compile)
  

--- 17,25 -----
  ;; can know your rights and responsibilities.  It should be in a
  ;; file named COPYING.  Among other things, the copyright notice
  ;; and this notice must be preserved on all copies.
+ ;;
+ ;; Added support for files spread over several directories
+ ;; December 1989, Robert Lupton (lupton@uhifa.ifa.hawaii.edu)
  
  (provide 'compile)
  
***************
*** 45,50
    "\\([^ \n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+ *of *[^ \n]+\\)"
    "Regular expression for filename/linenumber in error in compilation log.")
  
  (defun compile (command)
    "Compile the program including the current buffer.  Default: run make.
  Runs COMMAND, a shell command, in a separate process asynchronously

--- 48,56 -----
    "\\([^ \n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+ *of *[^ \n]+\\)"
    "Regular expression for filename/linenumber in error in compilation log.")
  
+ (defvar compilation-dir-list (list ".")
+   "list of directories to search for files with errors")
+ 
  (defun compile (command)
    "Compile the program including the current buffer.  Default: run make.
  Runs COMMAND, a shell command, in a separate process asynchronously
***************
*** 167,173
  If all preparsed error messages have been processed,
  the error message buffer is checked for new ones.
  A non-nil argument (prefix arg, if interactive)
! means reparse the error message buffer and start at the first error."
    (interactive "P")
    (if (or (eq compilation-error-list t)
  	  argp)

--- 173,182 -----
  If all preparsed error messages have been processed,
  the error message buffer is checked for new ones.
  A non-nil argument (prefix arg, if interactive)
! means reparse the error message buffer and start at the first error.
! The variable compilation-dir-list gives a list of directories to
! search for files; by default it only includes the current directory. The
! list may be set using compilation-make-dir-list"
    (interactive "P")
    (if (or (eq compilation-error-list t)
  	  argp)
***************
*** 270,277
  	  ;; text-buffer gets the buffer containing this error's file.
  	  (if (not (equal filename last-filename))
  	      (setq text-buffer
! 		    (and (file-exists-p (setq last-filename filename))
! 			 (find-file-noselect filename))
  		    last-linenum 0))
  	  (if text-buffer
  	      ;; Go to that buffer and find the erring line.

--- 279,297 -----
  	  ;; text-buffer gets the buffer containing this error's file.
  	  (if (not (equal filename last-filename))
  	      (setq text-buffer
! 		    ;; Look for the file in compilation-dir-list directories
! 		    (let ((dir compilation-dir-list) dir-filename)
! 		      (and
! 		       (progn
! 			 (while (and dir
! 				     (not (file-exists-p
! 					   (setq dir-filename
! 					   (concat (car dir) "/" filename)))))
! 			   (setq dir (cdr dir)))
! 			 dir-filename)
! 		       (setq last-filename filename)
! 		       (and (file-exists-p dir-filename)
! 			    (find-file-noselect dir-filename))))
  		    last-linenum 0))
  	  (if text-buffer
  	      ;; Go to that buffer and find the erring line.
***************
*** 305,309
  		      (progn
  			(skip-chars-forward "^ :,\n\t(")
  			(point)))))
  
  (define-key ctl-x-map "`" 'next-error)

--- 325,372 -----
  		      (progn
  			(skip-chars-forward "^ :,\n\t(")
  			(point)))))
+ 
+ (defun compilation-make-dir-list (str)
+ 
+   "Make a list of directories for next-error to search (. is added
+ automatically if you omit it). If you specify an empty string, all the
+ subdirectories of the current directory will be used."
+ 
+   (interactive "sDirectories: ")
+   (setq compilation-dir-list
+ 	(if (string= str "")
+ 	    (append (list ".") (sub-dirs "."))
+ 	  (string-to-list
+ 	    (if (not (string-match "\\(^\\|[ \t]\\)\\.[ \t]" str))
+ 		(setq str (concat ". " str)))))))
+ 
+ (defun string-to-list (str)
+   "Take a string of white-space separated words, and return them as a list"
+   (let ( str-list (start 0) end)
+     (while
+ 	(progn
+ 	  (setq str-list
+ 		(append str-list
+ 			(list (substring str start
+ 			     (setq end (string-match "[ \t\n]" str start))))))
+ 	  (setq start (and end (+ end 1)))))
+     str-list))
+ 
+ (defun sub-dirs (dir)
+   "Return a list of all subdirectories of DIR"
+   (interactive "DInitial directory? ")
+   (setq dir (concat (expand-file-name dir) "/"))
+   (let ( (dir-list)
+ 	 (file-list (directory-files dir))
+ 	 (file) )
+     (while (setq file (car file-list))
+       (if (and (not (or (string= file ".") (string= file "..")))
+ 	       (file-directory-p (concat dir file)))
+ 	  (let* ( (dir-name (concat dir file))
+ 		  (subs (sub-dirs dir-name)) )
+ 	    (setq dir-list (append dir-list
+ 				   (if subs subs (list dir-name))))))
+       (setq file-list (cdr file-list)))
+     dir-list)) 
  
  (define-key ctl-x-map "`" 'next-error)

lupton@uhccux.uhcc.hawaii.edu (Robert Lupton) (02/10/90)

Hmm, there's a small bug in my extended compile.el. The code to
automatically use all subdirectories was only finding leaf directories,
here's a patch (i.e. apply my other stuff first, then this patch)

			Robert
			
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
*** compile.el.1	Fri Dec 15 11:46:07 1989
--- compile.el	Fri Feb  9 08:04:39 1990
***************
*** 364,371
  	       (file-directory-p (concat dir file)))
  	  (let* ( (dir-name (concat dir file))
  		  (subs (sub-dirs dir-name)) )
! 	    (setq dir-list (append dir-list
! 				   (if subs subs (list dir-name))))))
        (setq file-list (cdr file-list)))
      dir-list)) 
  

--- 364,371 -----
  	       (file-directory-p (concat dir file)))
  	  (let* ( (dir-name (concat dir file))
  		  (subs (sub-dirs dir-name)) )
! 	    (setq dir-list (append dir-list (list dir-name)))
! 	    (if subs (setq dir-list (append dir-list subs)))))
        (setq file-list (cdr file-list)))
      dir-list))