From: lbn@hugin.dk (Lars Bo Nielsen)
Subject: Re: REQUEST: find-multiple-buffers.el
Reply-To: lbn@hugin.dk
Organization: Hugin Expert, Ltd.
Date: Wed, 23 Dec 1992 08:45:16 GMT

In article <1992Dec20.054956.24937@murdoch.acc.Virginia.EDU> mjc4y@uvacs.cs.Virginia.EDU (Matt Conway) writes:
   I'm looking for a function that I think is called
   find-multiple-buffers.el. It allows a user to do a find-file on a
   regular expression (to load all *.C files, for example.).

   Is there anyone here who knows where to find this function, or one
   that does what I'm describing? 

I have some old code laying around that probably does what you are
looking for.  Using this you do not have to quit your current emacs
just to say:

	emacs *.c *.h

when you want to change something in all your source files.  Just
call `re-find-file'. It will prompt for a directory (default current).
and then let you specify a regular expression that the files you are
going to load would match - you will even see which files match the
regular expression. In the previous example you would just enter:

	\.[ch]$

to get the *.c and *.h files.

When you have finished editing, the function `re-remove-buffers' will
remove all the buffers that was loaded in the previous call to
`re-find-file'.

Hope this will do the job,

Merry Christmas and a Happy New Year,

Lars Bo Nielsen (lbn@hugin.dk)

----cut here----cut here----cut here----cut here----cut here----
;; 
;; find-files.el - Find files matching reg-exp
;; 
;; Copyright (C) 1990 Lars Bo Nielsen (lbn@iesd.auc.dk).
;; 
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation.
;; 
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
;; See the GNU General Public License for more details.
;; 
;; Author          : Lars Bo Nielsen
;; Created On      : Wed Jan 17 14:31:31 1990
;; Last Modified By: Lars Bo Nielsen
;; Last Modified On: Tue Mar 27 18:59:25 1990
;; Update Count    : 66
;; 
;; HISTORY
;; 27-Mar-1990  (Last Mod: Wed Jan 24 15:17:22 1990 #65)  Lars Bo Nielsen
;;    're-find-file-display' has been changed to 'insert-list'
;; 19-Jan-1990  (Last Mod: Fri Jan 19 14:59:41 1990 #58)  Lars Bo Nielsen
;;    Added 're-remove-buffers' to remove the buffers. They are listed
;;    in 're-find-file-alist'.
;;    Also the function 're-find-file-display' has been added.
;; 19-Jan-1990  (Last Mod: Fri Jan 19 11:21:56 1990 #52)  Lars Bo Nielsen
;;    Reading '%' caused a bug, now two is inserted, and deleted.
;; 19-Jan-1990  (Last Mod: Fri Jan 19 09:00:29 1990 #40)  Lars Bo Nielsen
;;    Inhibit ^G inside the function. We catch it and kill the local
;;    buffers.
;;    I don't know how the normal keyboard commands (like ^X^B) is
;;    supposed to be catched.
;; 18-Jan-1990  (Last Mod: Thu Jan 18 20:35:05 1990 #35)  Lars Bo Nielsen
;;    Now it should be ok.
;; 

(defconst re-find-file-alist nil
  "List of files found by resent success-full call to re-find-file.")

(defun re-find-file (directory)
  (interactive "DFrom directory : ")
  (let ((tmp-buf (generate-new-buffer " * re-find-file tmp-buffer * "))
	(savedconfig (current-window-configuration))
	(list nil)
	(match-list nil)
	(regexp-not-complete t)
	(reg-exp-ok t)
	(regexp-complain "")
	(inhibit-quit t)
	(match "")
	(cur-buffer (current-buffer))
	char
	complete-buf)
    (or (string-match "/$" directory)
	(setq directory (concat directory "/")))
    (setq complete-buf directory)
    (set-buffer tmp-buf)		; Output goes to tmp-buf
    (erase-buffer)			; erase it
    (call-process "ls" nil t nil "-1A" (expand-file-name directory))
    (goto-char (point-min))		; Goto beginning of tmp-buf
    (while (not (eobp))
      (setq list
	    (cons (buffer-substring (point) (progn (end-of-line) (point)))
		  list))
      (or (eobp) (forward-char 1)))
    (switch-to-buffer complete-buf)
    (delete-other-windows)
    (while regexp-not-complete
      (if reg-exp-ok
	  (let ((tmp-list list))
	    (setq match-list nil)
	    (erase-buffer)
	    (while tmp-list
	      (if (or (string-match match (car tmp-list))
		      (string= ""  match))
		  (setq match-list (cons (car tmp-list) match-list)))
	      (setq tmp-list (cdr tmp-list)))
	    (erase-buffer)
	    (insert-list match-list)))
      (message (concat (format "%s file%s matching : "
			       (if (eq (length match-list) 0) "No"
				 (length match-list))
			       (if (eq (length match-list) 1) "" "s"))
		       match regexp-complain))
      (setq char (read-char))
      (cond
       ((eq char ?\C-g)			; Just exit
	(message "")
	(kill-buffer complete-buf)
	(kill-buffer tmp-buf)
	(set-window-configuration savedconfig)
	(signal 'quit nil))
       ((eq char ?\C-?)			; Delete last char
	(if (eq (length match) 0)	; Test if there is anything
	    (beep)			; to delete
	  (if (string-match "%%$" match) ; Extra care with '%'
	      (setq match (substring match 0 (- (length match) 2)))
	    (setq match (substring match 0 (1- (length match)))))))
       ((eq char ?\C-M)			; Return was pressed
	(setq regexp-not-complete nil))
       ((eq char ?%)			; Extra care with '%'
	(setq match (concat match "%%")))
       (t (setq match (concat match (char-to-string char)))))
      (condition-case errorval
	  (progn			; Test regexp
	    (looking-at match)		
	    (setq reg-exp-ok t regexp-complain ""))
	(error (progn (setq regexp-complain " [Incomplete input]")
		      (setq regexp-not-complete t)
		      (setq reg-exp-ok nil)))))
    (setq re-find-file-alist match-list)
    (setq inhibit-quit nil)
    (condition-case ()
	(if (and match-list (yes-or-no-p "Find files? "))
	    (progn
	      (while match-list
		(let* ((inhibit-quit nil) ; Allow quitting in here
		       (filename (car match-list))
		       (filefullname (concat directory filename)))
		  (if (file-directory-p filefullname)
		      (progn
			(beep)
			(if (y-or-n-p
			     (concat "File \"" filename
				     "\" is a directory. Read : "))
			    (progn
			      (message (concat "Getting " filename " ..."))
			      (find-file filefullname))))
		    (message (concat "Getting " filename " ..."))
		    (find-file filefullname)))
		(setq match-list (cdr match-list)))
	      (kill-buffer complete-buf)
	      (kill-buffer tmp-buf))
	  (message "")
	  (kill-buffer complete-buf)
	  (kill-buffer tmp-buf)
	  (set-window-configuration savedconfig))
      (quit (progn
	      (beep)
	      (kill-buffer complete-buf)
	      (kill-buffer tmp-buf)
	      (set-window-configuration savedconfig))))))

(defun re-remove-buffers ()
  (interactive)
  (let ((buffer (get-buffer-create " *temp*"))
	(list re-find-file-alist)
	(cur-win (current-window-configuration)))
    (if re-find-file-alist
	(progn
	  (switch-to-buffer buffer)
	  (delete-other-windows)
	  (unwind-protect
	      (progn
		(insert-list re-find-file-alist)
		(if (yes-or-no-p "Delete buffers? ")
		    (progn
		      (message "Deleting buffers ...")
		      (while list
			(condition-case ()
			    (kill-buffer (car list))
			  (error ()))
			(setq list (cdr list)))
		      (setq re-find-file-alist nil)
		      (message "Deleting buffers ... done"))))
	    (progn
	      (kill-buffer buffer)
	      (set-window-configuration cur-win))))
      (kill-buffer buffer)
      (error "No buffers to delete"))))

(defun insert-list (list &optional cols)
  "Inserts, in current buffer, LIST in cols.
Optional second arg COLS, default coloums.
If second arg not supplied, as many colums as possible is made."
  (let ((maxsize (if cols
		     (/ 80 cols)
		   (+ 2 (apply 'max (cons 10 (mapcar 'length list)))))))
    (while list
      (insert (car list))
      (insert-char ?\  (- maxsize (length (car list))))
      (if (> (current-column) (- 80 maxsize))
	  (progn
	    (just-one-space)
	    (insert "\n")))
      (setq list (cdr list)))
    (goto-char (point-min))))